[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每日一題陣列
- poj 3468 區間更新 整個區間加一個數和區間求和操作
- 求區間不同數的個數【樹狀陣列求解】陣列
- Git 和 SVN 之間的五個基本區別Git
- GIT和SVN之間的五個基本區別Git
- hdu4417 樹狀陣列(求指定區間比指定數小的數的個數)陣列
- CF365D-區間內出現偶數次的數的異或和
- 【ACM演算法競賽日常訓練】DAY16【奇♂妙拆分】【區區區間間間】【小AA的數列】數學 | 位運算 | 字首和ACM演算法
- 酒店房間和 C++ 區域性變數的作用域C++變數
- LeetCode 435 無重疊區間LeetCode
- javascript 隨機數區間JavaScript隨機
- 【Leetcode刷題篇】leetcode56 合併區間LeetCode
- JavaScript 獲取指定區間的數字JavaScript
- 生成指定區間的隨機小數隨機
- leetcode 191 位1的個數LeetCode
- [LeetCode] 57. Insert Interval 插入區間LeetCode
- SHLVL 和 BASH_SUBSHELL 兩個變數的區別變數
- CST和GMT時間的區別
- 敏捷和 Scrum 之間的區別敏捷Scrum
- Statement和PreparedStatement之間的區別
- 成員變數和區域性變數的區別變數
- excel統計大於15小於20的數並求和 統計區間個數的函式Excel函式
- 【leetcode.191】位1的個數LeetCode
- swift 區間運算子(... 和 ..Swift
- @Bean和@Component之間的區別?Bean
- MVC,MVP和MVVM之間的區別MVCMVPMVVM
- reboot和init 6之間的區別boot
- 【LeetCode】1304. 和為零的N個唯一整數(Java)LeetCodeJava
- 如何計算兩個時間間隔的天數
- Golang生成區間隨機整數Golang隨機
- js隨機產生區間數JS隨機
- javascript實現獲取指定數字區間的隨機數JavaScript隨機
- leetcode-841-鑰匙和房間LeetCode
- Categorical, Ordinal, Interval - 變數之間的區別Go變數
- 【LeetCode貪心#09】用最少數量的箭引爆氣球,(涉及區間重疊情況判斷)LeetCode
- Python 函式中引數前面一個和兩個星號(**)的區別Python函式