152. 乘積最大子序列

[TOC]

一猿推、題目描述

給定一個(gè)整數(shù)數(shù)組 nums ,找出一個(gè)序列中乘積最大的連續(xù)子序列(該序列至少包含一個(gè)數(shù))。

示例 1:

輸入: [2,3,-2,4]
輸出: 6
解釋: 子數(shù)組 [2,3] 有最大乘積 6。

示例 2:

輸入: [-2,0,-1]
輸出: 0
解釋: 結(jié)果不能為 2, 因?yàn)?[-2,-1] 不是子數(shù)組。

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/maximum-product-subarray
著作權(quán)歸領(lǐng)扣網(wǎng)絡(luò)所有欺旧。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系官方授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處蛤签。

二辞友、解題方法

1. 暴力法(超時(shí))


思路:

暴力出奇跡,這是我這種弟弟總是第一時(shí)間想到的東西震肮。既然你要乘積最大的連續(xù)子序列称龙,我將所有的乘積保存下來,再取最大的豈不簡(jiǎn)單粗暴戳晌?
只要令dp[i][j]表示從nums[i]nums[j]的乘積即可鲫尊,則顯然:
\begin{equation} dp[i][j]= \begin{cases} nums[j], & i = j \\ dp[i][j-1] \times nums[j], & i < j \end{cases} \end{equation}
當(dāng)然,不用問的沦偎,暴力怎么可能會(huì)出得了奇跡疫向?

時(shí)間復(fù)雜度:O(n^2)咳蔚,空間復(fù)雜度:O(n^2)


代碼:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        if (nums.empty())   return 0;

        auto ans = nums[0];
        vector<vector<int>> dp(nums.size(), vector<int>(nums.size(), 0));
        for (auto i = 0; i < nums.size(); ++i) {
            dp[i][i] = nums[i];
            ans = max(ans, nums[i]);
        }
        for (auto diff = 1; diff < nums.size(); ++diff) {
            for (auto i = 0; i + diff < nums.size(); ++i) {
                dp[i][i + diff] = dp[i][i + diff - 1] * nums[i + diff];
                ans = max(ans, dp[i][i + diff]);
            }
        }
        return ans;
    }
};

2. 數(shù)學(xué)搔驼?谈火??


思路:

既然暴力法沒轍了舌涨,那我們就稍微分析一下問題吧糯耍。

題目說,這是一個(gè)整數(shù)數(shù)組囊嘉。
相信能做這道題目的人谍肤,一定能理解因?yàn)槭沁B乘,所以在不考慮0的情況下一定是越多的整數(shù)相乘哗伯,得到的結(jié)果的絕對(duì)值越大,最后無非是正負(fù)的問題篷角。
同樣焊刹,負(fù)負(fù)得正,所以如果是偶數(shù)個(gè)負(fù)數(shù)的情況恳蹲,我們只要一股腦全乘起來就好了虐块,一定是最大的。而如果是奇數(shù)個(gè)負(fù)數(shù)的情況嘉蕾,要么放棄第一個(gè)負(fù)數(shù)贺奠,要么放棄最后一個(gè)負(fù)數(shù),取二者中能得到的最大乘積错忱。
如果要考慮0儡率,由于會(huì)將乘積變?yōu)?img class="math-inline" src="https://math.jianshu.com/math?formula=0" alt="0" mathimg="1">,我們可以利用0將數(shù)組進(jìn)行分割以清,在每一個(gè)子數(shù)組中儿普,利用上述結(jié)論即可。

時(shí)間復(fù)雜度:O(n)掷倔,空間復(fù)雜度:O(1)


代碼:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        if (nums.empty())   return 0;
        
        auto ans = nums[0], product = 1;
        // 從左往右掃描眉孩,等價(jià)于奇數(shù)情況放棄最右邊負(fù)數(shù)
        for (auto i = 0; i < nums.size(); ++i) {
            product *= nums[i];
            ans = ans > product ? ans : product;
            product = product == 0 ? 1 : product;
        }
        product = 1;
        // 從右往左掃描,等價(jià)于奇數(shù)情況放棄最左邊負(fù)數(shù)
        for (auto i = int(nums.size()) - 1; i > -1; --i) {
            product *= nums[i];
            ans = ans > product ? ans : product;
            product = product == 0 ? 1 : product;
        }
        return ans;
    }
};

3. 動(dòng)態(tài)規(guī)劃


思路:

這次是真動(dòng)態(tài)規(guī)劃勒葱,不是解法1那個(gè)假洋鬼子浪汪。

還記得最大子序和這一題嗎?它有動(dòng)態(tài)規(guī)劃的O(n)解凛虽。這一題跟它好像很類似死遭?只不過一個(gè)求和一個(gè)求積,或許我們可以采取類似的方法來解這一題涩维?

