Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy path53. Maximum Subarray.java
More file actions
Latest commit
executable file
·329 lines (283 loc) · 9.87 KB
/
Copy path53. Maximum Subarray.java
File metadata and controls
executable file
·329 lines (283 loc) · 9.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
E
tags: DP, SequenceDP, Array, DivideandConquer, DFS, PreSum, Subarray
time: O(n)
space: O(n), O(1) rollingarray
给一串数组, unsorted, canhavenegative/positivenum. 找数组中间subarray数字之和的最大值
#### PreSum
- 想着用一用prefixsum. 把值一个个叠加
- 然后presum[j] - presum[i- 1] 就是 (i,j)之间的和
- O(n^2), notassufficient
#### SequenceDP
- dp[i]: lastelement(或包括前i个element), 可能组成的subarray的最大sum.
- dp[i] = Math.max(dp[i-1]+lastElement, lastElement(dropdp[i-1]))
- init:
- dp = int[n + 1],
- dp[0]: first0items, doesnothaveanysum
- 因为continoussequence, 所以不满足条件的时候, 会断.
- needtotakecurrnumregardless => candropprevmaxindp[i]
- trackoverallmax
- initdp[0] = 0; max = MIN_VALUE因为有负数
- Time, spaceO(n)
- Rollingarray, spaceO(1)
#### DivideandConquer, DFS
- 找一个midpiont, 考虑3种情况: 1) 只要左边, 2) 只要右边, 3) cross-mid
- left/rigthcase: 直接dfs
- corss-midcase: continuoussummaxfromleft + continoussummaxfromright + mid
- continuoussummaxfromonedirection:
- WorstcaseO(n^2): visitallnodesO(n); indfs: calculatescontinuoussum (includingmid), whichisalsoO(n)
/*
// handle cross-mid case
int tempSum = 0, continuousLeftSumMax = 0;
// find continuous max going towards left
for (int i = mid - 1; i >= left; i--) {
// always continous summing up
tempSum += nums[i];
// from one direction, take the best
continuousLeftSumMax = Math.max(continuousLeftSumMax, tempSum);
}
*/
```
/**
LeetCode:
Given an integer array nums, find the contiguous subarray (containing at least one number)
which has the largest sum and return its sum.
Example:
Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.
Follow up:
If you have figured out the O(n) solution,
try coding another solution using the divide and conquer approach,
which is more subtle.
*/
// Despte the detailed dp[] solution, we have the light version:
publicclassSolution {
publicintmaxSubArray(int[] nums) {
if (nums == null || nums.length == 0) returnInteger.MIN_VALUE;
intpreMaxSum = 0, max = Integer.MIN_VALUE;
for (intnum : nums) {
preMaxSum = Math.max(num, preMaxSum + num);
max = Math.max(max, preMaxSum);
}
returnmax;
}
}
/*
Use regular preSum - smallest preSum in earlier spots, which gives largest value.
So maintain a regular preSum, and maintain a minPreSum.
Maintain a max to mark the difference between (preSum - minPreSum)
Also, here, we dont' really care about index.So just skip index.
O(n) here
*/
publicclassSolution {
publicintmaxSubArray(int[] nums) {
if (nums == null || nums.length == 0) return0;
intpreSum = 0, minPreSum = 0;
intmax = Integer.MIN_VALUE;
for (intnum : nums) {
preSum += num;
max = Math.max(max, preSum - minPreSum);
minPreSum = Math.min(minPreSum, preSum);
}
returnmax;
}
}
/*
Thoughts:
sequence dp
continous subarray: cannot skip element
dp[i]: for first i items, what's the largest sum that containts nums[i]?
dp[i] = Math.max(dp[i - 1] + nums[i - 1], nums[i - 1])
record max globally
dp[i]: 0 items, max = 0
*/
classSolution {
publicintmaxSubArray(int[] nums) {
if (nums == null || nums.length == 0) return0;
intn = nums.length, max = Integer.MIN_VALUE;
int[] dp = newint[n + 1]; // extra space to store dp[n]
dp[0] = 0;
for (inti = 1; i <= n; i++) {
// continuous so always will use nums[i-1]
dp[i] = Math.max(dp[i - 1] + nums[i - 1], nums[i - 1]);
max = Math.max(max, dp[i]);
}
returnmax;
}
}
// Rolling array:
classSolution {
publicintmaxSubArray(int[] nums) {
if (nums == null || nums.length == 0) return0;
intn = nums.length;
int[] dp = newint[2];
dp[0] = 0;
intmax = Integer.MIN_VALUE;
for (inti = 1; i <= n; i++) {
dp[i % 2] = Math.max(dp[(i - 1) % 2] + nums[i - 1], nums[i - 1]);
max = Math.max(max, dp[i % 2]);
}
returnmax;
}
}
/**
Slight diff: checking dp[i-1] >= 0.
Same as Math.max(dp[i - 1] + nums[i - 1], nums[i - 1]);
*/
classSolution {
publicintmaxSubArray(int[] nums) {
if (nums == null || nums.length == 0) return0;
// init dp, global max
intn = nums.length, max = Integer.MIN_VALUE;
int[] dp = newint[n + 1];
dp[0] = 0;
for (inti = 1; i <= n; i++) {
dp[i] = nums[i - 1] + (dp[i - 1] >= 0 ? dp[i - 1] : 0);
max = Math.max(max, dp[i]);
}
returnmax;
}
}
// Rolling array
classSolution {
publicintmaxSubArray(int[] nums) {
if (nums == null || nums.length == 0) return0;
intn = nums.length, max = Integer.MIN_VALUE;
int[] dp = newint[2];
dp[0] = 0;
for (inti = 1; i <= n; i++) {
dp[i % 2] = nums[i - 1] + (dp[(i - 1) % 2] >= 0 ? dp[(i - 1) % 2] : 0);
max = Math.max(max, dp[i % 2]);
}
returnmax;
}
}
/*
DFS, divide and conquer,
3 conditions: left of mid, right of mid, or cross-mid
use dfs to calculate left case, right case
carefully handle cross-mid case
*/
classSolution {
publicintmaxSubArray(int[] nums) {
if (nums == null || nums.length == 0) return0;
returndfs(nums, 0, nums.length - 1, Integer.MIN_VALUE);
}
privateintdfs(int[] nums, intleft, intright, intsum) {
if (left > right) returnInteger.MIN_VALUE;
// dfs on left, right range. Mid point is skipped
intmid = left + (right - left) / 2;
intleftMax = dfs(nums, left, mid - 1, sum);
intrightMax = dfs(nums, mid + 1, right, sum);
intmaxSum = Math.max(sum, Math.max(leftMax, rightMax));
// handle cross-mid case
// find continuous max going towards left
intcontinuousLeftSumMax = findContinuousSum(mid-1, left, right, -1, nums);
// find continuous max going towards right
intcontinuousRightSumMax = findContinuousSum(mid+1, left, right, 1, nums);
maxSum = Math.max(maxSum, nums[mid] + continuousLeftSumMax + continuousRightSumMax);
returnmaxSum;
}
// set up left/right bound, and use offset to customize for loop: avoid redundant code
privateintfindContinuousSum(intstart, intleft, intright, intoffset, int[] nums) {
intcontinuousSum = 0, max = 0;
for (inti = start; i >= left && i <= right; i+=offset) {
continuousSum += nums[i];
max = Math.max(max, continuousSum);
}
returnmax;
}
}
/*
LintCode
Maximum Subarray Show Result My Submissions
35% Accepted
Given an array of integers, find a contiguous subarray which has the largest sum.
Note
The subarray should contain at least one number
Example
For example, given the array [−2,2,−3,4,−1,2,1,−5,3], the contiguous subarray [4,−1,2,1] has the largest sum = 6.
Challenge
Can you do it in time complexity O(n)?
Tags Expand
Array SubArray Greedy Enumeration LintCode Copyright
*/
/*
Thoughts:
1. Move end see how far it can go which keeps sum increasing
2. sum[i] = sum[i - 1] + nums[i]. We need to decide if sum[i] will take sum[i-1] depending on if sum[i-1] is positive or negative.
3. maintain a maxSum
*/
classSolution {
publicintmaxSubArray(int[] nums) {
if (nums == null || nums.length == 0) {
return0;
}
finalint[] sums = newint[nums.length];
sums[0] = nums[0];
intmaxSum = sums[0];
for (inti = 1; i < nums.length; i++) {
if (sums[i - 1] < 0) {// sums[i-1] only reduces maxSum, therefore skip it in sums[i]
sums[i] = nums[i];
} else {
sums[i] = sums[i - 1] + nums[i];
}
maxSum = Math.max(maxSum, sums[i]);
}
returnmaxSum;
}
}
/*
Same as above, but with list as input
Thinking proces:
Store the sum in a array.
Normally, sum[i] = sum[i - 1] + nums[i].
However, if sum[i - 1] is a nagetive number, that means sum[i - 1] won't do any good for later sum but only decrease the sum.
In this case, when sums[i - 1] < 0, we don't add it.
When sum[i-1], it actaully starts from nums.get(i) again.
*/
publicclassSolution {
/**
* @param nums: A list of integers
* @return: A integer indicate the sum of max subarray
*/
publicintmaxSubArray(ArrayList<Integer> nums) {
if (nums == null || nums.size() == 0) {
return0;
}
int[] sums = newint[nums.size()];
sums[0] = nums.get(0);
intmaxSum = sums[0];
for (inti = 1; i < sums.length; i++) {
if (sums[i - 1] < 0) {
sums[i] = nums.get(i);
} else {
sums[i] = sums[i - 1] + nums.get(i);
}
maxSum = Math.max(maxSum, sums[i]);
}
returnmaxSum;
}
}
/*
To further extend the prefix sum idea, we are really trying:
Use regular preSum - smallest preSum in earlier spots, which gives largest value.
So maintain a regular preSum, and maintain a minPreSum.
Maintain a max to mark the difference between (preSum - minPreSum)
Also, here, we dont' really care about index.So just skip index.
O(n) here
*/
publicclassSolution {
publicintmaxSubArray(int[] nums) {
if (nums == null || nums.length == 0) return0;
intpreSum = 0, minPreSum = 0;
intmax = Integer.MIN_VALUE;
for (intnum : nums) {
preSum += num;
max = Math.max(max, preSum - minPreSum);
minPreSum = Math.min(minPreSum, preSum);
}
returnmax;
}
}
```