注意:prefixsum一般都是用PrefixSum[n+1]的数组,prefix[0] = 0; 那么

因为i, j 是A里面的坐标,而prefixsum比A多了1;所以原来的sum[j] - sum[i-1]变成了

sum(i~j) = prefixsum(j + 1) - prefixsum(i);

Interval Sum 思路:因为这个题目不需要modify数组操作,所以用prefix sum array就可以解决,O(N + M) N是数组大小,M是query次数;

/*** Definition of Interval:* public classs Interval {*     int start, end;*     Interval(int start, int end) {*         this.start = start;*         this.end = end;*     }* }*/public class Solution {/*** @param A: An integer list* @param queries: An query list* @return: The result list*/public List<Long> intervalSum(int[] A, List<Interval> queries) {List<Long> list = new ArrayList<>();int n = A.length;long[] prefixsum = new long[n + 1];prefixsum[0] = 0;for(int i = 1; i <= n; i++) {prefixsum[i] = prefixsum[i - 1] + A[i - 1];}for(Interval interval: queries) {list.add(prefixsum[interval.end + 1] - prefixsum[interval.start]);}return list;}
}

Subarray Sum 用prefixsum, A[i ~ j] = 0; 相当于 S[i-1] == S[j],也就是在数组里面找相等的数;hashmap, 存 S[i], i 就可以了;一定要存index;注意用hashmap put(0,0)因为是为了如果有sum直接== 0, 那么length应该是i - 0 = i;

