【LeetCode】LeetCode之乘积最大子数组——枚举+动态规划+Kadane算法
🔏1.題目描述
給你一個整數數組 nums ,請你找出數組中乘積最大的連續子數組(該子數組中至少包含一個數字),并返回該子數組所對應的乘積。
📜示例 1:
輸入: [2,3,-2,4]
輸出: 6
解釋: 子數組 [2,3] 有最大乘積 6。
📜示例 2:
輸入: [-2,0,-1]
輸出: 0
解釋: 結果不能為 2, 因為 [-2,-1] 不是子數組。
🍀2.暴力解法
該題最簡單的無非就是暴力解法,通過兩次for循環枚舉出所有子數組,然后維護一個最大值即可。
/*** 暴力解法* 時間復雜度:O(n^2)* 空間復雜度:O(1)*/public int maxProduct(int[] nums) {int maxProduct = nums[0];int size = nums.length;int curProduct = 1;for (int i = 0; i < size; i++) {for (int j = i; j < size; j++) {curProduct = curProduct * nums[j];maxProduct = Math.max(curProduct, maxProduct);}curProduct = 1;}return maxProduct;}復雜度分析
時間復雜度:O(n^2)
空間復雜度:O(n)
提交到LeetCode擦邊界通過了,本以為時間復雜度O(n^2)一般來說很難通過。
🍀3.動態規劃
動態規劃核心三要素:
- 階段:分解子問題,子問題與原問題求解過程相同
- 狀態:每個階段都有一個或多個狀態
- 決策:根據當前的決策,確定下一階段的狀態
那么怎么分析該問題呢?如果讓你求f(n),你覺得這個f(n)是怎么從推導過來的?
因為該題存在負負得正的情況,所以這種情況也要考慮;試想如果要求f(n)的乘積最大,是不是分為如下三種情況:
- 如果當前元素a為正數,那么如果要求f(n)最大,是不是只要確保f(n-1)最大即可
如果當前元素a為負數,那么如果要求f(n)最大,是不是只要保證f(n-1)最小即可,【(-3 * -10 = 30) ( -3 * -100 = 300)
第三種可能就是正負不一致,那最大值就是a
所以它的遞推關系式就是
Fmax(i) = max{Fmax(i-1)*a,Fmin(i-1)*a, a}
Fmin(i) = max{Fmax(i-1)*a, Fmin(i - 1)*a, a}
所以需要兩個dp數組進行維護。
/*** 動態規劃* 時間復雜度:O(n)* 空間復雜度:O(n)*/public int maxProduct2(int[] nums) {int size = nums.length;int[] maxDP = new int[nums.length];int[] minDP = new int[nums.length];int mp = nums[0];maxDP[0] = minDP[0] = mp;for (int i = 1; i < size; i++) {maxDP[i] = Math.max(Math.max(maxDP[i - 1] * nums[i], minDP[i - 1] * nums[i]), nums[i]);minDP[i] = Math.min(Math.min(maxDP[i - 1] * nums[i], minDP[i - 1] * nums[i]), nums[i]);mp = Math.max(mp, maxDP[i]);}return mp;}復雜度分析:
- 時間復雜度:O(n)
- 空間復雜度:O(n)
提交到LeetCode
那么有沒有什么辦法將空間優化到O(1)呢?
🍀3.Kadane算法
其實本質上Kadane算法還是使用的是動態規劃思想,說白了它就是將動態規劃的空間復雜度優化到了O(1),本質上就是動態規劃。
上述動態規劃是使用兩個dp數組作為記憶集的,我們會發現每次求解出的當前狀態的結果只會被下次使用一次。所以可以通過變量每次保存當前階段的結果,然后當求解出下一階段的結果時,會使用該變量一次,最后計算出了下一階段得結果,最后賦值給我當前變量即可。循環使用!
/*** Kadane算法【動態規劃優化空間】* 時間復雜度:O(n)* 空間復雜度:O(1)*/public int maxProduct3(int[] nums) {int size = nums.length;int mp = nums[0];int curMax1, curMin1;curMax1 = curMin1 = mp;for (int i = 1; i < size; i++) {int cur = curMax1;curMax1 = Math.max(Math.max(curMax1 * nums[i], curMin1 * nums[i]), nums[i]);curMin1 = Math.min(Math.min(cur * nums[i], curMin1 * nums[i]), nums[i]);mp = Math.max(mp, curMax1);}return mp;}復雜度分析:
- 時間復雜度:O(n)
- 空間復雜度:O(1)
總結
以上是生活随笔為你收集整理的【LeetCode】LeetCode之乘积最大子数组——枚举+动态规划+Kadane算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【LeetCode】LeetCode之跳
- 下一篇: 【LeetCode】LeetCode之乘