diff --git a/16. Moderate problems/16.17. max_subarray.md b/16. Moderate problems/16.17. max_subarray.md new file mode 100644 index 0000000..a3b77e5 --- /dev/null +++ b/16. Moderate problems/16.17. max_subarray.md @@ -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. \ No newline at end of file diff --git a/16. Moderate problems/16.17. max_subarray.py b/16. Moderate problems/16.17. max_subarray.py new file mode 100644 index 0000000..f7fe285 --- /dev/null +++ b/16. Moderate problems/16.17. max_subarray.py @@ -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()