forked from wisdompeak/LeetCode
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
separate the solution into two implementations
- Loading branch information
1 parent
f13ca2d
commit 17a0b80
Showing
9 changed files
with
250 additions
and
148 deletions.
There are no files selected for viewing
88 changes: 88 additions & 0 deletions
88
...er/315.Count-of-Smaller-Numbers-After-Self/315.Count-of-Smaller-Numbers-After-Self-v2.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
class Solution { | ||
public: | ||
std::vector<int> countSmaller(std::vector<int> &nums) | ||
{ | ||
// when iterating to index i, we want to efficiently | ||
// know how many elements on the right are less than nums[i] | ||
|
||
// it may be impossible to get to know this information in O(1) | ||
// therefore, O(logn) is the best achievement. | ||
|
||
// considering O(logn), there are two data structure candidates | ||
|
||
// binary indexed tree and segment tree | ||
|
||
// since, we only want to count element of which value < nums[i] | ||
// instead of ? < value < nums[i] | ||
|
||
// binary indexed tree is the choice. | ||
|
||
if (nums.empty()) | ||
return std::vector<int>(); | ||
|
||
auto [min_it, max_it] = std::minmax_element(nums.begin(), nums.end()); | ||
|
||
// mapping *min_it to be 1 | ||
int delta = 1 - *min_it; | ||
|
||
int min = *min_it + delta; | ||
int max = *max_it + delta; | ||
|
||
// There are 2107 trees on the dota 2 map. | ||
binary_indexed_tree tree(max); | ||
|
||
std::vector<int> counts(nums.size(), 0); | ||
|
||
for (int i = nums.size()-1; i >= 0; --i) | ||
{ | ||
// query how many elements are less than nums[i] | ||
int num = nums[i] + delta; | ||
counts[i] = tree.query(num-1); | ||
|
||
tree.update(num, 1); | ||
} | ||
|
||
return counts; | ||
} | ||
|
||
private: | ||
struct binary_indexed_tree | ||
{ | ||
std::vector<int> _arr; | ||
|
||
binary_indexed_tree(int max_val) | ||
: _arr(max_val+1, 0) | ||
{ | ||
// for binary indexed tree, index 0 means nothing, | ||
// therefore, if we want to store the information of max_val | ||
// we need an array of which the length is equal to max_val+1 | ||
} | ||
|
||
/** @brief query prefix sum of range [0, i] of internal array | ||
* @param: i int inclusive end pos of prefix sum array | ||
* @return: prefix sum value | ||
**/ | ||
int query(int i) | ||
{ | ||
assert (i < _arr.size()); | ||
|
||
int ret = 0; | ||
|
||
for (auto j = i; j > 0; j -= lowbit(j)) | ||
ret += _arr[j]; | ||
|
||
return ret; | ||
} | ||
|
||
void update(int i, int val) | ||
{ | ||
assert (i > 0); // logical error to touch array[i] | ||
assert (i < _arr.size()); | ||
|
||
for (auto j = i; j < _arr.size(); j += lowbit(j)) | ||
_arr[j] += val; | ||
} | ||
|
||
int lowbit(int i) { return i & (-i); } | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 0 additions & 60 deletions
60
...uer/315.Count-of-Smaller-Numbers-After-Self/315.Count-of-Smaller-Numbers-After-Self.t.cpp
This file was deleted.
Oops, something went wrong.
93 changes: 93 additions & 0 deletions
93
.../315.Count-of-Smaller-Numbers-After-Self/315.Count-of-Smaller-Numbers-After-Self.t.cpp.in
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
#include "gtest/gtest.h" | ||
#include <vector> | ||
#include <algorithm> | ||
using namespace std; | ||
|
||
#include <unistd.h> | ||
#include <ctime> | ||
|
||
#include <chrono> // benchmark | ||
|
||
#include <315.binary-indexed-tree.h> | ||
#include <315.divided-conquer.h> | ||
|
||
#include <cstdlib> // atexit | ||
#include <assert.h> | ||
#include <dlfcn.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
|
||
|
||
static std::vector<int> | ||
count_of_smaller_numbers_after_self_dc(std::vector<int> &nums) | ||
{ | ||
static void * handle = dlopen("@DC_315_SO@", RTLD_LAZY); | ||
assert (handle); | ||
|
||
static auto counter = | ||
(std::vector<int> (*)(std::vector<int> &))dlsym(handle, "count_v1"); | ||
|
||
// handle keep alive, no need to release | ||
|
||
return counter(nums); | ||
} | ||
|
||
static std::vector<int> | ||
count_of_smaller_numbers_after_self_bit(std::vector<int> &nums) | ||
{ | ||
static void * handle = dlopen("@BIT_315_SO@", RTLD_LAZY); | ||
|
||
assert (handle); | ||
|
||
static auto counter = | ||
(std::vector<int> (*)(std::vector<int> &))dlsym(handle, "count_v2"); | ||
|
||
// handle keep alive, no need to release | ||
|
||
return counter(nums); | ||
} | ||
|
||
TEST(count_of_smaller_numbers_after_self, consistency) | ||
{ | ||
std::vector<int> nums{5,2,6,1}; | ||
std::vector<int> expected{2,1,1,0}; | ||
|
||
ASSERT_EQ(count_of_smaller_numbers_after_self_dc(nums), expected); | ||
ASSERT_EQ(count_of_smaller_numbers_after_self_bit(nums), expected); | ||
} | ||
|
||
TEST(count_of_smaller_numbers_after_self, benchmark) | ||
{ | ||
std::vector<int> nums(1e5, 0); | ||
|
||
for (auto &num: nums) | ||
num = rand() % static_cast<int>(2 * 1e4) - 1e4; | ||
|
||
std::vector<int> counts1; | ||
std::vector<int> counts2; | ||
|
||
counts1.reserve(1e5); | ||
counts2.reserve(1e5); | ||
|
||
{ | ||
auto start = chrono::steady_clock::now(); | ||
counts1 = count_of_smaller_numbers_after_self_dc(nums); | ||
auto end = chrono::steady_clock::now(); | ||
|
||
printf("time cost of countSmaller using merge sort is %ld [ms]\n", | ||
chrono::duration_cast<chrono::milliseconds>(end - start).count()); | ||
} | ||
|
||
{ | ||
auto start = chrono::steady_clock::now(); | ||
counts2 = count_of_smaller_numbers_after_self_bit(nums); | ||
auto end = chrono::steady_clock::now(); | ||
|
||
printf("time cost of countSmaller using binary indexed tree is %ld [ms]\n", | ||
chrono::duration_cast<chrono::milliseconds>(end - start).count()); | ||
} | ||
|
||
ASSERT_EQ(counts1, counts2); | ||
} | ||
|
||
|
10 changes: 10 additions & 0 deletions
10
tests/Divide_Conquer/315.Count-of-Smaller-Numbers-After-Self/315.binary-indexed-tree.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#include <315.binary-indexed-tree.h> | ||
#include <Divide_Conquer/315.Count-of-Smaller-Numbers-After-Self/315.Count-of-Smaller-Numbers-After-Self-v2.cpp> | ||
|
||
#include <stdio.h> | ||
|
||
std::vector<int> count_v2(std::vector<int> &nums) | ||
{ | ||
static Solution s; | ||
return s.countSmaller(nums); | ||
} |
12 changes: 12 additions & 0 deletions
12
tests/Divide_Conquer/315.Count-of-Smaller-Numbers-After-Self/315.binary-indexed-tree.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#ifndef TESTS_DIVIDE_CONQUER_315_BINARY_INDEXED_TREE | ||
#define TESTS_DIVIDE_CONQUER_315_BINARY_INDEXED_TREE | ||
|
||
#include <vector> | ||
#include <algorithm> | ||
using namespace std; | ||
#include <assert.h> | ||
|
||
// binary indexed tree | ||
extern "C" { std::vector<int> count_v2(std::vector<int> &nums); } | ||
|
||
#endif |
10 changes: 10 additions & 0 deletions
10
tests/Divide_Conquer/315.Count-of-Smaller-Numbers-After-Self/315.divided-conquer.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#include <315.divided-conquer.h> | ||
#include <Divide_Conquer/315.Count-of-Smaller-Numbers-After-Self/315.Count-of-Smaller-Numbers-After-Self.cpp> | ||
|
||
#include <stdio.h> | ||
|
||
std::vector<int> count_v1(std::vector<int> &nums) | ||
{ | ||
static Solution s; | ||
return s.countSmaller(nums); | ||
} |
12 changes: 12 additions & 0 deletions
12
tests/Divide_Conquer/315.Count-of-Smaller-Numbers-After-Self/315.divided-conquer.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#ifndef TESTS_DIVIDE_CONQUER_315_DIVIDE_CONQUER | ||
#define TESTS_DIVIDE_CONQUER_315_DIVIDE_CONQUER | ||
|
||
#include <vector> | ||
#include <algorithm> | ||
using namespace std; | ||
#include <assert.h> | ||
|
||
// divided conquer | ||
extern "C" { std::vector<int> count_v1(std::vector<int> &nums); } | ||
|
||
#endif |
Oops, something went wrong.