741. 摘櫻桃 : 經(jīng)典線性 DP 運用題

題目描述

這是 LeetCode 上的 741. 摘櫻桃 郑叠,難度為 困難

Tag : 「線性 DP」

一個N \times N 的網(wǎng)格( grid) 代表了一塊櫻桃地油吭,每個格子由以下三種數(shù)字的一種來表示:

  • 0 表示這個格子是空的署拟,所以你可以穿過它。
  • 1 表示這個格子里裝著一個櫻桃心包,你可以摘到櫻桃然后穿過它馒铃。
  • -1 表示這個格子里有荊棘,擋著你的路娃殖。

你的任務(wù)是在遵守下列規(guī)則的情況下议谷,盡可能的摘到最多櫻桃:

  • 從位置 (0, 0) 出發(fā)卧晓,最后到達 (N-1, N-1) ,只能向下或向右走逼裆,并且只能穿越有效的格子(即只可以穿過值為 0 或者 1 的格子)胜宇;
  • 當(dāng)?shù)竭_ (N-1, N-1) 后恢着,你要繼續(xù)走财破,直到返回到 (0, 0) ,只能向上或向左走碗淌,并且只能穿越有效的格子抖锥;
  • 當(dāng)你經(jīng)過一個格子且這個格子包含一個櫻桃時,你將摘到櫻桃并且這個格子會變成空的(值變?yōu)?)纳像;
  • 如果在 (0, 0)(N-1, N-1) 之間不存在一條可經(jīng)過的路徑拯勉,則沒有任何一個櫻桃能被摘到岔帽。

示例 1:

輸入: grid =
[[0, 1, -1],
 [1, 0, -1],
 [1, 1,  1]]

輸出: 5

解釋: 
玩家從(0,0)點出發(fā)导绷,經(jīng)過了向下走,向下走贾费,向右走檐盟,向右走,到達了點(2, 2)导犹。
在這趟單程中陌宿,總共摘到了4顆櫻桃,矩陣變成了[[0,1,-1],[0,0,-1],[0,0,0]]。
接著掰烟,這名玩家向左走,向上走蝎亚,向上走发框,向左走,返回了起始點梅惯,又摘到了1顆櫻桃。
在旅程中铣减,總共摘到了5顆櫻桃,這是可以摘到的最大值了缔刹。

說明:

  • grid 是一個 N \times N 的二維數(shù)組劣针,N的取值范圍是 1 <= N <= 50
  • 每一個 grid[i][j] 都是集合 {-1, 0, 1} 其中的一個數(shù)
  • 可以保證起點 grid[0][0] 和終點 grid[N-1][N-1] 的值都不會是 -1

線性 DP

為了方便捺典,我們令 gridg,同時調(diào)整矩陣橫縱坐標(biāo)從 1 開始肝箱。

原問題為先從左上角按照「只能往下 + 只能往右」的規(guī)則走到右下角稀蟋,然后再按照「只能往上 + 只能往左」的規(guī)則走回左上角,途徑的值為 1 的格子得一分(只能得分一次骏融,得分后置零)萌狂,同時不能經(jīng)過值為 -1 的格子茫藏。

其中第二趟的規(guī)則等價于按照第一趟的規(guī)則從左上角到右下角再走一遍,再結(jié)合每個位置的只能得分一次凉当,可以將原問題等價于:兩個點從左上角開始同時走,最終都走到右下角的最大得分看杭。

定義 f[k][i1][i2] 為當(dāng)前走了 k 步(橫縱坐標(biāo)之和)楼雹,且第一個點當(dāng)前在第 i1 行,第二點在第 i2 行時的最大得分榨咐,最終答案為 f[2n][n][n]携悯,同時有 f[2][1][1] = g[0][0] 的起始狀態(tài)。

由于兩個點是同時走(都走了 k 步)龟劲,結(jié)合「只能往下 + 只能往右」的規(guī)則轴或,可直接算得第一個點所在的列為 j1 = k - i1照雁,第二點所在的列為 j2 = k - i2

不失一般性考慮 f[k][i1][i2] 該如何轉(zhuǎn)移萍诱,兩個點均有可能走行或走列污呼,即有 4 種前驅(qū)狀態(tài):f[k - 1][i1 - 1][i2]f[k - 1][i1 - 1][i2 - 1]籍凝、f[k - 1][i1][i2 - 1]f[k - 1][i1][i2],在四者中取最大值饵蒂,同時當(dāng)前位置 (i1, j1)(i2, j2) 的得分需要被累加酱讶,假設(shè)兩者得分別為 AB,若兩個位置不重疊的話得问,可以同時累加软免,否則只能累加一次。