public class Solution {/*** @param nums: A list of integers* @return: A list of integers includes the index of the first number and the index of the last number*/public List<Integer> subarraySum(int[] nums) {List<Integer> res = new ArrayList<>();if(nums == null || nums.length == 0) {return res;}int n = nums.length;int[] prefixSum = new int[n + 1];prefixSum[0] = 0;for(int i = 1; i <= n; i++) {prefixSum[i] = prefixSum[i - 1] + nums[i - 1];}HashMap<Integer, Integer> hashmap = new HashMap<>();hashmap.put(0, 0);for(int i = 1; i <= n; i++) {if(hashmap.containsKey(prefixSum[i])) {// -1:prefixsum的index都要-1,才能map到原来的array index上;// +1:A[i...j] == 0 -> sum[j] == sum[i - 1]; 求i, 所以要+1;res.add(hashmap.get(prefixSum[i] - 1 + 1));res.add(i - 1);}hashmap.put(prefixSum[i], i);}return res;}
}

Subarray Sum II

思路:固定右边界aj, 问题转换为找左边的两个边界,

XXXVVVVVVVVXXXXX aj

.....ai .................ak ........ aj

<=end        >=start

这两个区间都是可以用双指针来计算得到的,O(N)

Prefix Sum 现在用n+1数组来求;

public class Solution {/*** @param A: An integer array* @param start: An integer* @param end: An integer* @return: the number of possible answer*/public int subarraySumII(int[] A, int start, int end) {if(A == null || A.length == 0) {return 0;}int n = A.length;int[] prefixSum = new int[n + 1];prefixSum[0] = 0;for(int i = 1; i <= n; i++) {prefixSum[i] = prefixSum[i - 1] + A[i - 1];}int res = 0;/**XXXXXXVVVVVVVVVXXXXXX j>end         <startleft          right*/int left = 0, right = 0;for(int j = 1; j <= n; j++) {while(right < j && prefixSum[j] - prefixSum[right] >= start) {right++;}while(left < j && prefixSum[j] - prefixSum[left] > end) {left++;}res += (right - left);}return res;}
}

Subarray Sum Closest 思路:将prefixsum的array,排序,然后比较相邻的两个sum,如果求diff最小的,注意;如果prefixsum == 0,则不用找了,找了个最佳答案,否则看最相近的;

public class Solution {/** @param nums: A list of integers* @return: A list of integers includes the index of the first number and the index of the last number*/private class Node {public int index;public int sum;public Node(int index, int sum) {this.index = index;this.sum = sum;}}public int[] subarraySumClosest(int[] nums) {int[] res = new int[2];if(nums == null || nums.length == 0) {return res;}int n = nums.length;int[] sum = new int[n + 1];sum[0] = 0;List<Node> list = new ArrayList<Node>();for(int i = 1; i <= n; i++) {sum[i] = sum[i - 1] + nums[i - 1];if(sum[i] == 0) {res[0] = 0;res[1] = i - 1;return res;}list.add(new Node(i, sum[i]));}Collections.sort(list, (a, b) ->(a.sum - b.sum));int diff = Integer.MAX_VALUE;for(int i = 0; i < list.size() - 1; i++) {int curdiff = list.get(i + 1).sum - list.get(i).sum;if(curdiff < diff) {diff = curdiff;// sum[i, j] = S[j] - S[i - 1], 所以真正的区间是: [i + 1, j]if(list.get(i).index < list.get(i + 1).index) {res[0] = list.get(i).index;res[1] = list.get(i + 1).index - 1;} else {res[0] = list.get(i + 1).index;res[1] = list.get(i).index - 1;}}}return res;}
}

Submatrix Sum 用prefixsum,代表是从(0,0) 到(i,j) 的区域sum。然后固定上边界和下边界,然后扫描j,用hashmap来找有没有重复的区域,如果有就找到了区域为0的,然后记录答案,注意,因为prefixsum是+1了的index,所以,最后右下角的点需要减去1,左上角的点因为默认+1,所以不用减去1了。 O(N^3); Space O(N^2);

public class Solution {/** @param matrix: an integer matrix* @return: the coordinate of the left-up and right-down number*/public int[][] submatrixSum(int[][] matrix) {int[][] res = new int[2][2];if(matrix == null || matrix.length == 0 || matrix[0].length == 0) {return res;}int m = matrix.length;int n = matrix[0].length;int[][] prefixSum = new int[m + 1][n + 1];for(int i = 0; i <= m; i++) {for(int j = 0; j <= n; j++) {if(i == 0 || j == 0) {prefixSum[i][j] = 0;} else {prefixSum[i][j] = prefixSum[i - 1][j] + prefixSum[i][j - 1] - prefixSum[i - 1][j - 1] + matrix[i - 1][j - 1];}}}for(int x1 = 0; x1 < m; x1++) {for(int x2 = x1 + 1; x2 <= m; x2++) {// 记住,这里每次循环都要新建一个hashmap;HashMap<Integer, Integer> hashmap = new HashMap<>();for(int j = 0; j <= n; j++) {int area = prefixSum[x2][j] - prefixSum[x1][j];if(hashmap.containsKey(area)) {int k = hashmap.get(area);res[0][0] = x1;res[0][1] = k;res[1][0] = x2 - 1;res[1][1] = j - 1;} else {hashmap.put(area, j);}}}}return res;}
}

Lintcode: Continuous Subarray Sum 思路:

思路:用prefixsum来做,求最大,那么就跟股票那题一样,存一个最小,然后每次跟最小比差,如果大,记录下来。注意prefixsum的index默认是+1了的,所以result是[start, i - 1];

是因为sum[i, j] = S[j] - S[i - 1], = prefixsum[j + 1] - prefixsum[i], prefixsum里面的index是原来数组的index + 1所形成。所以在prefixsum的index要还原成原来array的index都要减去1,然而,S[j] - S[i - 1] == Sum[i,j],所以求i的范围,需要把start +1,这样start + 1 - 1=start, end - 1,就是对应原来数组的index了;

public class Solution {/** @param A: An integer array* @return: A list of integers includes the index of the first number and the index of the last number*/public List<Integer> continuousSubarraySum(int[] A) {List<Integer> list = new ArrayList<Integer>();if(A == null || A.length == 0) {return list;}int sum = 0;int minsum = 0;int max = Integer.MIN_VALUE;int start = 0, end = 0;list.add(start); list.add(end);int n = A.length;for(int i = 1; i <= n; i++) {sum += A[i - 1];if(sum - minsum > max) {max = sum - minsum;list.set(0, start);list.set(1, i - 1);}if(sum < minsum) {minsum = sum;start = i;}}return list;}
}

[LeetCode Continuous Subarray Sum] 思路:这题算法是根据(a + n*k) % k == a % k, 所以 [23,2,6,4,7] k = 6, the running sum is [23,25,31,35,42] and the remainders are [5,1,1,5,0]. We got remainder 5 at index 0 and at index 3. That means, in between these two indexes we must have added a number which is multiple of the k.  也就是跟two sum类似,如果存 ( cursum % k )余数和index,那么如果我又遇见了同样的余数,那么代表中间肯定有个subarray 和是n * k. 注意这题tricky的地方是: [0,0] 0 或者[6,6] 6 这种,如果map.put(0,0)会返回false,处理的方法就是map.put(0,-1)这样代表余数是0的情况可以有1 个,我遇见的下一个,肯定可以判断是len > 1 从而返回true

class Solution {public boolean checkSubarraySum(int[] nums, int k) {if(nums == null || nums.length == 0) {return false;}HashMap<Integer, Integer> hashmap = new HashMap<>();// value = -1 is due to the fact that the size of the subarray is required to be least two// 因为key 是sum,value是index,题目要求array at least 2.所以,如果找到一个sum,另外一个index 减去current index,就必须 > 1; 所以存-1;hashmap.put(0, -1); int cursum = 0;for(int i = 0; i < nums.length; i++) {cursum += nums[i];if(k != 0) {cursum = cursum % k;}Integer pre = hashmap.get(cursum);if(pre != null) {if(i - pre > 1) {return true;}} else {hashmap.put(cursum, i);}}return false;}
}

Range Sum Query - Immutable Prefix 模板,Sum[i, j] = prefixsum[j + 1] - prefixsum[i];

class NumArray {private int[] prefixsum;public NumArray(int[] nums) {int n = nums.length;this.prefixsum = new int[n + 1];for(int i = 1; i <= n; i++) {prefixsum[i] = prefixsum[i - 1] + nums[i - 1];}}public int sumRange(int i, int j) {return prefixsum[j + 1] - prefixsum[i];}
}/*** Your NumArray object will be instantiated and called as such:* NumArray obj = new NumArray(nums);* int param_1 = obj.sumRange(i,j);*/

Subarray Sum Equals K 思路:用prefixsum prefixsum[j+1] - prefixsum[i] = k,  O(N^2) 优化就是:类似2sum,用hashmap优化,注意先判断是否含有,再加入,否则会有重复计算;O(N) Space O(N);

class Solution {public int subarraySum(int[] nums, int k) {if(nums == null || nums.length == 0) {return 0;}int n = nums.length;int cursum = 0;//       sum      frequency;HashMap<Integer, Integer> hashmap = new HashMap<>();int count = 0;for(int i = 0; i < nums.length; i++) {cursum += nums[i];if(cursum == k) {count++;}// 存prefixsum - k, 也就是之前的比较小的数,这样在后面一旦碰见,那么就表示相吻合,a - b = k;// count已经加过1了,那么这里只需要加入之前的频率。if(hashmap.containsKey(cursum - k)) {count += hashmap.get(cursum - k);}// hashmap里面的频率要+1;hashmap.put(cursum, hashmap.getOrDefault(cursum, 0) + 1);}return count;}
}

Number of Submatrices That Sum to Target   这类矩阵的题目,就矩阵和,都是prefixsum的思路,这里比较巧妙的是,用每一行的prefixsum来求解,i, j 是start col, end col, k是row,相当于从右往左投影计算array[k], 把j往左投影,然后array 其实是一个竖着的矩阵往左投影sum的结果。问题就变成了560. Subarray Sum Equals K , 注意hashmap每次都要重新生成,因为i, j  变化了,那么相当于每次生成一个新的array了,所以每次都是一次新的计算; Time : O(col ^2 * row);

class Solution {public int numSubmatrixSumTarget(int[][] matrix, int target) {int n = matrix.length;int m = matrix[0].length;int[] array = new int[n];int res = 0;for(int i = 0; i < m; i++) {Arrays.fill(array, 0);for(int j = i; j < m; j++) {for(int k = 0; k < n; k++) { // j每次增加一格,k从上到下,都要加入对应的array[k];array[k] += matrix[k][j]; // 把每一行k, [i,j] sum起来;}res += subarraySum(array, target);}   }return res;}public int subarraySum(int[] nums, int k) {if(nums == null || nums.length == 0) {return 0;}HashMap<Integer, Integer> hashmap = new HashMap<>();int sum = 0;int count = 0;for(int i = 0; i < nums.length; i++) {sum += nums[i];if(sum == k) {count++;}if(hashmap.containsKey(sum - k)) {count += hashmap.get(sum - k);}hashmap.put(sum, hashmap.getOrDefault(sum, 0) + 1);}return count;}
}

Find Pivot Index 思路:prefixsum的模板,注意index可以是最后一个,因为整个array sum == 0,也是可以的;

class Solution {public int pivotIndex(int[] nums) {if(nums == null || nums.length == 0) {return -1;}int n = nums.length;int[] prefixsum = new int[n + 1];prefixsum[0] = 0;for(int i = 1; i <= n; i++) {prefixsum[i] = prefixsum[i - 1] + nums[i - 1];}for(int i = 1; i <= n; i++) {int leftsum = prefixsum[i - 1];int rightsum = prefixsum[n] - prefixsum[i];if(leftsum == rightsum) {return i - 1;}}return -1;}
}

Split Array with Equal Sum 思路:先固定j,然后左边分两半,sum相等就存入hashset,然后右边分两半,sum相等,就看sum在不在hashset里面;这里presum用0开始的index,这样写prefixsum好写。严格按照// 0 < i, i + 1 < j, j + 1 < k < n - 1; 这个提示来写。

class Solution {public boolean splitArray(int[] nums) {if(nums == null || nums.length == 0) {return false;}int n = nums.length;int[] prefixsum = new int[n];prefixsum[0] = nums[0];for(int i = 1; i < n; i++) {prefixsum[i] = prefixsum[i - 1] + nums[i];}// 0 < i, i + 1 < j, j + 1 < k < n - 1for(int j = 3; j < n - 3; j++) {HashSet<Integer> set = new HashSet<>();for(int i = 1; i + 1 < j; i++) {if(prefixsum[i - 1] == prefixsum[j - 1] - prefixsum[i]) {set.add(prefixsum[i - 1]);}}for(int k = j + 2; k < n - 1; k++) {if(prefixsum[k - 1] - prefixsum[j] == prefixsum[n - 1] - prefixsum[k]) {if(set.contains(prefixsum[n - 1] - prefixsum[k])) {return true;}}}}return false;}
}

Product of the Last K Numbers  思路:prefix product array,注意默认的第一位是个1,然后往后面加 list.get( list.size() - 1) * num;最后,k == n的时候,因为前面有1,所以return 0,超过了输入num的个数范围;

class ProductOfNumbers {private ArrayList<Integer> list;public ProductOfNumbers() {list = new ArrayList();list.add(1); // 跟prefix一样,第一个元素add为1;}public void add(int num) {if(num == 0) {list.clear();list.add(1);} else {list.add(list.get(list.size() - 1) * num);}}public int getProduct(int k) {int n = list.size();//因为前面加了默认1,跟prefixsum一样,所以k == n 相当于k 大于了元素个数了,直接return 0;if(k >= n) { return 0;} else {return list.get(n - 1) / list.get(n - 1 - k);}}
}/*** Your ProductOfNumbers object will be instantiated and called as such:* ProductOfNumbers obj = new ProductOfNumbers();* obj.add(num);* int param_2 = obj.getProduct(k);*/

Find Two Non-overlapping Sub-arrays Each With Target Sum 这题很类似于560. Subarray Sum Equals K, 不同在于要找两个不同的subarray,那么如何找两个array就是利用dp[i]来找,dp[i]存的物理意义是,到目前subarry sum为target的最小的length,如果pre != -1 && dp[pre] != Integer.MAX_VALUE代表找到了第二array,之前还有一个array和为target;因为dp[i] = dp[i - 1];所以只有一个的话,dp[pre]会一直是integer.MAX_VALUE;

注意:计算prefixsum的index,必须加入-1,因为前几个数和就是target,如果要算length,就是i - (-1) = i + 1;因为i是0开头的;560. Subarray Sum Equals K 那个题是用hashmap存prefixsum , frequency. 计算频率,就(0,1)如果计算index或者长度就是(0,-1)。

class Solution {public int minSumOfLengths(int[] arr, int target) {if(arr == null || arr.length == 0) {return -1;}HashMap<Integer, Integer> hashmap = new HashMap<>();// 计算prefixsum的index,必须加入-1,因为前几个数和就是target,如果要算length,就是i - (-1) = i + 1;因为i是0开头的;hashmap.put(0, -1);int n = arr.length;int[] dp = new int[n];int res = Integer.MAX_VALUE;int cursum = 0;for(int i = 0; i < arr.length; i++) {cursum += arr[i];dp[i] = i > 0 ? dp[i - 1] : Integer.MAX_VALUE;if(hashmap.containsKey(cursum - target)) {int pre = hashmap.get(cursum - target);dp[i] = Math.min(dp[i], i - pre);// 如何求得两个区间,就是用dp[i] 记录到目前为止,cursum == target的array的最小的length;// 如果 pre == -1 或者dp[pre] == Integer.MAX_VALUE,代表之前只找到一个区间;如果不是,那么就是之前已经找到一个区间,现在找到了第二个区间;if(pre != -1 && dp[pre] != Integer.MAX_VALUE) {res = Math.min(res, dp[pre] + i - pre);}}hashmap.put(cursum, i);}return res == Integer.MAX_VALUE ? -1 : res;}
}

Max Sum of Rectangle No Larger Than K 核心思想就是:每列column,从左向右投影,left, right, 是左右边界,然后sums[n] 是长度为row的投影sum,也就是prefixsum。每次移动left, right,计算出sums array之后,问题就转换为,在一个array里面,找subarray sum最接近K的sum;这里用了treeset ceiling是第一个大于input的value,num >= currsum - k; currsum - num <= k; 每次update这个currsum - num  就可以了。currsum 是累加的sum;

注意:currusm - num 代表的就是下面的block的matrix;set.add(0); // 需要padding,是为了解决只有一个row value的情况;比如说cursum = 10, k = 10,那么就只有一个sum的话,就是要返回10,如果没有0,就会返回null,得不到sum就等于k的情况;

class Solution {public int maxSumSubmatrix(int[][] matrix, int k) {if(matrix == null || matrix.length == 0 || matrix[0].length == 0) {return 0;}int n = matrix.length;int m = matrix[0].length;int result = Integer.MIN_VALUE;for(int left = 0; left < m; left++) {int[] arr = new int[n];for(int right = left; right < m; right++) {for(int i = 0; i < n; i++) {arr[i] += matrix[i][right];}TreeSet<Integer> treeset = new TreeSet<>();// 需要padding,是为了解决只有一个row value的情况;// 比如说cursum = 10, k = 10,那么就只有一个sum的话,就是要返回10,如果没有0,就会返回null,得不到sum就等于k的情况;treeset.add(0);int cursum = 0;for(int prefixsum: arr) {cursum += prefixsum;// num >= cursum - k;// k >= cursum - num;Integer num = treeset.ceiling(cursum - k);if(num != null) {// k >= cursum - num;// currusm - num 代表的就是下面的block的matrix;result = Math.max(result, cursum - num);}treeset.add(cursum);}}}return result;}
}

Shortest Subarray with Sum at Least K  思路:这题跟Minimum Size Subarray Sum 很相似,不同的是,加入了负数,使得问题变复杂了。思路就是:求区间和,很容易想到prefixsum,这个很好求出,但是怎么扫描去求sum>=k的最小区间长度,sum[i] .... sum[j].... sum[k] 如果sum[i] > sum[j], sum[k] - sum[i] >=k, 那么sum[k] - sum[j] 更加>=k,同时j > i,那么j到k区间会更小,那么sum[i]就没必要存,发现这个性质那么就是单调栈,前面的数sum[i], 比当前的数sum[j]要大,就没必要存,那么栈里面就是单调递增的,我们要保持里面是递增的,那么后面进来的数,如果比last要小,则踢掉前面的数,为什么?是因为如果存了,last > i, future - last >= k, 那么future - i 更加>= k, 所以 last比i大,没必要存;

More detailed on this, we always add at the LAST position
B[d.back] <- B[i] <- ... <- B[future id]
B[future id] - B[d.back()] >= k && B[d.back()] >= B[i]
B[future id] - B[i] >= k too

前后都要进出,那么用deque可以满足要求。这里要注意一点,长度是 i - deque.peekFirst()。为什么,是因为sum[j] - sum[i] ,subarray的长度其实是i + 1,...j,那么就是j - i + 1 - 1 = j - i;

class Solution {public int shortestSubarray(int[] A, int K) {if(A == null || A.length == 0) {return -1;}int n = A.length;int[] prefixsum = new int[n + 1];prefixsum[0] = 0;for(int i = 1; i <= n; i++) {prefixsum[i] = prefixsum[i - 1] + A[i - 1];}Deque<Integer> arrayDeque = new ArrayDeque<Integer>();int res = Integer.MAX_VALUE;for(int i = 0; i <= n; i++) {while(!arrayDeque.isEmpty() && prefixsum[i] - prefixsum[arrayDeque.peekFirst()] >= K) {res = Math.min(res, i - arrayDeque.peekFirst());arrayDeque.pollFirst();}while(!arrayDeque.isEmpty() && prefixsum[i] <= prefixsum[arrayDeque.peekLast()]) {arrayDeque.pollLast();}arrayDeque.offer(i);}return res == Integer.MAX_VALUE ? -1 : res;}
}

Maximum Side Length of a Square with Sum Less than or Equal to Threshold  思路:build 矩阵的prefixsum ,记住建立的时候是 sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1] + mat[i - 1][j - 1];

利用prefixsum求正方形的时候是:sum[i][j] - sum[i - len][j] - sum[i][j - len] + sum[i - len][j - len]

建立好prefixsum之后,在0,math.min(n,m)之间做binary search, T: n * m * log(min(n,m));

生成prefixsum的时候,是从上到下生成,计算区间的时候,是相减的;不要记忆公式,逻辑推理就行;

class Solution {public int maxSideLength(int[][] mat, int threshold) {int n = mat.length;int m = mat[0].length;int[][] sum = new int[n + 1][m + 1];for(int i = 1; i <= n; i++) {for(int j = 1; j <= m; j++) {sum[i][j] = sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1] + mat[i - 1][j - 1];}}int start = 0; int end = Math.min(n, m);while(start + 1 < end) {int mid = start + (end - start) / 2;if(canhave(mat, mid, threshold, sum)) {start = mid;} else {end = mid;}}if(canhave(mat, end, threshold, sum)) {return end;}if(canhave(mat, start, threshold, sum)) {return start;}return 0;}private boolean canhave(int[][] mat, int len, int threshold, int[][] sum) {for(int i = len; i <= mat.length; i++) {for(int j = len; j <= mat[0].length; j++) {if(sum[i][j] - sum[i - len][j] - sum[i][j - len] + sum[i - len][j - len] <= threshold) {return true;}}}return false;}
}

思路2:这个比较巧妙,就是在建立prefixsum 矩阵的时候,一起判断,是否有比len更大的合法正方形,有就len++;O(m * n);

class Solution {public int maxSideLength(int[][] mat, int threshold) {if(mat == null || mat.length == 0 || mat[0].length == 0) {return 0;}int n = mat.length;int m = mat[0].length;int[][] prefixsum = new int[n + 1][m + 1];int len = 1;int res = 0;for(int i = 1; i <= n; i++) {for(int j = 1; j <= m; j++) {prefixsum[i][j] = prefixsum[i - 1][j] + prefixsum[i][j - 1] - prefixsum[i - 1][j - 1] + mat[i - 1][j - 1];if(i - len >= 0 && j - len >= 0&& prefixsum[i][j] - prefixsum[i - len][j] - prefixsum[i][j - len] + prefixsum[i - len][j - len] <= threshold) {res = len;len++;}}}return res;}
}

Maximum Size Subarray Sum Equals k 思路:prefixsum,这里可以不用array存,直接sum加起来,用hashmap就变成了<Integer, Integer> sum, index 只要查sum - target 是否存在就可以,存在就是当前index - i,0...i ...j 长度就是j - i; O(N)

class Solution {public int maxSubArrayLen(int[] nums, int k) {if(nums == null || nums.length == 0) {return 0;}int res = 0;int cursum = 0;//       cursum   0 based indexHashMap<Integer, Integer> hashmap = new HashMap<>();hashmap.put(0, -1); // 是为了array刚好 0...j 元素和是target,那么长度是j - (-1) = j + 1用的;for(int i = 0; i < nums.length; i++) {cursum += nums[i];if(hashmap.containsKey(cursum - k)) {res = Math.max(res, i - hashmap.get(cursum - k));}// 这行很关键,就是之前有,就不要存,因为是找最大的length,所以前面的不要覆盖掉;if(!hashmap.containsKey(cursum)) {hashmap.put(cursum, i);}}return res;}
}

Matrix Block Sum 思路:这题其实考点就是个prefixSum,Sum[i..j] = PrefixSum[j] - PrefixSum[i-1],注意这里是i - 1;

// 这个点是i - k + 1的上面一个点,根据prefixSum 定义
// Sum[i, j] = PrefixSum[j] - PrefixSum[i-1];
// i - 1,也就是这个点;所以这里r1, c1没有+1;

r1 c1

r2 c2

r1, c1 的点,其实是区域范围 (i - k + 1, j - k  + 1)的上一个点;

class Solution {public int[][] matrixBlockSum(int[][] mat, int k) {if(mat == null || mat.length == 0 || mat[0].length == 0) {return mat;}int m = mat.length;int n = mat[0].length;int[][] prefixSum = new int[m + 1][n + 1];for(int i = 0; i <= m; i++) {for(int j = 0; j <= n; j++) {if(i == 0 || j == 0) {prefixSum[i][j] = 0;} else {prefixSum[i][j] = prefixSum[i - 1][j] + prefixSum[i][j - 1] - prefixSum[i - 1][j - 1]+ mat[i - 1][j - 1];}}}int[][] res = new int[m][n];for(int i = 0; i < m; i++) {for(int j = 0; j < n; j++) {int r1 = Math.max(0, i - k);int c1 = Math.max(0, j - k);int r2 = Math.min(m, i + k + 1);int c2 = Math.min(n, j + k + 1);res[i][j] = prefixSum[r2][c2] - prefixSum[r1][c2] - prefixSum[r2][c1] + prefixSum[r1][c1];}}return res;}
}

Maximum Sum of 3 Non-Overlapping Subarrays  思路:这个题目还是比较巧妙的,要求三段的和最大,核心算法就是:固定中间的一段subarry,分别用O(1)的时间去求左边部分的最大的subarry和,右边部分的最大的subarry的和。怎么用O(1)的时间去求subarry,很简单,prefixsum。但是怎么O(1)的去求一个大区间里面,哪一段的subarry是最大的,这个点就要用dp来pre compute,用leftdp记录到目前为止,从左往右看,到第i为止的最大的k size的subarry的起点index,同理:rightdp记录从右往左看 k size最大和的起点;这样有了这两个array,我就可以一口气算出

[0, i] [i, i + k -1] [i + k, n - 1] 三个区间段里面,哪三段的和最大,左边和右边可以O(1)算出来,中间的i在动,但是也可以O(1)计算出来;

prefixsum index的推倒,要熟练;

sum[i, j] = prefixsum[j] - prefixsum[i - 1] 由于 array +1了,所以 prefixsum[j + 1] - prefixsum[i]

i 跟j之间有k,那么  j = i + k - 1 <==>  i = j - k + 1;

从左往右计算,是j在移动,所以消除 i,prefixsum[j + 1] - prefixsum[j - k + 1];

从右往左计算,是i在移动,所以消除 j,prefixsum[i + k - 1 + 1] - prefixsum[i] = prefixsum[i + k] - prefixsum[i];

class Solution {public int[] maxSumOfThreeSubarrays(int[] nums, int k) {int n = nums.length;int[] presum = new int[n + 1];for(int i = 0; i < n; i++) {presum[i + 1] = presum[i] + nums[i];}// 记录到目前i为止的,从左往右看,最大的subarry的和的起始位子;int[] leftdp = new int[n];// 记录到目前i为止的,从右往左看,最大的subarry的和的起始位子;int[] rightdp = new int[n];leftdp[k] = 0;for(int j = k, total = presum[k] - presum[0]; j < n; j++) {if(presum[j + 1] - presum[j - k + 1] > total) {total = presum[j + 1] - presum[j - k + 1];leftdp[j] = j - k + 1;} else {leftdp[j] = leftdp[j - 1];}}rightdp[n - k] = n - k;for(int i = n - k - 1, total = presum[n] - presum[n - k]; i >= 0; i--) {if(presum[i + k] - presum[i] >= total) {total = presum[i + k] - presum[i];rightdp[i] = i;} else {rightdp[i] = rightdp[i + 1];}}// left,     middle,        right;// [0, i], [i, i + k - 1], [i + k, n - 1];int[] res = {-1,-1,-1};int maxsum = 0;// 左边最起码要有k个,所以start = k,右边也是要有k个,那么起点就是倒数第二个k个,也就是 n - 2*k;// 核心算法:就是固定中间的subarry,然后一口气算出各个subarry的和,怎么算,// 也就是pre calculate的leftdp, rightdp, // 然后用leftdp 和rightdp O(1)去算各个subarry的和;for(int i = k; i <= n - 2 * k; i++) {int l = leftdp[i - 1];int r = rightdp[i + k];int cursum = (presum[l + k] - presum[l]) + (presum[i + k] - presum[i]) + (presum[r + k] - presum[r]);if(cursum > maxsum) {maxsum = cursum;res[0] = l;res[1] = i;res[2] = r;}}return res;}
}

Prefix Sum 总结相关推荐

