parent
8da990843f
commit
44805d8516
|
|
@ -0,0 +1,104 @@
|
||||||
|
# 16.8. Contiguous sequence or Maximum subarray problem
|
||||||
|
|
||||||
|
## Given an array of integers, both negative and positive, find the contiguous sequence with the largest sum. Return the sum
|
||||||
|
|
||||||
|
> example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nums = [2, -8, 3, -2, 4, -10]
|
||||||
|
output = 5, [3, -2, 4]
|
||||||
|
```
|
||||||
|
|
||||||
|
## First idea
|
||||||
|
|
||||||
|
Brute force, check all possible substrings/subarrays and check for the maximum. Keep track of the biggest, discard those smaller. Very bad complexity.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
1. [2]:2
|
||||||
|
2. start with [2,-8]: -6
|
||||||
|
3. [2, -8, 3]: -3. but [-8, 3]: -5, and [3]: 3
|
||||||
|
4. [3,-2]: 1
|
||||||
|
5. [3,-2,4]:5
|
||||||
|
6. [3,-2,4,-10]:-5
|
||||||
|
7. [-2,4,-10]:-8
|
||||||
|
8. [-4,-10]:-6
|
||||||
|
```
|
||||||
|
|
||||||
|
This is O(n), but does it work for each case?
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nums = [2, -12, 3, -5, 4, -10]
|
||||||
|
possibility = max(nums) = 4
|
||||||
|
output = 4
|
||||||
|
|
||||||
|
1. [2]:2
|
||||||
|
2. [2,-12]:-10
|
||||||
|
3. [3,-5]:-2
|
||||||
|
4. [4, -10]:-6
|
||||||
|
```
|
||||||
|
|
||||||
|
if max(nums) > 0, find first positive element in array. Negative values with abs(neg) > max(nums) are useless. We might have [3,-1,4,-1,2]:7 and this might win.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nums = [2, 1, 1, 1, -8, 3, -1, 4, -2, 3, -1, -1, -1, -3, -6]
|
||||||
|
possibility = max(nums) = 4
|
||||||
|
output = 7
|
||||||
|
|
||||||
|
1. [2]:2
|
||||||
|
2. [2,1,1,1]:5 (until negative num. if neg > 4, discard).
|
||||||
|
3. [3,-1,4-2,3]:7 iterate through the array, if the sequence > max, keep track of highest and index. when we go lower, keep track until sum of sequence < max
|
||||||
|
4. [3,-1,4-2,3,-1,-1,-1]:4 Can we break? before finishing the array? but what if there is a huge sequence of max-1 max-1 max-1 max-1... we can only break this sequence if total sum < 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Another possibility
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nums = [3, -1, 4, -2, 3, -1, -1, 3, -3, -6]
|
||||||
|
possibility = max(nums) = 4
|
||||||
|
output = 8, [3, -1, 4, -2, 3, -1, -1, 3]
|
||||||
|
```
|
||||||
|
|
||||||
|
But what if:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nums = [3, -1, 4, -2, 3, -1, -3, 3, -6, 4]
|
||||||
|
possibility = max(nums) = 4
|
||||||
|
output = 7, [3, -1, 4, -2, 3]
|
||||||
|
```
|
||||||
|
|
||||||
|
We still have to consider the whole subarray as long as the sum is positive, because if we find a max value, it will boost the sum.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nums = [4, -3, 3, -4, 4, -1, 1, 3, -7]
|
||||||
|
possibility = max(nums) = 4
|
||||||
|
output = 7, [4, -3, 3, -4, 4, -1, 1, 3]
|
||||||
|
```
|
||||||
|
|
||||||
|
Have to consider the whole substring until total value is negative.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nums = [4, -3, 3, -4, 4, -1, 1, 3, -7, 2, 2, 4]
|
||||||
|
possibility = max(nums) = 4
|
||||||
|
output = 8 [2, 2, 4]
|
||||||
|
```
|
||||||
|
|
||||||
|
If max value is negative, the threshold of keeping the subarray is until total sum is smaller than 2*max. but no, if maxval is negative, all the other numbers in the array will also be negative, so sum decreseases. return max(nums).
|
||||||
|
|
||||||
|
Tests passed, code works! O(n), O(1) space. Is this greedy algorithm?
|
||||||
|
|
||||||
|
## Hints
|
||||||
|
|
||||||
|
* A sequence of values with negative sum never start or end a sequence, they might be in the middle of a longer sequence.
|
||||||
|
* Start from the beginning of the array. As that subsequence gets larger, it stays as the best subsequence. Once it becomes negative, it's useless.
|
||||||
|
* When the sum is negative, reset the count
|
||||||
|
* This can be solved in O(n) time and O(1) space.
|
||||||
|
|
||||||
|
I think I got it right.
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
We only want negative numbers inculded in the sequence when they are in the middle of two positive sequences, each of which have a sum greater than the negative value. When the maxval is surpassed, we keep track of the new maxval and sum/count. Keep updating the sum until either maxval is surpassed again, or sum is negative. if that's the case, reset sum.
|
||||||
|
|
||||||
|
My code is exactly the same as the solution! (except for some unecessary variables I had).
|
||||||
|
|
||||||
|
If all numbers in the array are negative, can we consider a subsequence of length = 0 and thus maxval = 0? or does it need to have 1+ values? this is a good thing to consider with the interviewer.
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
def cont_seq(nums):
|
||||||
|
if not nums:
|
||||||
|
return 0
|
||||||
|
if len(nums) == 1:
|
||||||
|
return nums[0]
|
||||||
|
if len(nums) == 2:
|
||||||
|
return max(max(nums), sum(nums))
|
||||||
|
if max(nums) < 0:
|
||||||
|
return max(nums)
|
||||||
|
if max(nums) == min(nums):
|
||||||
|
return max(nums)
|
||||||
|
|
||||||
|
maxval = 0
|
||||||
|
count = 0
|
||||||
|
for n in nums:
|
||||||
|
count += n
|
||||||
|
if count < 0:
|
||||||
|
count = 0
|
||||||
|
elif count > maxval:
|
||||||
|
maxval = count
|
||||||
|
|
||||||
|
return maxval
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
data = [([], 0),
|
||||||
|
([2, -8, 3, -2, 4, -10], 5),
|
||||||
|
([2, -12, 3, -5, 4, -10], 4),
|
||||||
|
([2, 1, 1, 1, -8, 3, -1, 4, -2, 3, -1, -1, -1, -3, -6], 7),
|
||||||
|
([3, -1, 4, -2, 3, -1, -1, 3, -3, -6], 8),
|
||||||
|
([3, -1, 4, -2, 3, -1, -3, 3, -6, 4], 7),
|
||||||
|
([4, -3, 3, -4, 4, -1, 1, 3, -7], 7),
|
||||||
|
([4, -3, 3, -4, 4, -1, 1, 3, -7, 2, 2, 4], 8)]
|
||||||
|
|
||||||
|
def test_rotate_matrix(self):
|
||||||
|
for nums, expected in self.data:
|
||||||
|
res = cont_seq(nums)
|
||||||
|
self.assertEqual(res, expected)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Loading…
Reference in New Issue