假如類比過來殃姓,我們采用dp[i]表示到nums[i]為止的乘積最大值袁波,我們并不能像求和一樣令:
dp[i]=max(dp[i-1] + nums[i],\ nums[i])
因?yàn)槌朔ù嬖谪?fù)負(fù)得正的情況,哪怕當(dāng)前是負(fù)數(shù)蜗侈,指不準(zhǔn)下面掃描到一個(gè)負(fù)數(shù)立馬就變成了正的最大值了呢篷牌?所以我們必須要能保存已經(jīng)出現(xiàn)的最小值的情況,同時(shí)踏幻,因?yàn)樽畲笾岛妥钚≈悼赡軙?huì)互換枷颊,我們還需要保存已經(jīng)出現(xiàn)的最大值的情況。
pos[i]该面、neg[i]分別表示掃描到nums[i]為止的最大值和最小值夭苗,則我們有:
\begin{equation} pos[i]= \begin{cases} max(pos[i-1] \times nums[i], \ nums[i]), & nums[i] \geq 0 \\ max(neg[i-1] \times nums[i], \ nums[i]), & nums[i] < 0 \end{cases} \end{equation}
\begin{equation} neg[i]= \begin{cases} min(neg[i-1] \times nums[i], \ nums[i]), & nums[i] \geq 0 \\ min(pos[i-1] \times nums[i], \ nums[i]), & nums[i] < 0 \end{cases} \end{equation}
這里的maxmin可以用來處理掉0的情況,否則一旦出現(xiàn)0就全完了隔缀。

看得出來题造,由于我們只需要使用到pos[i-1]neg[i-1],所以我們可以將狀態(tài)壓縮到posneg兩個(gè)變量猾瘸,來節(jié)約開辟數(shù)組的內(nèi)存界赔。

時(shí)間復(fù)雜度:O(n),空間復(fù)雜度:O(1)


代碼:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        if (nums.empty())
            return 0;

        auto ans = numeric_limits<int>::min();
        auto pos = 1, neg = 1;
        for (auto &num : nums) {
            if (num < 0)    swap(pos, neg);
            pos = max(pos * num, num);
            neg = min(neg * num, num);
            ans = max(pos, ans);
        }
        return ans;
    }
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末牵触,一起剝皮案震驚了整個(gè)濱河市淮悼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌揽思,老刑警劉巖袜腥,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異钉汗,居然都是意外死亡羹令,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門儡湾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來特恬,“玉大人,你說我怎么就攤上這事徐钠“┕簦” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵尝丐,是天一觀的道長(zhǎng)显拜。 經(jīng)常有香客問我,道長(zhǎng)爹袁,這世上最難降的妖魔是什么远荠? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮失息,結(jié)果婚禮上譬淳,老公的妹妹穿的比我還像新娘档址。我一直安慰自己,他們只是感情好邻梆,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布守伸。 她就那樣靜靜地躺著,像睡著了一般浦妄。 火紅的嫁衣襯著肌膚如雪尼摹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天剂娄,我揣著相機(jī)與錄音蠢涝,去河邊找鬼。 笑死阅懦,一個(gè)胖子當(dāng)著我的面吹牛和二,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播耳胎,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼儿咱,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了场晶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤怠缸,失蹤者是張志新(化名)和其女友劉穎诗轻,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體揭北,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扳炬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了搔体。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恨樟。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖疚俱,靈堂內(nèi)的尸體忽然破棺而出劝术,到底是詐尸還是另有隱情,我是刑警寧澤呆奕,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布养晋,位于F島的核電站,受9級(jí)特大地震影響梁钾,放射性物質(zhì)發(fā)生泄漏绳泉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一姆泻、第九天 我趴在偏房一處隱蔽的房頂上張望零酪。 院中可真熱鬧冒嫡,春花似錦、人聲如沸四苇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛔琅。三九已至胎许,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間罗售,已是汗流浹背辜窑。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寨躁,地道東北人穆碎。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像职恳,于是被迫代替她去往敵國(guó)和親所禀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 題目鏈接難度: 中等 類型:動(dòng)態(tài)規(guī)劃 給定一個(gè)整數(shù)數(shù)組 nums 放钦,找出一個(gè)序列中乘積最大的連續(xù)...
    wzNote閱讀 10,384評(píng)論 0 3
  • 本題考察的是動(dòng)態(tài)規(guī)劃 題目描述 給定一個(gè)整數(shù)數(shù)組 nums 色徘,找出一個(gè)序列中乘積最大的連續(xù)子序列(該序列至少包含一...
    小怪獸大作戰(zhàn)閱讀 629評(píng)論 0 1
  • 題目描述 給定一個(gè)整數(shù)數(shù)組 nums ,找出一個(gè)序列中乘積最大的連續(xù)子序列(該序列至少包含一個(gè)數(shù))操禀。 示例 1: ...
    zhipingChen閱讀 253評(píng)論 0 1
  • 152. 乘積最大子序列 乘積最大子序列給定一個(gè)整數(shù)數(shù)組 nums 褂策,找出一個(gè)序列中乘積最大的連續(xù)子序列(該序列至...
    leacoder閱讀 347評(píng)論 0 1
  • 描述:給定一個(gè)整數(shù)數(shù)組 nums ,找出一個(gè)序列中乘積最大的連續(xù)子序列(該序列至少包含一個(gè)數(shù))颓屑。 示例 1: 輸入...
    小北覓閱讀 916評(píng)論 0 1