Skip to content

Commit 8882d56

Browse files
committed
前缀和
1 parent 77a9976 commit 8882d56

File tree

4 files changed

+183
-0
lines changed

4 files changed

+183
-0
lines changed

leetcode_Java/DoneTitle.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,15 @@
3131
236. 二叉树的最近公共祖先
3232
283. 移动零
3333
300. 最长上升子序列
34+
303. 区域和检索 - 数组不可变
35+
304. 二维区域和检索 - 矩阵不可变
3436
338. 比特位计数
3537
406. 根据身高重建队列
3638
437. 路径总和
3739
448. 找到所有数组中消失的数字
3840
461. 汉明距离
3941
538. 把二叉搜索树转换为累加树
4042
543. 二叉树的直径
43+
560. 和为 K 的子数组
4144
589. N叉树的前序遍历
4245
617. 合并二叉树

leetcode_Java/Solution0303.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// 区域和检索 - 数组不可变
2+
3+
4+
/*
5+
暴力破解:直接累加计算区间和,时间复杂度O(n)
6+
*/
7+
class NumArray {
8+
private int[] nums;
9+
10+
public NumArray(int[] nums) {
11+
this.nums = nums;
12+
}
13+
14+
public int sumRange(int left, int right) {
15+
int res = 0;
16+
for (int i = left; i <= right; i++) {
17+
res += nums[i];
18+
}
19+
return res;
20+
}
21+
}
22+
23+
24+
/*
25+
前缀和:
26+
1、使用数组存放前缀和,preSum[n] 表示nums数组索引区间 [0, n-1] 的和
27+
2、计算某个区间元素和,可以直接通过前缀和相减得到,时间复杂度O(1)
28+
*/
29+
class NumArray {
30+
private int[] preSum;
31+
32+
public NumArray(int[] nums) {
33+
preSum = new int[nums.length + 1];
34+
for (int i = 0; i < nums.length; i++) {
35+
preSum[i + 1] = preSum[i] + nums[i];
36+
}
37+
}
38+
39+
public int sumRange(int left, int right) {
40+
return preSum[right + 1] - preSum[left];
41+
}
42+
}
43+
44+
/**
45+
* Your NumArray object will be instantiated and called as such:
46+
* NumArray obj = new NumArray(nums);
47+
* int param_1 = obj.sumRange(left,right);
48+
*/

leetcode_Java/Solution0304.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// 二维区域和检索 - 矩阵不可变
2+
3+
4+
/*
5+
一维前缀和:
6+
1、初始化时对矩阵的每一行计算前缀和,检索时对二维区域中的每一行计算子数组和,然后对每一行的子数组和计算总和。
7+
2、preSum[n][m] 表示矩阵matrix 左上角为(n, 0) 右下角为 (n, m-1) 的子矩形范围元素和
8+
3、preSum 初始化时比 matrix 多了一列,用于初始化前缀和矩阵首列为0
9+
4、检索的时间复杂度是 O(m)
10+
*/
11+
class NumMatrix {
12+
private int[][] preSum;
13+
14+
public NumMatrix(int[][] matrix) {
15+
int n = matrix.length, m = matrix[0].length;
16+
preSum = new int[n][m + 1];
17+
for (int row = 0; row < n; row++) {
18+
for (int col = 0; col < m; col++) {
19+
preSum[row][col + 1] = preSum[row][col] + matrix[row][col];
20+
}
21+
}
22+
}
23+
24+
public int sumRegion(int row1, int col1, int row2, int col2) {
25+
int res = 0;
26+
for (int i = row1; i <= row2; i++) {
27+
res += preSum[i][col2 + 1] - preSum[i][col1];
28+
}
29+
return res;
30+
}
31+
}
32+
33+
34+
35+
/*
36+
二维前缀和:
37+
1、preSum[n][m] 表示矩阵matrix 左上角为(0, 0) 右下角为 (n-1, m-1) 的子矩形范围元素和
38+
2、preSum 初始化时比 matrix 多了一行一列,用于初始化前缀和矩阵首行首列为0
39+
3、前缀和矩阵元素填充、计算子矩形元素和,都是通过其他子矩形的面积加减得到
40+
4、检索的时间复杂度是 O(1)
41+
*/
42+
class NumMatrix {
43+
private int[][] preSum;
44+
45+
public NumMatrix(int[][] matrix) {
46+
int n = matrix.length, m = matrix[0].length;
47+
preSum = new int[n + 1][m + 1];
48+
for (int row = 1; row <= n; row++) {
49+
for (int col = 1; col <= m; col++) {
50+
preSum[row][col] = preSum[row - 1][col] + preSum[row][col - 1] - preSum[row - 1][col -1] + matrix[row - 1][col - 1];
51+
}
52+
}
53+
}
54+
55+
public int sumRegion(int row1, int col1, int row2, int col2) {
56+
return preSum[row2 + 1][col2 + 1] - preSum[row2 + 1][col1] - preSum[row1][col2 + 1] + preSum[row1][col1];
57+
}
58+
}
59+
60+
/**
61+
* Your NumMatrix object will be instantiated and called as such:
62+
* NumMatrix obj = new NumMatrix(matrix);
63+
* int param_1 = obj.sumRegion(row1,col1,row2,col2);
64+
*/

