最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++實現(xiàn)LeetCode(152.求最大子數(shù)組乘積)

 更新時間:2021年07月29日 14:55:48   作者:Grandyang  
這篇文章主要介紹了C++實現(xiàn)LeetCode(152.求最大子數(shù)組乘積),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下

[LeetCode] 152. Maximum Product Subarray 求最大子數(shù)組乘積

Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product.

Example 1:

Input: [2,3,-2,4]
Output: 6
Explanation: [2,3] has the largest product 6.

Example 2:

Input: [-2,0,-1]
Output: 0
Explanation: The result cannot be 2, because [-2,-1] is not a subarray.

這個求最大子數(shù)組乘積問題是由最大子數(shù)組之和 Maximum Subarray 演變而來,但是卻比求最大子數(shù)組之和要復(fù)雜,因為在求和的時候,遇到0,不會改變最大值,遇到負數(shù),也只是會減小最大值而已。而在求最大子數(shù)組乘積的問題中,遇到0會使整個乘積為0,而遇到負數(shù),則會使最大乘積變成最小乘積,正因為有負數(shù)和0的存在,使問題變得復(fù)雜了不少。比如,現(xiàn)在有一個數(shù)組 [2, 3, -2, 4],可以很容易的找出所有的連續(xù)子數(shù)組,[2],[3],[-2],[4],[2, 3],[3, -2],[-2, 4],[2, 3, -2],[3, -2, 4],[2, 3, -2, 4],然后可以很輕松的算出最大的子數(shù)組乘積為6,來自子數(shù)組 [2, 3]。但如何寫代碼來實現(xiàn)自動找出最大子數(shù)組乘積呢,博主最先想到的方比較簡單粗暴,就是找出所有的子數(shù)組,然后算出每一個子數(shù)組的乘積,然后比較找出最大的一個,需要兩個 for 循環(huán),第一個 for 遍歷整個數(shù)組,第二個 for 遍歷含有當前數(shù)字的子數(shù)組,就是按以下順序找出子數(shù)組: [2],[2, 3],[2, 3, -2],[2, 3, -2, 4],[3],[3, -2],[3, -2, 4],[-2],[-2, 4],[4],在本地測試的一些數(shù)組全部通過,于是興高采烈的拿到 OJ 上測試,結(jié)果喪心病狂的 OJ 用一個有 15000 個數(shù)字的數(shù)組來測試,然后說程序的運行時間超過了要求值,一看代碼,果然如此,時間復(fù)雜度 O(n2), 得想辦法只用一次循環(huán)搞定。想來想去想不出好方法,于是到網(wǎng)上搜各位大神的解決方法。其實這道題最直接的方法就是用 DP 來做,而且要用兩個 dp 數(shù)組,其中 f[i] 表示子數(shù)組 [0, i] 范圍內(nèi)并且一定包含 nums[i] 數(shù)字的最大子數(shù)組乘積,g[i] 表示子數(shù)組 [0, i] 范圍內(nèi)并且一定包含 nums[i] 數(shù)字的最小子數(shù)組乘積,初始化時 f[0] 和 g[0] 都初始化為 nums[0],其余都初始化為0。那么從數(shù)組的第二個數(shù)字開始遍歷,那么此時的最大值和最小值只會在這三個數(shù)字之間產(chǎn)生,即 f[i-1]*nums[i],g[i-1]*nums[i],和 nums[i]。所以用三者中的最大值來更新 f[i],用最小值來更新 g[i],然后用 f[i] 來更新結(jié)果 res 即可,由于最終的結(jié)果不一定會包括 nums[n-1] 這個數(shù)字,所以 f[n-1] 不一定是最終解,不斷更新的結(jié)果 res 才是,參見代碼如下:

解法一:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int res = nums[0], n = nums.size();
        vector<int> f(n, 0), g(n, 0);
        f[0] = nums[0];
        g[0] = nums[0];
        for (int i = 1; i < n; ++i) {
            f[i] = max(max(f[i - 1] * nums[i], g[i - 1] * nums[i]), nums[i]);
            g[i] = min(min(f[i - 1] * nums[i], g[i - 1] * nums[i]), nums[i]);
            res = max(res, f[i]);
        }
        return res;
    }
};

我們可以對上面的解法進行空間上的優(yōu)化,以下摘自 OJ 官方解答,大體思路相同,寫法更加簡潔:

Besides keeping track of the largest product, we also need to keep track of the smallest product. Why? The smallest product, which is the largest in the negative sense could become the maximum when being multiplied by a negative number.

Let us denote that:

f(k) = Largest product subarray, from index 0 up to k.

Similarly,

g(k) = Smallest product subarray, from index 0 up to k.

Then,

f(k) = max( f(k-1) * A[k], A[k], g(k-1) * A[k] )
g(k)
= min( g(k-1) * A[k], A[k], f(k-1) * A[k] )

