Skip to content

Commit dfcb00b

Browse files
committed
New Problem "Count of Range Sum"
1 parent 8a30713 commit dfcb00b

File tree

2 files changed

+164
-0
lines changed

2 files changed

+164
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ LeetCode
88

99
| # | Title | Solution | Difficulty |
1010
|---| ----- | -------- | ---------- |
11+
|327|[Count of Range Sum](https://leetcode.com/problems/count-of-range-sum/) | [C++](./algorithms/cpp/countOfRangeSum/CountOfRangeSum.cpp)|Hard|
1112
|326|[Power of Three](https://leetcode.com/problems/power-of-three/) | [C++](./algorithms/cpp/powerOfThree/PowerOfThree.cpp)|Easy|
1213
|322|[Coin Change](https://leetcode.com/problems/coin-change/) | [C++](./algorithms/cpp/coinChange/coinChange.cpp)|Medium|
1314
|319|[Bulb Switcher](https://leetcode.com/problems/bulb-switcher/) | [C++](./algorithms/cpp/bulbSwitcher/bulbSwitcher.cpp)|Medium|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
// Source : https://leetcode.com/problems/count-of-range-sum/
2+
// Author : Hao Chen
3+
// Date : 2016-01-15
4+
5+
/***************************************************************************************
6+
*
7+
* Given an integer array nums, return the number of range sums that lie in [lower,
8+
* upper] inclusive.
9+
*
10+
* Range sum S(i, j) is defined as the sum of the elements in nums between indices
11+
* i and
12+
* j (i ≤ j), inclusive.
13+
*
14+
* Note:
15+
* A naive algorithm of O(n2) is trivial. You MUST do better than that.
16+
*
17+
* Example:
18+
* Given nums = [-2, 5, -1], lower = -2, upper = 2,
19+
* Return 3.
20+
* The three ranges are : [0, 0], [2, 2], [0, 2] and their respective sums are: -2, -1, 2.
21+
*
22+
* Credits:Special thanks to @dietpepsi for adding this problem and creating all test
23+
* cases.
24+
*
25+
***************************************************************************************/
26+
27+
28+
/*
29+
* At first of all, we can do preprocess to calculate the prefix sums
30+
*
31+
* S[i] = S(0, i), then S(i, j) = S[j] - S[i].
32+
*
33+
* Note: S(i, j) as the sum of range [i, j) where j exclusive and j > i.
34+
*
35+
* With these prefix sums, it is trivial to see that with O(n^2) time we can find all S(i, j)
36+
* in the range [lower, upper]
37+
*
38+
* int countRangeSum(vector<int>& nums, int lower, int upper) {
39+
* int n = nums.size();
40+
* long[] sums = new long[n + 1];
41+
* for (int i = 0; i < n; ++i) {
42+
* sums[i + 1] = sums[i] + nums[i];
43+
* }
44+
* int ans = 0;
45+
* for (int i = 0; i < n; ++i) {
46+
* for (int j = i + 1; j <= n; ++j) {
47+
* if (sums[j] - sums[i] >= lower && sums[j] - sums[i] <= upper) {
48+
* ans++;
49+
* }
50+
* }
51+
* }
52+
* delete []sums;
53+
* return ans;
54+
* }
55+
*
56+
* The above solution would get time limit error.
57+
*
58+
* Recall `count smaller number after self` where we encountered the problem
59+
*
60+
* count[i] = count of nums[j] - nums[i] < 0 with j > i
61+
*
62+
* Here, after we did the preprocess, we need to solve the problem
63+
*
64+
* count[i] = count of a <= S[j] - S[i] <= b with j > i
65+
*
66+
* In other words, if we maintain the prefix sums sorted, and then are able to find out
67+
* - how many of the sums are less than 'lower', say num1,
68+
* - how many of the sums are less than 'upper + 1', say num2,
69+
* Then 'num2 - num1' is the number of sums that lie within the range of [lower, upper].
70+
*
71+
*/
72+
73+
class Node{
74+
public:
75+
long long val;
76+
int cnt; //amount of the nodes
77+
Node *left, *right;
78+
Node(long long v):val(v), cnt(1), left(NULL), right(NULL) {}
79+
};
80+
81+
// a tree stores all of prefix sums
82+
class Tree{
83+
public:
84+
Tree():root(NULL){ }
85+
~Tree() { freeTree(root); }
86+
87+
void Insert(long long val) {
88+
Insert(root, val);
89+
}
90+
int LessThan(long long sum, int val) {
91+
return LessThan(root, sum, val, 0);
92+
}
93+
94+
private:
95+
Node* root;
96+
97+
//general binary search tree insert algorithm
98+
void Insert(Node* &root, long long val) {
99+
if (!root) {
100+
root = new Node(val);
101+
return;
102+
}
103+
104+
root->cnt++;
105+
106+
if (val < root->val ) {
107+
Insert(root->left, val);
108+
}else if (val > root->val) {
109+
Insert(root->right, val);
110+
}
111+
}
112+
//return how many of the sums less than `val`
113+
// - `sum` is the new sums which hasn't been inserted
114+
// - `val` is the `lower` or `upper+1`
115+
int LessThan(Node* root, long long sum, int val, int res) {
116+
117+
if (!root) return res;
118+
119+
if ( sum - root->val < val) {
120+
//if (sum[j, i] < val), which means all of the right branch must be less than `val`
121+
//so we add the amounts of sums in right branch, and keep going the left branch.
122+
res += (root->cnt - (root->left ? root->left->cnt : 0) );
123+
return LessThan(root->left, sum, val, res);
124+
}else if ( sum - root->val > val) {
125+
//if (sum[j, i] > val), which means all of left brach must be greater than `val`
126+
//so we just keep going the right branch.
127+
return LessThan(root->right, sum, val, res);
128+
}else {
129+
//if (sum[j,i] == val), which means we find the correct place,
130+
//so we just return the the amounts of right branch.]
131+
return res + (root->right ? root->right->cnt : 0);
132+
}
133+
}
134+
void freeTree(Node* root){
135+
if (!root) return;
136+
if (root->left) freeTree(root->left);
137+
if (root->right) freeTree(root->right);
138+
delete root;
139+
}
140+
141+
};
142+
143+
144+
145+
class Solution {
146+
public:
147+
int countRangeSum(vector<int>& nums, int lower, int upper) {
148+
Tree tree;
149+
tree.Insert(0);
150+
long long sum = 0;
151+
int res = 0;
152+
153+
for (int n : nums) {
154+
sum += n;
155+
int lcnt = tree.LessThan(sum, lower);
156+
int hcnt = tree.LessThan(sum, upper + 1);
157+
res += (hcnt - lcnt);
158+
tree.Insert(sum);
159+
}
160+
161+
return res;
162+
}
163+
};

0 commit comments

Comments
 (0)