|
2 | 2 |
|
3 | 3 | // #Hard #Array #Dynamic_Programming #Binary_Search #Matrix #Ordered_Set
|
4 | 4 |
|
5 | | -/* |
6 | | -* |
7 | | -* Basic idea is the same as previous approach but we solve the problem in Step 2 differently. |
8 | | -* Here we leverage divide and conquer technique. Basically we perform merge sort on prefix sum values and |
9 | | -* calculate result during merge step. |
10 | | -* One might remember the idea of using merge sort to count inversions in an array. This is very similar. |
11 | | - |
12 | | -* So how exactly do we compute result during merge step? |
13 | | -* Suppose we are merging left prefix subarray and right prefix subarray. |
14 | | -* Remember from previous approach, for each index we're trying to find an old prefix sum which is just greater than or |
15 | | -* equal to current prefix sum - k. |
16 | | -* So we can iterate over right subarray and for each index j, keep incrementing the pointer |
17 | | -* in left array i (initialized to start index) till that situation is false (or basically prefix[i] < prefix[j] - k). |
18 | | -* This way, we can compute the result for all cross subarrays (i.e. i in left subarray and j in right subarray) |
19 | | -* in linear time. |
20 | | -* After this, we do the standard merging part of merge sort. |
21 | | -* |
22 | | -*/ |
23 | | - |
24 | | -import java.util.Arrays; |
25 | | - |
26 | 5 | public class Solution {
|
27 | | - private int[] m; |
28 | | - |
29 | | - private int merge(int[] a, int l, int m, int r, int k) { |
30 | | - int res = Integer.MIN_VALUE; |
31 | | - for (int j = m + 1; j <= r; j++) { |
32 | | - int i = l; |
33 | | - while (i <= m && a[j] - a[i] > k) { |
34 | | - i++; |
35 | | - } |
36 | | - if (i > m) { |
37 | | - break; |
38 | | - } |
39 | | - res = Math.max(res, a[j] - a[i]); |
40 | | - if (res == k) { |
41 | | - return res; |
42 | | - } |
43 | | - } |
44 | | - int i = l; |
45 | | - int j = m + 1; |
46 | | - int t = 0; |
47 | | - while (i <= m && j <= r) { |
48 | | - this.m[t++] = a[i] <= a[j] ? a[i++] : a[j++]; |
49 | | - } |
50 | | - while (i <= m) { |
51 | | - this.m[t++] = a[i++]; |
52 | | - } |
53 | | - while (j <= r) { |
54 | | - this.m[t++] = a[j++]; |
55 | | - } |
56 | | - for (i = l; i <= r; i++) { |
57 | | - a[i] = this.m[i - l]; |
58 | | - } |
59 | | - return res; |
60 | | - } |
61 | | - |
62 | | - private int mergeSort(int[] a, int l, int r, int k) { |
63 | | - if (l == r) { |
64 | | - return a[l] <= k ? a[l] : Integer.MIN_VALUE; |
65 | | - } |
66 | | - int localM = l + ((r - l) >> 1); |
67 | | - int res = mergeSort(a, l, localM, k); |
68 | | - if (res == k) { |
69 | | - return res; |
| 6 | + public int maxSumSubmatrix(int[][] matrix, int k) { |
| 7 | + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { |
| 8 | + return 0; |
70 | 9 | }
|
71 | | - res = Math.max(res, mergeSort(a, localM + 1, r, k)); |
72 | | - if (res == k) { |
73 | | - return res; |
74 | | - } |
75 | | - return Math.max(res, merge(a, l, localM, r, k)); |
76 | | - } |
77 | | - |
78 | | - private int maxSumSubArray(int[] a) { |
79 | | - int min = 0; |
80 | | - int res = Integer.MIN_VALUE; |
81 | | - for (int sum : a) { |
82 | | - res = Math.max(res, sum - min); |
83 | | - min = Math.min(min, sum); |
84 | | - } |
85 | | - return res; |
86 | | - } |
87 | | - |
88 | | - private int maxSumSubArray(int[] a, int k) { |
89 | | - int res = maxSumSubArray(a); |
90 | | - if (res <= k) { |
91 | | - return res; |
92 | | - } |
93 | | - return mergeSort(a.clone(), 0, a.length - 1, k); |
94 | | - } |
95 | | - |
96 | | - public int maxSumSubMatrix(int[][] matrix, int k) { |
97 | | - int localM = matrix.length; |
98 | | - int localN = localM == 0 ? 0 : matrix[0].length; |
| 10 | + int row = matrix.length; |
| 11 | + int col = matrix[0].length; |
99 | 12 | int res = Integer.MIN_VALUE;
|
100 | | - boolean groupingRows = true; |
101 | | - if (localM > localN) { |
102 | | - int temp = localM; |
103 | | - localM = localN; |
104 | | - localN = temp; |
105 | | - groupingRows = false; |
106 | | - } |
107 | | - int[] sum = new int[localN]; |
108 | | - this.m = new int[localN]; |
109 | | - for (int i = 0; i < localM; i++) { |
110 | | - Arrays.fill(sum, 0); |
111 | | - for (int j = i; j < localM; j++) { |
112 | | - int pre = 0; |
113 | | - if (groupingRows) { |
114 | | - for (int t = 0; t < localN; t++) { |
115 | | - sum[t] += pre += matrix[j][t]; |
| 13 | + for (int i = 0; i < col; i++) { |
| 14 | + int[] sum = new int[row]; |
| 15 | + for (int j = i; j < col; j++) { |
| 16 | + for (int r = 0; r < row; r++) { |
| 17 | + sum[r] += matrix[r][j]; |
| 18 | + } |
| 19 | + int curr = 0; |
| 20 | + int max = sum[0]; |
| 21 | + for (int n : sum) { |
| 22 | + curr = Math.max(n, curr + n); |
| 23 | + max = Math.max(curr, max); |
| 24 | + if (max == k) { |
| 25 | + return max; |
116 | 26 | }
|
| 27 | + } |
| 28 | + if (max < k) { |
| 29 | + res = Math.max(max, res); |
117 | 30 | } else {
|
118 | | - for (int t = 0; t < localN; t++) { |
119 | | - sum[t] += pre += matrix[t][j]; |
| 31 | + for (int a = 0; a < row; a++) { |
| 32 | + int currSum = 0; |
| 33 | + for (int b = a; b < row; b++) { |
| 34 | + currSum += sum[b]; |
| 35 | + if (currSum <= k) { |
| 36 | + res = Math.max(currSum, res); |
| 37 | + } |
| 38 | + } |
| 39 | + } |
| 40 | + if (res == k) { |
| 41 | + return res; |
120 | 42 | }
|
121 | | - } |
122 | | - res = Math.max(res, maxSumSubArray(sum, k)); |
123 | | - if (res == k) { |
124 | | - return res; |
125 | 43 | }
|
126 | 44 | }
|
127 | 45 | }
|
|
0 commit comments