There we have a dynamic programming formula. Using two arrays of size n, we could deduce the final answer as f(n-1). Since we only need to access its previous elements at each step, two variables are sufficient.

public int maxProduct(int[] A) {
   assert A.length > 0;
   int max = A[0], min = A[0], maxAns = A[0];
   for (int i = 1; i < A.length; i++) {
      int mx = max, mn = min;
      max = Math.max(Math.max(A[i], mx * A[i]), mn * A[i]);
      min = Math.min(Math.min(A[i], mx * A[i]), mn * A[i]);
      maxAns = Math.max(max, maxAns);
   }
   return maxAns;
}

根據(jù)上述描述可以寫出代碼如下:

解法二:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        if (nums.empty()) return 0;
        int res = nums[0], mn = nums[0], mx = nums[0];
        for (int i = 1; i < nums.size(); ++i) {
            int tmax = mx, tmin = mn;
            mx = max(max(nums[i], tmax * nums[i]), tmin * nums[i]);
            mn = min(min(nums[i], tmax * nums[i]), tmin * nums[i]);
            res = max(res, mx);
        }
        return res;
    }
};

下面這種方法也是用兩個變量來表示當前最大值和最小值的,但是沒有無腦比較三個數(shù),而是對于當前的 nums[i] 值進行了正負情況的討論:

1. 當遍歷到一個正數(shù)時,此時的最大值等于之前的最大值乘以這個正數(shù)和當前正數(shù)中的較大值,此時的最小值等于之前的最小值乘以這個正數(shù)和當前正數(shù)中的較小值。

2. 當遍歷到一個負數(shù)時,先用一個變量t保存之前的最大值 mx,然后此時的最大值等于之前最小值乘以這個負數(shù)和當前負數(shù)中的較大值,此時的最小值等于之前保存的最大值t乘以這個負數(shù)和當前負數(shù)中的較小值。

3. 在每遍歷完一個數(shù)時,都要更新最終的最大值。

P.S. 如果這里改成求最小值的話,就是求最小子數(shù)組乘積,并且時間復(fù)雜度是醉人的 O(n),是不是很強大呢,參見代碼如下:

解法三:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int res = nums[0], mx = res, mn = res;
        for (int i = 1; i < nums.size(); ++i) {
            if (nums[i] > 0) {
                mx = max(mx * nums[i], nums[i]);
                mn = min(mn * nums[i], nums[i]);
            } else {
                int t = mx;
                mx = max(mn * nums[i], nums[i]);
                mn = min(t * nums[i], nums[i]);
            }
            res = max(res, mx);
        }
        return res;
    }
};

下面這道題使用了一個 trick 來將上面解法的分情況討論合成了一種,在上面的解法中分析了當 nums[i] 為正數(shù)時,最大值和最小值的更新情況,為負數(shù)時,稍有不同的就是最小值更新時要用到之前的最大值,而不是更新后的最大值,所以才要用變量t來保存之前的結(jié)果。而下面這種方法的巧妙處在于先判斷一個當前數(shù)字是否是負數(shù),是的話就交換最大值和最小值。那么此時的 mx 就是之前的 mn,所以 mx 的更新還是跟上面的方法是統(tǒng)一的,而在在更新 mn 的時候,之前的 mx 已經(jīng)保存到 mn 中了,而且并沒有改變,所以可以直接拿來用,不得不說,確實叼啊,參見代碼如下:

解法四:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int res = nums[0], mx = res, mn = res;
        for (int i = 1; i < nums.size(); ++i) {
            if (nums[i] < 0) swap(mx, mn);
            mx = max(nums[i], mx * nums[i]);
            mn = min(nums[i], mn * nums[i]);
            res = max(res, mx);
        }
        return res;
    }
};

再來看一種畫風不太一樣的解法,這種解法遍歷了兩次,一次是正向遍歷,一次是反向遍歷,相當于正向建立一個累加積數(shù)組,每次用出現(xiàn)的最大值更新結(jié)果 res,然后再反響建立一個累加積數(shù)組,再用出現(xiàn)的最大值更新結(jié)果 res,注意當遇到0的時候,prod 要重置為1。至于為啥正反兩次遍歷就可以得到正確的結(jié)果了呢?主要還是由于負數(shù)個數(shù)的關(guān)系,因為負數(shù)可能會把最大值和最小值翻轉(zhuǎn),那么當有奇數(shù)個負數(shù)時,如果只是正向遍歷的話,可能會出錯,比如 [-1, -2, -3],累加積會得到 -1,2,-6,看起來最大值只能為2,其實不對,而如果我們再反向來一遍,累加積為 -3,6,-6,就可以得到6了。所以當負數(shù)個數(shù)為奇數(shù)時,首次出現(xiàn)和末尾出現(xiàn)的負數(shù)就很重要,有可能會是最大積的組成數(shù)字,所以遍歷兩次就不會漏掉組成最大值的機會,參見代碼如下:

