[leetCode]327. 區間和的個數
題目
連結:https://leetcode-cn.com/problems/count-of-range-sum
給定一個整數陣列 nums
,返回區間和在 [lower, upper]
之間的個數,包含 lower
和 upper
。
區間和 S(i, j)
表示在 nums
中,位置從 i
到 j
的元素之和,包含 i
和 j (i ≤ j)
。
說明:
最直觀的演算法複雜度是 O(n^2)
,請在此基礎上優化你的演算法。
示例:
輸入: nums = [-2,5,-1], lower = -2, upper = 2,
輸出: 3
解釋: 3個區間分別是: [0,0], [2,2], [0,2],它們表示的和分別為: -2, -1, 2。
歸併排序
由於要求區間和因此可以想到字首和陣列,設字首和陣列為preSum
。
問題可以轉換為 preSum[j] - preSum[i] 屬於[lower, upper]
如果給定兩個升序排列的陣列n1,n2
, 嘗試找出下標對(i, j)
, 滿足: n2[j] - n1[i] 屬於[lower, upper]
由於兩個陣列是升序排列的所以只需要在n2
中維護兩個指標 l, r
, 一開始都指向n2
的起始位置,首先考慮n1
的第一個元素,l
向有移動知道找到一個元素使n2[l] - n1[0] >= lower
為止,這樣l
右側的元素均大於n1[0] + lower
, 再移動r
指標,直到n2[r] - n1[0] > upper
這樣r
左側的元素均小於等於n1[0] + upper
,所以區間[l, r)
的所有下標j
都滿足n2[j] - n1[i] 屬於[lower, upper]
。下面繼續考察n1
的第二個元素,由於n1
是遞增的所以l, r
繼續向右移動。 在上述過程中對於n1
的每一個下標都應記錄相應區間[l, r)
的大小,最終就統計得到了下標對(i, j)的數量。
class Solution {
private int lower;
private int upper;
public int countRangeSum(int[] nums, int lower, int upper) {
this.lower = lower;
this.upper = upper;
int n = nums.length;
long[] preSum = new long[n + 1];
for (int i = 0; i < n; i++) {
preSum[i + 1] = preSum[i] + nums[i];
}
return mergeSort(preSum, 0, preSum.length - 1);
}
public int mergeSort(long[] sums, int lo, int hi) {
if (lo >= hi) {
return 0;
}
int mid = lo + (hi - lo) / 2;
int ans = 0;
ans += mergeSort(sums, lo, mid);
ans += mergeSort(sums, mid + 1, hi);
ans += merge(sums, lo, mid, hi);
return ans;
}
public int merge(long[] sums, int lo, int mid, int hi) {
int i = lo, l = mid + 1, r = mid + 1;
int count = 0;
while (i <= mid) {
while (l <= hi && sums[i] + lower > sums[l]) { // l 右側的元素都大於等於 sums[i] + lower
l++;
}
while (r <= hi && sums[i] + upper >= sums[r]) { // r 左側的元素都小於等於 sums[i] + upper
r++;
}
count+= r - l;
i++;
}
int[] aux = new int[hi - lo + 1];
int idx = 0;
int p1 = lo, p2 = mid + 1;
while (p1 <= mid && p2 <= hi) {
if (sums[p1] < sums[p2]) {
aux[idx++] = (int) sums[p1++];
} else {
aux[idx++] = (int) sums[p2++];
}
}
while (p1 <= mid) {
aux[idx++] = (int) sums[p1++];
}
while (p2 <= hi) {
aux[idx++] = (int) sums[p2++];
}
for (int j = lo; j <= hi; j++) {
sums[j] = aux[j-lo];
}
return count;
}
}
相關文章
- 327. 區間和的個數 (歸併排序)排序
- Leetcode 327. 區間和的個數 (字首和 + 離散化 + 樹狀陣列)LeetCode陣列
- 【Leetcode每日一題】327. 區間和的個數(線段樹/樹狀陣列)LeetCode每日一題陣列
- 求區間不同數的個數【主席樹求解】
- 輸出一個區間內的質數(素數)
- 求區間不同數的個數【樹狀陣列求解】陣列
- LeetCode 435 無重疊區間LeetCode
- 輸出區間內的偶數和(遞迴)遞迴
- 【Leetcode刷題篇】leetcode56 合併區間LeetCode
- [LeetCode] 57. Insert Interval 插入區間LeetCode
- leetcode 191 位1的個數LeetCode
- 本題要求統計給定整數M和N區間內素數的個數並對它們求和。
- 【ACM演算法競賽日常訓練】DAY16【奇♂妙拆分】【區區區間間間】【小AA的數列】數學 | 位運算 | 字首和ACM演算法
- 【leetcode.191】位1的個數LeetCode
- CF365D-區間內出現偶數次的數的異或和
- 【LeetCode】1304. 和為零的N個唯一整數(Java)LeetCodeJava
- 統計整數區間[N,M](N,M<100000)中所以非偶數的合數個數,並輸出這個數。
- leetcode-841-鑰匙和房間LeetCode
- LeetCode 2544[交替數字和]LeetCode
- 58. 區間和
- 區間眾數(分塊)
- @Bean和@Component之間的區別?Bean
- querySelector和getElementById之間的區別
- CST和GMT時間的區別
- 敏捷和 Scrum 之間的區別敏捷Scrum
- JavaScript 獲取指定區間的數字JavaScript
- 生成指定區間的隨機小數隨機
- LeetCode 164 最大間距 HERODING的LeetCode之路LeetCode
- leetcode:確實的第一個整數(java)LeetCodeJava
- LeetCode 41. 缺失的第一個正數LeetCode
- LeetCode-485-最大連續 1 的個數LeetCode
- 【LeetCode貪心#09】用最少數量的箭引爆氣球,(涉及區間重疊情況判斷)LeetCode
- LeetCode1450. 在既定時間做作業的學生人數LeetCode
- 列印1-100之間所有9的倍數的整數,統計個數 及 總和
- swift 區間運算子(... 和 ..Swift
- MVC,MVP和MVVM之間的區別MVCMVPMVVM
- python和GO語言之間的區別!PythonGo
- return,continue和break之間的區別