【LeetCode】LeetCode之乘积为正数的最长子数组长度——暴力枚举+动态规划+Kadane算法
🔐1.題目描述
給你一個整數數組 nums ,請你求出乘積為正數的最長子數組的長度。
一個數組的子數組是由原數組中零個或者更多個連續數字組成的數組。
請你返回乘積為正數的最長子數組長度。
?示例 1:
輸入:nums = [1,-2,-3,4]
輸出:4
解釋:數組本身乘積就是正數,值為 24 。
?示例 2:
輸入:nums = [0,1,-2,-3,-4]
輸出:3
解釋:最長乘積為正數的子數組為 [1,-2,-3] ,乘積為 6 。
注意,我們不能把 0 也包括到子數組中,因為這樣乘積為 0 ,不是正數。
?示例 3:
輸入:nums = [-1,-2,-3,0,1]
輸出:2
解釋:乘積為正數的最長子數組是 [-1,-2] 或者 [-2,-3] 。
?示例 4:
輸入:nums = [-1,2]
輸出:1
?示例 5:
輸入:nums = [1,2,3,5,-6,4,0,10]
輸出:4
💎提示:
1 <= nums.length <= 10^5
-10^9 <= nums[i] <= 10^9
2.枚舉
通過兩層for循環,暴力枚舉出所有得子數組,然后進行判斷即可得到結果;
/*** 枚舉*/public int getMaxLen(int[] nums) {int size = nums.length;int ml = 0; //最大乘積為正數的最長子數組長度int curl = 0; //當前乘積為正數的最長子數組長度long curV = 1; //保存每次乘積之后的數【如果是正數我們直接設置為1,負數為-1,因為數的大小和本體無關,我們只管正負】for (int i = 0; i < size; i++) {for (int j = i; j < size; j++) {curV *= nums[j]; curl++; //將當前子數組長度++if (curV > 0) {curV = 1;//置為1是因為連續乘積數會很大,會超出long范圍,所以正數結果置為1即可ml = Math.max(curl, ml);//將當前最長長度與最長長度比較} else if (curV == 0) {break; //如果乘積為0,說明當前nums[i]==0,所以需要跳過,因為0不是正數也不是負數} else {curV = -1;//如果curV <0 ,乘積置為-1即可,防止乘積數太大}}curl = 0; //每遍歷一層,就要重置curl和curVcurV = 1;}return ml;}提交到LeetCode發現超時了,這應該也正常吧,畢竟是暴力解法
復雜度分析
- 時間復雜度:O(n^2)
- 空間復雜度:O(1)
3.動態規劃
動態規劃核心三要素:
🍀階段:分解子問題,子問題與原問題求解過程相同
🍀狀態:每個階段都有一個或多個狀態
🍀決策:根據當前的決策,確定下一階段的狀態
那么怎么分析該問題呢?怎么確定狀態呢?
由于本題存在負負得正得情況,所以需要使用兩個dp數組保存當前狀態,一個是positive(正數)數組,一個是negative(負數)數組;【因為負數乘以負數有可能得到一個更大的值呀】
試想如果要求f(n)的最長子數組長度,是不是分為如下三種情況:
(1) 當nums[i] > 0時
- positive[i] = positive[i - 1] + 1
- negative[i] = negative[i - 1] == 0 ? 0 : negative[i - 1] + 1
只所以要考慮negative[i - 1]==0的情況,是因為我們需要求最長子數組乘積為負數的長度,而negative[i - 1]一旦為0,又由于當前nums[i]為正數,所以不可能形成負數的情況。
(2) 當nums[i] == 0時
- positive[i] = negative[i] = 0
(3)當nums[i] < 0時
- positive[i] negative[i] == 0 ? 0 : positive[i] + 1
- negative[i] = positive[i] + 1
提交到LeetCode自然能通過!
復雜度分析:
- 時間復雜度:O(n)
- 空間復雜度:O(n)
能不能將空間復雜度優化到O(1)呢?
3.Kadane算法
其實本質上Kadane算法還是使用的是動態規劃思想,說白了它就是將動態規劃的空間復雜度優化到了O(1),本質上就是動態規劃。
上述動態規劃是使用兩個dp數組作為記憶集的,我們會發現每次求解出的當前狀態的結果只會被下次使用一次。所以可以通過變量每次保存當前階段的結果,然后當求解出下一階段的結果時,會使用該變量一次,最后計算出了下一階段得結果,最后賦值給我當前變量即可。循環使用!
public int getMaxLen4(int[] nums) {int size = nums.length;int pos = nums[0] > 0 ? 1 : 0;int neg = nums[0] < 0 ? 1 : 0;int ml = pos;for (int i = 1; i < size; i++) {if (nums[i] > 0) {pos = pos + 1;neg = neg == 0 ? 0 : neg + 1;} else if (nums[i] == 0) {pos = neg = 0;} else {int temp = pos;pos = neg == 0 ? 0 : neg + 1;neg = temp + 1;}ml = Math.max(ml, pos);}return ml;}復雜度分析:
- 時間復雜度:O(n)
- 空間復雜度:O(1)
總結
以上是生活随笔為你收集整理的【LeetCode】LeetCode之乘积为正数的最长子数组长度——暴力枚举+动态规划+Kadane算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【LeetCode】LeetCode之乘
- 下一篇: 有关使用junit依赖出现@Before