leetcode_Java/Solution0560.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// 和为 K 的子数组
2+
3+
4+
/*
5+
暴力破解:两层for循环遍历判断所有子数组
6+
*/
7+
class Solution {
8+
public int subarraySum(int[] nums, int k) {
9+
int n = nums.length, count = 0;
10+
for (int end = 0; end < n; end++) {
11+
int sum = 0;
12+
for (int start = end; start >= 0; start--) {
13+
sum += nums[start];
14+
if (sum == k) {
15+
count++;
16+
}
17+
}
18+
}
19+
return count;
20+
}
21+
}
22+
23+
24+
/*
25+
前缀和 + 暴力破解
26+
*/
27+
class Solution {
28+
public int subarraySum(int[] nums, int k) {
29+
int n = nums.length, count = 0;
30+
int[] preSum = new int[n + 1];
31+
for (int i = 0; i < n; i++) {
32+
preSum[i + 1] = preSum[i] + nums[i];
33+
}
34+
for (int end = 1; end <= n; end++) {
35+
for (int start = 0; start < end; start++) {
36+
if (preSum[end] - preSum[start] == k) {
37+
count++;
38+
}
39+
}
40+
}
41+
return count;
42+
}
43+
}
44+
45+
46+
/*
47+
前缀和 + 哈希表:
48+
1、使用HashMap存放 <前缀和, 出现次数>
49+
2、由于前缀和通过HashMap获取,不用在数组中获取,因此用一个变量记录当前前缀和即可
50+
3、由于 pre[end] - pre[start - 1] = k 则 pre[end] - k = pre[start - 1]
51+
遍历数组,边累加计算当前前缀和,并判断另一个预期的前缀和是否出现在HashMap中,以及出现次数,可以构成和为 k 的连续子数组,累加个数
52+
4、累加记录当前前缀和及次数到HashMap中
53+
*/
54+
class Solution {
55+
public int subarraySum(int[] nums, int k) {
56+
Map<Integer, Integer> map = new HashMap<>();
57+
map.put(0, 1);
58+
int curPreSum = 0, count = 0;
59+
for (int i = 0; i < nums.length; i++) {
60+
curPreSum += nums[i];
61+
if (map.containsKey(curPreSum - k)) {
62+
count += map.get(curPreSum - k);
63+
}
64+
map.put(curPreSum, map.getOrDefault(curPreSum, 0) + 1);
65+
}
66+
return count;
67+
}
68+
}

0 commit comments

Comments
 (0)