Skip to content

Commit c4f2c52

Browse files
committed
add maximumSubArray proper solutions
1 parent 77a2604 commit c4f2c52

File tree

6 files changed

+282
-7
lines changed

6 files changed

+282
-7
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Find the maximum possible sum in nums[] auch that nums[mid] is part of it
2+
function maxCrossingSum(nums, left, mid, right) {
3+
let leftMaxCrossingMid = Number.MIN_SAFE_INTEGER
4+
let sum = 0
5+
// Include elements on left of mid. (including nums[mid] itself, since we start from nums[mid] it is always included)
6+
// at the very least will contain nums[mid].. when all are positive it will have nums[mid] to nums[left]
7+
for (let i=mid; i >= left; i--) {
8+
sum = sum + nums[i]
9+
leftMaxCrossingMid = Math.max(sum, leftMaxCrossingMid)
10+
}
11+
let rightMaxCrossingMid = Number.MIN_SAFE_INTEGER
12+
sum = 0
13+
// Include elements on right of mid. (starts from nums[mid + 1] itself, since we start from nums[mid + 1] it is always included)
14+
// at the very least will contain nums[mid + 1].. when all are positive it will have nums[mid + 1] to nums[right]
15+
for (let i=(mid + 1); i <= right; i++) {
16+
sum = sum + nums[i]
17+
rightMaxCrossingMid = Math.max(sum, rightMaxCrossingMid)
18+
}
19+
return leftMaxCrossingMid + rightMaxCrossingMid
20+
}
21+
22+
function maxSubArrayHelper(nums, left, right) {
23+
// base case, only one element
24+
if (left === right) {
25+
return nums[left]
26+
}
27+
28+
const mid = Math.trunc(left + (right - left) / 2)
29+
30+
// Maximum subarray sum in left half
31+
const leftMax = maxSubArrayHelper(nums, left, mid)
32+
// Maximum subarray sum in right half
33+
const rightMax = maxSubArrayHelper(nums, mid + 1, right)
34+
// Maximum subarray sum such that the subarray crosses the midpoint
35+
const maxCrossingMid = maxCrossingSum(nums, left, mid, right)
36+
37+
/* Return maximum of following three possible cases
38+
a) Maximum subarray sum in left half
39+
b) Maximum subarray sum in right half
40+
c) Maximum subarray sum such that the subarray crosses the midpoint
41+
*/
42+
return Math.max(leftMax, rightMax, maxCrossingMid)
43+
}
44+
45+
var maxSubArray = function(nums) {
46+
return maxSubArrayHelper(nums, 0, nums.length - 1)
47+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* @param {number[]} nums
3+
* @return {number}
4+
*/
5+
var maxSubArray = function(nums) {
6+
// global maximum seen so far
7+
let maxSum = Number.MIN_SAFE_INTEGER
8+
// best max ending at previous array element (this is our subproblem)
9+
let prevSubArrayMaxSum = Number.MIN_SAFE_INTEGER
10+
nums.forEach(num => {
11+
/*
12+
We want to answer the question:
13+
"What is the Max Contiguous Subarray Sum we can achieve ending at index i?"
14+
15+
We have 2 choices:
16+
17+
prevSubArrayMaxSum + nums[i] (extend the previous subarray best whatever it was)
18+
1.) Let the item we are sitting at contribute to this best max we achieved
19+
ending at index i - 1.
20+
21+
2.) Just take the item we are sitting at's value.
22+
23+
The max of these 2 choices will be the best answer to the Max Contiguous SubArraySum ending at i index
24+
*/
25+
const currSubArrayMaxSum = Math.max(num, prevSubArrayMaxSum + num)
26+
maxSum = Math.max(maxSum, currSubArrayMaxSum)
27+
prevSubArrayMaxSum = currSubArrayMaxSum
28+
})
29+
return maxSum
30+
};
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
class CubicTimeSolution {
2+
3+
public int maxSubArray(int[] nums) {
4+
5+
int n = nums.length;
6+
int maximumSubArraySum = Integer.MIN_VALUE;
7+
8+
/*
9+
We will use these outer 2 for loops to investigate all
10+
windows of the array.
11+
12+
We plant at each 'left' value and explore every
13+
'right' value from that 'left' planting.
14+
15+
These are our bounds for the window we will investigate.
16+
*/
17+
for (int left = 0; left < n; left++) {
18+
for (int right = left; right < n; right++) {
19+
20+
/*
21+
Let's investigate this window
22+
*/
23+
int windowSum = 0;
24+
25+
/*
26+
Add all items in the window
27+
*/
28+
for (int k = left; k <= right; k++) {
29+
windowSum += nums[k];
30+
}
31+
32+
/*
33+
Did we beat the best sum seen so far?
34+
*/
35+
maximumSubArraySum = Math.max(maximumSubArraySum, windowSum);
36+
37+
}
38+
}
39+
40+
return maximumSubArraySum;
41+
}
42+
43+
}
44+
45+
class QuadraticTimeSolution {
46+
47+
public int maxSubArray(int[] nums) {
48+
49+
int n = nums.length;
50+
int maximumSubArraySum = Integer.MIN_VALUE;
51+
52+
for (int left = 0; left < n; left++) {
53+
54+
/*
55+
Reset our running window sum once we choose a new
56+
left bound to plant at. We then keep a new running
57+
window sum.
58+
*/
59+
int runningWindowSum = 0;
60+
61+
/*
62+
We improve by noticing we are performing duplicate
63+
work. When we know the sum of the subarray from
64+
0 to right - 1...why would we recompute the sum
65+
for the subarray from 0 to right?
66+
67+
This is unnecessary. We just add on the item at
68+
nums[right].
69+
*/
70+
for (int right = left; right < n; right++) {
71+
72+
/*
73+
We factor in the item at the right bound
74+
*/
75+
runningWindowSum += nums[right];
76+
77+
/*
78+
Does this window beat the best sum we have seen so far?
79+
*/
80+
maximumSubArraySum = Math.max(maximumSubArraySum, runningWindowSum);
81+
82+
}
83+
}
84+
85+
return maximumSubArraySum;
86+
}
87+
88+
}
89+
90+
class LinearTimeSolution {
91+
92+
public int maxSubArray(int[] nums) {
93+
94+
/*
95+
We default to say the the best maximum seen so far is the first
96+
element.
97+
98+
We also default to say the the best max ending at the first element
99+
is...the first element.
100+
*/
101+
int maxSoFar = nums[0];
102+
int maxEndingHere = nums[0];
103+
104+
/*
105+
We will investigate the rest of the items in the array from index
106+
1 onward.
107+
*/
108+
for (int i = 1; i < nums.length; i++){
109+
110+
/*
111+
We are inspecting the item at index i.
112+
113+
We want to answer the question:
114+
"What is the Max Contiguous Subarray Sum we can achieve ending at index i?"
115+
116+
We have 2 choices:
117+
118+
maxEndingHere + nums[i] (extend the previous subarray best whatever it was)
119+
1.) Let the item we are sitting at contribute to this best max we achieved
120+
ending at index i - 1.
121+
122+
nums[i] (start and end at this index)
123+
2.) Just take the item we are sitting at's value.
124+
125+
The max of these 2 choices will be the best answer to the Max Contiguous
126+
Subarray Sum we can achieve for subarrays ending at index i.
127+
128+
Example:
129+
130+
index 0 1 2 3 4 5 6 7 8
131+
Input: [ -2, 1, -3, 4, -1, 2, 1, -5, 4 ]
132+
-2, 1, -2, 4, 3, 5, 6, 1, 5 'maxEndingHere' at each point
133+
134+
The best subarrays we would take if we took them:
135+
ending at index 0: [ -2 ] (snippet from index 0 to index 0)
136+
ending at index 1: [ 1 ] (snippet from index 1 to index 1) [we just took the item at index 1]
137+
ending at index 2: [ 1, -3 ] (snippet from index 1 to index 2)
138+
ending at index 3: [ 4 ] (snippet from index 3 to index 3) [we just took the item at index 3]
139+
ending at index 4: [ 4, -1 ] (snippet from index 3 to index 4)
140+
ending at index 5: [ 4, -1, 2 ] (snippet from index 3 to index 5)
141+
ending at index 6: [ 4, -1, 2, 1 ] (snippet from index 3 to index 6)
142+
ending at index 7: [ 4, -1, 2, 1, -5 ] (snippet from index 3 to index 7)
143+
ending at index 8: [ 4, -1, 2, 1, -5, 4 ] (snippet from index 3 to index 8)
144+
145+
Notice how we are changing the end bound by 1 everytime.
146+
*/
147+
maxEndingHere = Math.max(maxEndingHere + nums[i], nums[i]);
148+
149+
/*
150+
Did we beat the 'maxSoFar' with the 'maxEndingHere'?
151+
*/
152+
maxSoFar = Math.max(maxSoFar, maxEndingHere);
153+
}
154+
155+
return maxSoFar;
156+
}
157+
158+
}

00_Arrays/MaximumSubArray/MaximumSubArray.java renamed to 00_Arrays/MaximumSubArray/Java/MaximumSubArray.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,5 @@ public static int divideAndConquer(final int[] a, final int start, final int end
5050
}
5151
return Math.max(leftmax+rightmax, Math.max(leftMSS, rightMSS));
5252
}
53-
53+
5454
}

