forked from szl0072/Leetcode-Solution-Code
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathCountofRangeSum.java
134 lines (108 loc) · 3.71 KB
/
CountofRangeSum.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package leetcode;
import java.util.Map;
import java.util.TreeMap;
/**
* Project Name : Leetcode
* Package Name : leetcode
* File Name : CountofRangeSum
* Creator : Edward
* Date : Jan, 2018
* Description : 327. Count of Range Sum
*/
public class CountofRangeSum {
/**
* Given an integer array nums, return the number of range sums that lie in [lower, upper] inclusive.
Range sum S(i, j) is defined as the sum of the elements in nums
between indices i and j (i ≤ j), inclusive.
Note:
A naive algorithm of O(n2) is trivial. You MUST do better than that.
Example:
Given nums = [-2, 5, -1], lower = -2, upper = 2,
Return 3.
The three ranges are : [0, 0], [2, 2], [0, 2] and their respective sums are: -2, -1, 2.
1 2 3
1 3 6 .. lower = 1 upper = 3
sum = 6 3 - 5
treeMap : 1 3
Map : (3,1)
TreeMap<Key, Value>
subMap
* @param nums
* @param lower
* @param upper
* @return
*/
// time : O(n^2) 不确定 space : O(n)
public int countRangeSum(int[] nums, int lower, int upper) {
if (nums == null || nums.length == 0) return 0;
TreeMap<Long, Long> treeMap = new TreeMap<>();
treeMap.put((long)0, (long)1);
long sum = 0;
long count = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
long from = sum - upper;
long to = sum - lower;
Map<Long, Long> sub = treeMap.subMap(from, true, to, true);
for (Long value : sub.values()) {
count += value;
}
treeMap.put(sum, treeMap.getOrDefault(sum, (long)0) + 1);
}
return (int)count;
}
// time : O(nlogn) space : O(n)
public int countRangeSum2(int[] nums, int lower, int upper) {
long[] sum = new long[nums.length + 1];
for(int i = 1; i <= nums.length; i++) {
sum[i] = sum[i-1] + nums[i-1];
}
return helper(sum, new long[sum.length], 0, sum.length - 1, lower, upper);
}
/**
rangeEnd是第一个满足 sums[rangeEnd] - sums[i] > upper 的下标
rangeStart是第一个满足 sums[rangeStart] - sums[i] >= lower 的下标
[lower, upper]之间的区间的个数是rangeEnd - rangeStart
遍历前半段 匹配后半段
[1,3] [2,4]
* @param sum
* @param helper
* @param low
* @param high
* @param lower
* @param upper
* @return
*/
private int helper(long[] sum, long[] helper, int low, int high, long lower, long upper) {
if (low >= high) {
return 0;
}
int mid = (high + 1 - low) / 2 + low;
int count = helper(sum, helper, low, mid - 1, lower, upper)
+ helper(sum, helper, mid, high, lower, upper);
int rangeStart = mid, rangeEnd = mid;
for(int i = low; i < mid; i++) {
while(rangeStart <= high && sum[rangeStart] - sum[i] < lower)
rangeStart++;
while(rangeEnd <= high && sum[rangeEnd] - sum[i] <= upper)
rangeEnd++;
count += rangeEnd - rangeStart;
}
merge(sum, helper, low, mid, high);
return count;
}
private void merge(long[] sum, long[] helper, int low, int mid, int high) {
int left = low, right = mid, idx = low;
while(left < mid && right <= high) {
if (sum[left] <= sum[right])
helper[idx++] = sum[left++];
else
helper[idx++] = sum[right++];
}
while(left < mid)
helper[idx++] = sum[left++];
while(right <= high)
helper[idx++] = sum[right++];
System.arraycopy(helper, low, sum, low, high + 1 - low);
}
}