  1. CodeForces - 1485F Copy or Prefix Sum(dp)

    题目链接:点击查看 题目大意:给出数组 bbb,问可以构造出多少种满足条件的数组 aaa,规定数组 aaa 和数组 bbb 的关系如下: bi=aib_i = a_ibi​=ai​ or bi=∑j= ...

  2. codeforces1485 F. Copy or Prefix Sum(dp)

    F. Copy or Prefix Sum Venice technique简要就是懒标记思想. 由于前缀和数组和原数组一一对应,这里我们选择求aia_iai​的前缀和数组的方案数(下面aia_iai ...

  3. 牛客网暑期ACM多校训练营(第九场)H. Prefix Sum(CDQ分治)

    题目描述 Niuniu has learned prefix sum and he found an interesting about prefix sum. Let's consider (k+1 ...

  4. 牛客网暑期ACM多校训练营(第十场)D Rikka with Prefix Sum

    链接:https://www.nowcoder.com/acm/contest/148/D 来源:牛客网 题目描述 Prefix Sum is a useful trick in data struc ...

  5. 【CodeForces - 1150C】Prefix Sum Primes(思维)

    题干: We're giving away nice huge bags containing number tiles! A bag we want to present to you contai ...

  6. Prefix Sum Primes

    https://codeforces.com/contest/1150/problem/C 题解:思维+贪心 按2 1 2 2 2 ...... 1 1 1 1就可以了 /* *@Author: ST ...

  7. OpenGL 2D Prefix Sum 2维前缀总和的实例

    OpenGL 2维前缀总和 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <vmath.h> #include <shader ...

  8. 牛客网暑期ACM多校训练营(第十场)D Rikka with Prefix Sum (组合数学)

    https://www.nowcoder.com/acm/contest/148/D 题意 一个A数组,初始全为0.现有三种操作,1:给区间[L,R]+w:2:把每个位置的元素变为其前缀和:3:求区间 ...

  9. Leetcode 560. Subarray Sum Equals K

    前缀和(prefix sum/cumulative sum) import collectionsclass Solution(object):def subarraySum(self, nums, ...

最新文章

  1. bad geometry: block count 65536 exceeds size of device (53248 blocks)
  2. 如何用python画出中国地图-用Python画中国地图(二)
  3. 用php写的亲亲鲜花网站_php54鲜花销售网站
  4. 《AutoCAD 2016中文版从入门到精通》——1.5 基本输入操作
  5. 电气控制及可编程序控制器【1】
  6. python爬去学校_利用Python如何爬取自己学校的官网?用这招就行!
  7. windows抓包工具——Fiddler配置及使用、手机抓包(iPhone、安卓)
  8. linux操作系统有哪些
  9. Hp-socket高性能网络库三--tcp组件pack接收模型
  10. 打开Word,显示无法创建工作文件,请检查临时环境变量的解决办法
  11. Linux 操作系统 之 虚拟内存
  12. 超级账本 —— 面向企业的分布式账本
  13. PL-2303HX新版驱动
  14. BBRPlus魔改版本
  15. Linux下破解神器(thc org hc-hydra
  16. 动词ing基本用法_动词ing的用法
  17. Ring3无敌进程让你的进程变得和smss.exe一样支持64
  18. if中逻辑运算符表达式运行顺序
  19. 数据结构(C语言)第二版 第四章课后答案
  20. python爬虫跳过异常处理

热门文章

  1. Python自学全套教程(免费领取)
  2. 第六周项目六——复数模板类
  3. #ArcMap进行数据批量处理-模型构建器-批量重采样
  4. Switf的基本语法
  5. linux ftp 删文件夹,Linux FTP账号无法删除文件夹如何解决
  6. kali常用命令总结
  7. swift 将图片保存到本地_swift 图片存储到本地文件的搜索结果-阿里云开发者社区...
  8. 习题4-6 莫尔斯电码 UVa508
  9. 【红黑树 -- 理论与实现】
  10. ALicoin:真正基于社区共识自治的数字资产交易平台