00_Arrays/MaximumSubArray/README.md

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,49 @@
1-
## Maximum subarray sum
2-
> Given a array, find largest sum contiguous subarray
3-
1+
## Maximum Subarray
2+
3+
![Difficulty-Easy](https://img.shields.io/badge/Difficulty-Easy-green)
4+
5+
Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
6+
7+
Example:
8+
9+
Input: [-2,1,-3,4,-1,2,1,-5,4],
10+
Output: 6
11+
Explanation: [4,-1,2,1] has the largest sum = 6.
12+
Follow up:
13+
14+
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
15+
16+
Accepted
17+
18+
## Complexity Analysis (Divide and conquer):
19+
20+
**See [JS Solution](JS/DivideAndConquer.js)**
21+
22+
- **Time complexity** : `O(n) -- linear`. We sweep through the array once.
23+
24+
- **Space complexity** : `O(1)`. Only two extra variables to keep the global-max-so-far and max-subarray-sum-for-subarray-ending-at-previous-element-of-thearray.
25+
26+
## Complexity Analysis (Divide and conquer):
27+
28+
**See [JS Solution](JS/DivideAndConquer.js)**
29+
30+
- **Time complexity** : `O(n * log(n))`. We divide each problem by half. Making it `log(n)` steps. In each step we do `O(n)` work. Same as `merge sort` complexity analysis.
31+
32+
- **Space complexity** : `O(log(n))`. Stack space to keep on dividing in half. Same as `merge sort` complexity analysis.
33+
34+
## Complexity Analysis (Brute Force):
35+
36+
**See [Java Solution](Java/BackToBackSWESolution.java)**
37+
38+
- **Time complexity** : `O(n^2) and O(n^3)`. For each element we consider every window (subarray) that contains this element.
39+
40+
- **Space complexity** : `O(1)`. No extra space used
41+
442
## Time complexities
5-
* Brute force - `O(n^2) and O(n^3)`
43+
* Brute force - `O(n^2) and O(n^3)` -- see [Java Solution](Java/BackToBackSWESolution.java)
644
* Divide and conquer - `O(nlogn)`
745
* Kadane algorithm - `O(n)` - TODO
8-
9-
[Source - youtube](https://www.youtube.com/watch?v=ohHWQf1HDfU)
46+
47+
#### [YouTube - Back To Back SWE - detailed kadane explanation](https://www.youtube.com/watch?v=2MmGzdiKR9Y)
48+
#### [geeksforgeeks - divide-and-conquer explanation](https://www.geeksforgeeks.org/maximum-subarray-sum-using-divide-and-conquer-algorithm/)
49+
#### [YouTube - my code school - explains all variations](https://www.youtube.com/watch?v=ohHWQf1HDfU)

0 commit comments

Comments
 (0)