91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++中怎么利用LeetCode求最大子數組乘積

發布時間:2021-07-29 17:46:06 來源:億速云 閱讀:233 作者:Leah 欄目:開發技術

這期內容當中小編將會給大家帶來有關C++中怎么利用LeetCode求最大子數組乘積,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

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

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.

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

我們可以對上面的解法進行空間上的優化,以下摘自 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;
}

根據上述描述可以寫出代碼如下:

解法二:

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;
    }
};

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

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

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

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

P.S. 如果這里改成求最小值的話,就是求最小子數組乘積,并且時間復雜度是醉人的 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] 為正數時,最大值和最小值的更新情況,為負數時,稍有不同的就是最小值更新時要用到之前的最大值,而不是更新后的最大值,所以才要用變量t來保存之前的結果。而下面這種方法的巧妙處在于先判斷一個當前數字是否是負數,是的話就交換最大值和最小值。那么此時的 mx 就是之前的 mn,所以 mx 的更新還是跟上面的方法是統一的,而在在更新 mn 的時候,之前的 mx 已經保存到 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;
    }
};

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

解法五:

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;
    }
};

上述就是小編為大家分享的C++中怎么利用LeetCode求最大子數組乘積了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

齐齐哈尔市| 安宁市| 襄垣县| 莆田市| 荣成市| 宜丰县| 枣阳市| 林州市| 分宜县| 垫江县| 上犹县| 闵行区| 苍山县| 扎赉特旗| 浪卡子县| 新竹县| 霞浦县| 肥西县| 龙口市| 东至县| 大洼县| 镶黄旗| 景泰县| 西峡县| 郴州市| 嘉善县| 府谷县| 叙永县| 右玉县| 南岸区| 大化| 巴中市| 繁峙县| 古浪县| 永泰县| 馆陶县| 禹城市| 越西县| 唐海县| 莎车县| 霸州市|