一些細(xì)節(jié):為了防止從值為 -1 的格子進行轉(zhuǎn)移影響正確性漓骚,我們需要先將所有 f[k][i1][i2] 初始化為負(fù)無窮榛泛。

代碼:

class Solution {
    static int N = 55, INF = Integer.MIN_VALUE;
    static int[][][] f = new int[2 * N][N][N];
    public int cherryPickup(int[][] g) {
        int n = g.length;
        for (int k = 0; k <= 2 * n; k++) {
            for (int i1 = 0; i1 <= n; i1++) {
                for (int i2 = 0; i2 <= n; i2++) {
                    f[k][i1][i2] = INF;
                }
            }
        }
        f[2][1][1] = g[0][0];
        for (int k = 3; k <= 2 * n; k++) {
            for (int i1 = 1; i1 <= n; i1++) {
                for (int i2 = 1; i2 <= n; i2++) {
                    int j1 = k - i1, j2 = k - i2;
                    if (j1 <= 0 || j1 > n || j2 <= 0 || j2 > n) continue;
                    int A = g[i1 - 1][j1 - 1], B = g[i2 - 1][j2 - 1];
                    if (A == -1 || B == -1) continue;
                    int a = f[k - 1][i1 - 1][i2], b = f[k - 1][i1 - 1][i2 - 1], c = f[k - 1][i1][i2 - 1], d = f[k - 1][i1][i2];
                    int t = Math.max(Math.max(a, b), Math.max(c, d)) + A;
                    if (i1 != i2) t += B;
                    f[k][i1][i2] = t;
                }
            }
        }
        return f[2 * n][n][n] <= 0 ? 0 : f[2 * n][n][n];
    }
}
  • 時間復(fù)雜度:狀態(tài)數(shù)量級為 n^3曹锨,每個狀態(tài)轉(zhuǎn)移復(fù)雜度為 O(1)沛简。整體復(fù)雜度為 O(n^3)
  • 空間復(fù)雜度:O(n^3)

最后

這是我們「刷穿 LeetCode」系列文章的第 No.741 篇,系列開始于 2021/01/01给郊,截止于起始日 LeetCode 上共有 1916 道題目捧灰,部分是有鎖題,我們將先把所有不帶鎖的題目刷完炭庙。

在這個系列文章里面煌寇,除了講解解題思路以外,還會盡可能給出最為簡潔的代碼擦盾。如果涉及通解還會相應(yīng)的代碼模板淌哟。

為了方便各位同學(xué)能夠電腦上進行調(diào)試和提交代碼,我建立了相關(guān)的倉庫:https://github.com/SharingSource/LogicStack-LeetCode 腐碱。

在倉庫地址里,你可以看到系列文章的題解鏈接喂走、系列文章的相應(yīng)代碼谋作、LeetCode 原題鏈接和其他優(yōu)選題解。

更多更全更熱門的「筆試/面試」相關(guān)資料可訪問排版精美的 合集新基地 ????

本文由mdnice多平臺發(fā)布

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末帖池,一起剝皮案震驚了整個濱河市睡汹,隨后出現(xiàn)的幾起案子寂殉,更是在濱河造成了極大的恐慌,老刑警劉巖彤叉,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件焕檬,死亡現(xiàn)場離奇詭異实愚,居然都是意外死亡,警方通過查閱死者的電腦和手機腊敲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門碰辅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來没宾,“玉大人,你說我怎么就攤上這事循衰。” “怎么了伐蒋?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵先鱼,是天一觀的道長。 經(jīng)常有香客問我掸读,道長闹蒜,這世上最難降的妖魔是什么抑淫? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任始苇,我火速辦了婚禮,結(jié)果婚禮上函喉,老公的妹妹穿的比我還像新娘荣月。我一直安慰自己,他們只是感情好哺窄,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布萌业。 她就那樣靜靜地躺著,像睡著了一般婴程。 火紅的嫁衣襯著肌膚如雪抱婉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機與錄音侵贵,去河邊找鬼。 笑死卡睦,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的恕齐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼瞬逊,長吁一口氣:“原來是場噩夢啊……” “哼显歧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起确镊,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤士骤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蕾域,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拷肌,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年旨巷,在試婚紗的時候發(fā)現(xiàn)自己被綠了巨缘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片采呐。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡若锁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出斧吐,到底是詐尸還是另有隱情又固,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布会通,位于F島的核電站口予,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏涕侈。R本人自食惡果不足惜沪停,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望裳涛。 院中可真熱鬧木张,春花似錦、人聲如沸端三。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽郊闯。三九已至妻献,卻和暖如春蛛株,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背育拨。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工谨履, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人熬丧。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓笋粟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親析蝴。 傳聞我的和親對象是個殘疾皇子害捕,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

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