Prefix and array
Learn from Small and beautiful algorithm skills: prefix and array
303. Region and retrieval - array immutable
304. Two dimensional area and retrieval - the matrix is immutable
560. Subarray with sum K
1314. Matrix areas and
The key to distinguish between prefix and sliding window is whether the element has a negative number
One dimensional prefix sum
303. Region and retrieval - array immutable
To match the prefix and array index with the original array index,
Prefix and array length is n+1
At this time, the prefix and array i position elements represent the sum of the first i elements in the original array.
class NumArray { int []arr; public NumArray(int[] nums) { arr = new int [nums.length+1]; arr[0]=nums[0]; for(int i =1 ; i<arr.length;i++){ arr[i] = arr[i-1]+nums[i-1]; } } public int sumRange(int left, int right) { return arr[right+1]-arr[left]; } }
2D prefix and
304. Two dimensional area and retrieval - the matrix is immutable
Two dimensional matrix prefix sum
Similarly, in order to facilitate management
When we build prefixes and arrays, the number of rows and columns should be 1 more than the original array
Prefix and array arr [1] [1] represents the sum of matrix elements from the first row to the first row and from the first column to the first column in the original array
such as
Original array:
3 1
5 6
Its prefix and array are
0 0 0
0 3 3+1
0 3+5 3+1+5+6
Arr [2] [2] represents the sum of matrix elements from the first row to the second row and from the first column to the second column in the original array
The prefix established under this condition and the [i, j] element of the array represent the sum of the elements in the rectangle surrounded by [0, 0] to [i-1, j-1] in the original array.
class NumMatrix { int [][] arr ; public NumMatrix(int[][] matrix) { int m = matrix.length, n = matrix[0].length; if (m == 0 || n == 0) return; arr = new int [m+1][n+1]; // The first row and the first column have no practical significance, and the traversal starts with the row and column being 1 for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ arr[i][j]=arr[i-1][j]+arr[i][j-1]+matrix[i-1][j-1]-arr[i-1][j-1]; } } } public int sumRegion(int row1, int col1, int row2, int col2) { return arr[row2+1][col2+1]-arr[row1][col2+1]-arr[row2+1][col1]+arr[row1][col1]; } }
When solving the prefix sum of prefix and array arr [i, j], we need to use
arr[i-1,j]
arr[i,j-1]
arr[i-1,j-1]
Original array [i, j]
Elements in these four positions
Figure source leetcode - stupid pig blasting group - problem solution
Because arr [i, j] can be divided into four parts, that is, the four matrices with different colors in the figure above.
Use the sum of previously calculated elements to reduce the amount of calculation of the current element. Otherwise, the elements in [i, j] are traversed and accumulated every time, and the time responsibility is very high.
Realize the sum of elements in the rectangle surrounded by [i, j] to [m, n] (m > = i, n > = j)
Explanation of snow and candles in the upper picture source
//s(O,F) = arr[x1][y2+1] //s(O,E) = arr[x2+1][ y1] //arr[x1][y1] is actually the part in the upper left corner. Because the area of this part is subtracted once more, it needs to be added back. arr[x2+1][y2+1]-arr[x1][y2+1]-arr[x2+1][y1]+arr[x1][y1]
Prefixes and ideas
Violence Act
Generate prefix and array, and then subtract every two positions. If the value is the target number, res+1
Yes, but not elegant.
int subarraySum(int[] nums, int k) { int n = nums.length; // Construct prefix and int[] sum = new int[n + 1]; sum[0] = 0; for (int i = 0; i < n; i++) sum[i + 1] = sum[i] + nums[i]; int ans = 0; // Enumerate all subarrays for (int i = 1; i <= n; i++) for (int j = 0; j < i; j++) // sum of nums[j..i-1] if (sum[i] - sum[j] == k) ans++; return ans; }
Because we only care about the number of times and don't care about the specific solution, we can use hash table to speed up the operation
After reading the posts written by many people to describe the optimal solution, I finally found the version that I can really understand
Prefix and technique: solving the subarray problem
Because the time complexity is the largest, the expenditure is this part, which can be optimized
for (int i = 1; i <= n; i++) for (int j = 0; j < i; j++) if (sum[i] - sum[j] == k) ans++;
What's the second for loop doing? In the calculation, there are several j that can make the difference between sum[i] and sum[j] k. For each such j, add one to the result.
sum[ i ] - sum [ j ] == k
Swap the order of variables
if (sum[j] == sum[i] - k) ans++;
If you can directly record how many times sum [J] and sum [i] - K are equal, it is equivalent to finding the result.
Because we don't ask which elements are specific, we only ask the number of times, so we can use map to record in the process of generating prefix and
Each prefix and the number of occurrences are put into the map and updated in real time
Then, before the next update, judge whether there is sum - k in the map. If so, add the prefix and the number of occurrences.
code:
class Solution { public int subarraySum(int[] nums, int k) { // Key: prefix sum, value: the number of prefix sum corresponding to key Map<Integer, Integer> preSumFreq = new HashMap<>(); // For elements with subscript 0, the prefix sum is 0 and the number is 1 //For example, if you enter [1,1,0], k = 2. If there is no such line of code, it will return 0. The cases of 1 + 1 = 2 and 1 + 1 + 0 = 2 are omitted //Input: [3,1,1,0] k = 2 will not be omitted //Because presum[3] - presum[0] represents the sum of the first three bits, a map is required Put (0,1), pad the bottom //Example source: Author: chefyuan //Link: https://leetcode-cn.com/problems/subarray-sum-equals-k/solution/de-liao-yi-wen-jiang-qian-zhui-he-an-pai-yhyf/ preSumFreq.put(0, 1); int preSum = 0; int count = 0; for (int num : nums) { preSum += num; // First obtain the number of prefixes and prefix - K and add them to the count variable if (preSumFreq.containsKey(preSum - k)) { // System.out.println("num= " + num +" preSum= "+ preSum + " preSum-k= " + (preSum-k)); // System.out.println("previous count =" "+ count"); count += preSumFreq.get(preSum - k); //System.out.println("after count =" "+ count"); } // Then maintain the definition of preSumFreq preSumFreq.put(preSum, preSumFreq.getOrDefault(preSum, 0) + 1); } return count; } }
Questions similar to the idea of the algorithm:
Other prefixes and topics: