0. Maximum Product Subarray.java Level: Medium Tags: [Array, DP, Subarray]
从一组数列(正负都有)里面找一串连续的子序列, 而达到乘积product最大值.
- 求最值, 想到DP. Time/Space O (n)
- 两个特别处:
-
- 正负数情况, 需要用两个DP array.
-
- continuous prodct 这个条件决定了在Math.min, Math.max的时候,
- 是跟nums[x]当下值比较的, 如果当下值更适合, 会舍去之前的continous product, 然后重新开始.
- 这也就注定了需要一个global variable 来hold result.
- maxProduct && minProduct 里面的 index i, 都只能 i - 1相关, 所以可以省去redundant operatoins
- Time: O(n), space: O(1)
1. Maximum Average Subarray I.java Level: Easy Tags: [Array, Subarray]
time: O(n) space: O(1)
简单的求sum of fixed window k, 同时求max avg, 结尾求余数就好.
2. Minimum Size Subarray Sum.java Level: Medium Tags: [Array, Binary Search, Subarray, Two Pointers]
time: O(n) space: O(1)
给一串positive integer, 找最短的subarray sum, where the sum >= s
- 全部是positive integer, 那么preSum一定是增长的.
- 那其实就用two pointer:
start=0, end=0不断往前移动. 策略: -
- end++ until a solution where sum >= s is reached
-
- 然后移动start; 记录每个solution, Math.min(min, end - start);
-
- 然后再移动end,往下找
- Note: 虽然一眼看上去是nested loop.但是分析后,发现其实就是按照end pointer移动的Loop。start每次移动一格。总体上,还是O(n)
- O(nlogn) NOT DONE.
- O(n^2), inefficient
3. Continuous Subarray Sum.java Level: Medium Tags: [Coordinate DP, DP, Math, Subarray]
给一个非负数的数列和数字k(可正负, 可为0). 找到连续子序列(长度超过2), 使得这个subarray的sum 是 k的倍数. 问: 是否可能?
- O(n^2)
- 需要记录在0 ~ i点(包括nums[i], 以nums[i]结尾)的sum, 坐标型动态规划.
- dp[i] = dp[i - 1] + nums[i];
- 最后移动, 作比较
- 从sum = 每次[i ~ j]的所有情况
- 验证
4. Maximum Subarray.java Level: Easy Tags: [Array, DFS, DP, Divide and Conquer, PreSum, Sequence DP, Subarray]
time: O(n) space: O(n), O(1) rolling array
给一串数组, unsorted, can have negative/positive num. 找数组中间 subarray 数字之和的最大值
- dp[i]: 前i个element,包括 last element (i-1), 可能组成的 subarray 的最大sum.
- init: dp = int[n + 1], dp[0]: first 0 items, does not have any sum
- 因为continous sequence, 所以不满足条件的时候, 会断. That is: need to take curr num, regardless => can drop prev max in dp[i]
- track overall max
- init dp[0] = 0; max = MIN_VALUE 因为有负数
- Time, space O(n)
- Rolling array, space O(1)
- 找一个mid piont, 考虑3种情况: 只要左边, 只要右边, cross-mid
- left/rigth 的case, 直接 dfs
- corss-mid case: continuous sum max from left + continous sum max from right + mid
- continuous sum max from one direction:
5. Maximum Subarray II.java Level: Medium Tags: [Array, DP, Greedy, PreSum, Sequence DP, Subarray]
给一串数组, 找数组中间 两个不交互的 subarray 数字之和的最大值
- 考虑两个方向的dp[i]: 包括i在内的subarray max sum.
- dp[i] 的特点是: 如果上一个 dp[i - 1] + nums[i - 1] 小于 nums[i-1], 那么就舍弃之前, 从头再来:
- dp[i] = Math.max(dp[i - 1] + nums.get(i - 1), nums.get(i - 1));
- 缺点: 无法track全局max, 需要记录max.
- 因为我们现在要考虑从左边/右边来的所有max, 所以要记录maxLeft[] 和 maxRight[]
- maxLeft[i]: 前i个元素的最大sum是多少 (不断递增); maxRight反之, 从右边向左边
- 最后比较maxLeft[i] + maxRight[i] 最大值
- Space, Time O(n)
- Rolling array, reduce some space, but can not reduce maxLeft/maxRight
- preSum是[0, i] 每个数字一次加起来的值
- 如果维持一个minPreSum, 就是记录[0, i]sum的最小值(因为有可能有负数)
- preSum - minPreSum 就是在 [0, i]里, subarray的最大sum值
- 把这个最大subarray sum 记录在array, left[] 里面
- right[] 是一样的道理
- enumerate一下元素的排列顺位, 最后 max = Math.max(max, left[i] + right[i + 1])
6. Subarray Sum.java Level: Easy Tags: [Array, Hash Table, PreSum, Subarray]
time: O(n) space: O(n)
给一串数字, 找其中的一个subarray的 [start, end] index, 条件: subarary sum == 0.
subarray sum equals k的简单版: k = 0- 求preSum, 然后不断check
map.containsKey(preSum - k). - 如果
priorSum = preSum - k == 0, 说明 [priorSum.index + 1, curr index] 就是我们要找的这一段
- 分析出,如果sum[0
a]=x, 然后sum[0b]=x, 说明sum[a+1 ~ b] == 0 - 用hashMap存每个sum[0~i]的值和index i. 如果有重复,就找到了一组sum为0的数组.
7. Subarray Sum Closest.java Level: Medium Tags: [PreSum, PriorityQueue, Sort, Subarray]
time: O(nlogn) space: O(n)
给一串数字, 找subarray的首尾index, 条件: subarray最接近0.
- Can be a 2D array, or a
class Pointto store preSum + index - Sort preSum: smaller (有可能负数) 靠前, 大数字靠后
- 比较�preSum种相连接的两个节点, 找差值min; 因为最接近的两个preSum节点的差值肯定是最小
- min所在的两个节点的index, 就是�result candidate: 这两个index可能再原nums里面相差很远
- time O(nlogn), sort
- space: O(n)
- 因为map虽然能存 preSum + index, 但是无法有效排序
- 所以用一个class来存这两个信息, 然后合理排序
8. Subarray Sum Equals K.java Level: Medium Tags: [Array, Hash Table, PreSum, Subarray]
time: O(n) space: O(n)
给一串数字, 找其中的 # of subarray的 where subararySum == k.
- Hash Table two sum 思想, but
save frequency of current preSum - map.get(priorSum) = the # of possible ways to reach k
- Keep counting
- O(n) time, O(n) space
- From the orignal presum solution:
target = preSum[j] - preSum[i - 1]. Here:k = sum - priorSum, and reversely,priorSum = sum - k - priorSum is just previously calcualted sum; track its frequency using
map<preSumValue, frequency> - map.get(priorSum): # ways to sum up to priorSum.
- Also, to get
priorSum + k = sum: each unique way of building priorSum will append later elements to reach sum (the later elemnts will sum up to k) - Therefore # ways to build
k = map.get(priorSum)
- move from starting point i = [0 ~ n -1] and define range = [i ~ j]
- use presum to verify k:
preSum[j] - preSum[i - 1] - O(n^2):
1 + 2 + 3 + 4 ... + n ~= O(n^2)
9. Maximum Size Subarray Sum Equals k.java Level: Medium Tags: [Hash Table, PreSum, Subarray]
time: O(n) space: O(n)
- use
Map<preSum value, index>to store inline preSum and its index. -
- Build presum incline
-
- Use map to cache current preSum value and its index:
Map<preSum value, index>
- Use map to cache current preSum value and its index:
-
- Each iteration: calculate possible preSum candidate that prior target sequence. ex:
(preSum - k)
- Each iteration: calculate possible preSum candidate that prior target sequence. ex:
-
- Use the calculated preSum candidate to find index
-
- Use found index to calculate for result. ex: calculate range.
10. Minimum Subarray.java Level: Easy Tags: [Array, DP, Greedy, Sequence DP, Subarray]
time: O(m) space: O(1)
给一串数组, unsorted, can have negative/positive num. 找数组中间 subarray 数字之和的最小值
- 看到 min value, 至少考虑dp:
- Consider last num: min sum will be (preMinSum + curr, or curr)
- Use preMinSum to cache previouly calcualted min sum, also compare with +curr.
- Have a global min to track: because the preMinSum can be dis-continuous.
- 也可以写成 dp[i] 但是没什么必要