解法五:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int res = nums[0], prod = 1, n = nums.size();
        for (int i = 0; i < n; ++i) {
            res = max(res, prod *= nums[i]);
            if (nums[i] == 0) prod = 1;
        }
        prod = 1;
        for (int i = n - 1; i >= 0; --i) {
            res = max(res, prod *= nums[i]);
            if (nums[i] == 0) prod = 1;
        }
        return res;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/152

類似題目:

Maximum Subarray

House Robber

Product of Array Except Self

Maximum Product of Three Numbers

Subarray Product Less Than K

參考資料:

https://leetcode.com/problems/maximum-product-subarray/

https://leetcode.com/problems/maximum-product-subarray/discuss/48302/2-passes-scan-beats-99

https://leetcode.com/problems/maximum-product-subarray/discuss/48261/share-my-dp-code-that-got-ac

https://leetcode.com/problems/maximum-product-subarray/discuss/48252/sharing-my-solution-o1-space-on-running-time

https://leetcode.com/problems/maximum-product-subarray/discuss/48230/possibly-simplest-solution-with-on-time-complexity

https://leetcode.com/problems/maximum-product-subarray/discuss/48389/my-concise-dp-on-java-solution-with-o1-extra-space

到此這篇關(guān)于C++實現(xiàn)LeetCode(152.求最大子數(shù)組乘積)的文章就介紹到這了,更多相關(guān)C++實現(xiàn)求最大子數(shù)組乘積內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++ std:map的使用方法

    C++ std:map的使用方法

    std::map是C++標準庫中一個強大而高效的關(guān)聯(lián)容器,本文就來介紹一下C++ std:map的使用方法,具有一定的參考價值,感興趣的可以了解一下
    2025-02-02
  • C語言楊輝三角兩種實現(xiàn)方法

    C語言楊輝三角兩種實現(xiàn)方法

    大家好,本篇文章主要講的是C語言楊輝三角兩種實現(xiàn)方法,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • C++獲取zip文件列表方法

    C++獲取zip文件列表方法

    本文將介紹獲取zip文件列表的方法,有些新手的朋友可以參考下
    2012-12-12
  • C語言分治法實現(xiàn)歸并排序

    C語言分治法實現(xiàn)歸并排序

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)歸并排序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • 詳解C++編程中的文件流與字符串流

    詳解C++編程中的文件流與字符串流

    這篇文章主要介紹了C++編程中的文件流與字符串流,是C++入門學習中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-09-09
  • c語言處理函數(shù)調(diào)用的方法

    c語言處理函數(shù)調(diào)用的方法

    函數(shù)就是一段封裝好的,可以重復(fù)使用的代碼,它使得我們的程序更加模塊化,不需要編寫大量重復(fù)的代碼。這篇文章主要介紹了c語言是如何處理函數(shù)調(diào)用的?需要的朋友可以參考下
    2021-11-11
  • C語言二維數(shù)組應(yīng)用之掃雷游戲

    C語言二維數(shù)組應(yīng)用之掃雷游戲

    這篇文章主要為大家詳細介紹了C語言二維數(shù)組應(yīng)用之掃雷游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • C語言簡單實現(xiàn)掃雷小游戲

    C語言簡單實現(xiàn)掃雷小游戲

    這篇文章主要為大家詳細介紹了C語言簡單實現(xiàn)掃雷小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-09-09
  • C++實現(xiàn)LeetCode(172.求階乘末尾零的個數(shù))

    C++實現(xiàn)LeetCode(172.求階乘末尾零的個數(shù))

    這篇文章主要介紹了C++實現(xiàn)LeetCode(172.求階乘末尾零的個數(shù)),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • C++實現(xiàn)圖像目標區(qū)裁剪ImageCropping

    C++實現(xiàn)圖像目標區(qū)裁剪ImageCropping

    本文主要介紹了C++實現(xiàn)圖像目標區(qū)裁剪ImageCropping,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-06-06

最新評論

师宗县| 石嘴山市| 海原县| 同德县| 宜章县| 仙游县| 秦皇岛市| 沂水县| 呈贡县| 木里| 嵊泗县| 固始县| 土默特右旗| 双城市| 六枝特区| 石嘴山市| 曲水县| 荆州市| 桂平市| 彩票| 襄城县| 香河县| 清新县| 荥经县| 永福县| 香格里拉县| 云林县| 通江县| 资中县| 琼结县| 鹿邑县| 尼木县| 金山区| 义乌市| 个旧市| 南郑县| 朝阳区| 青海省| 屯留县| 临城县| 玉溪市|