2019年vivo秋招筆試(第三題)

leetcode 546.移除盒子

給出一些不同顏色的盒子,盒子的顏色由數字表示,即不同的數字表示不同的顏色。
你將經過若干輪操作去去掉盒子,直到所有的盒子都去掉爲止。每一輪你可以移除具有相同顏色的連續 k 個盒子(k >= 1),這樣一輪之後你將得到 k*k 個積分。
當你將所有盒子都去掉之後,求你能獲得的最大積分和。

示例 1:
輸入:

[1, 3, 2, 2, 2, 3, 4, 3, 1]

輸出:

23

解釋:

[1, 3, 2, 2, 2, 3, 4, 3, 1]
----> [1, 3, 3, 4, 3, 1] (33=9 分)
----> [1, 3, 3, 3, 1] (1
1=1 分)
----> [1, 1] (33=9 分)
----> [] (2
2=4 分)

提示:盒子的總數 n 不會超過 100。

使用動態規劃做。
dp[i][j]表示在子數組[i,j]範圍內能得到的最高分數,那麼最後我們返回dp[0,n-1]就是要求的結果。

這裏使用的高分技巧是:使得在總體全局的情況下,每次移除的數字是最多的。這樣使得k*k的值是最大的。於是便存在那麼一種情況:在移除某個或者某幾個數字後,使得原本不連續的相同數字量在一起。因此我們要儘可能的使得原本分開的相同的數字,連續後一起消掉。

假如在[i,j]中間有個位置boxed[i]和boxes[m]相等,那麼我們應該考慮直接移除區間[i+1,m-1]上的數字,使得boxes[i]與boxes[m]相鄰。

那麼我們我們獲得了一部分的積分是dp[i+1][m-1],還剩下boxes[i]和boxes[m,j]區間的數字,此時我們無法處理子數組[m,j],因爲有些信息沒有包括在我們的dp數組中。

此類問題歸納爲不自己包含的子問題,其解法依賴於一些子問題以外的信息。爲了解決它,我們需要修改問題的定義。

無法處理boxes[m,j]區間是因爲缺少了關鍵信息,我們不知道boxes[m]左邊相同數字的個數k,只有知道這個信息,那麼m的位置纔有意義。所以dp數組應該是一個三維數組dp[i][j][k],表示區間[i,j]中能獲得的最大積分,但boxes[i]左邊有k個數字其相等,那麼我們的目標就是要求dp[0][n-1][0],dp[i][j][k]=(1+k)*(1+k)

對於dp[i][j][k],如果移除了boxes[i],那麼我們獲得(1+k)*(1+k)+dp[i+1][j][0]。對於上面的情況,假如在[i,j]中間有個位置m,boxes[i]==boxes[m],我們也應該先考慮移除[i+1,m-1]這部分,我們得到積分dp[i+1][m-1][0],然後再處理剩下部分,得到積分dp[m][j][k+1],k+1的原因是,了中間的部分後,原本和boxes[m]不相鄰的boxes[i]現在相鄰了,又因爲二者值相同,所以k應該加1。

class Solution {
public:
    int removeBoxes(vector<int>& boxes) {
        int n = boxes.size();
        int dp[100][100][100] = {0};
        return helper(boxes, 0, n - 1, 0, dp);
    }
    int helper(vector<int>& boxes, int i, int j, int k, int dp[100][100][100]) {
        if (j < i) return 0;
        if (dp[i][j][k] > 0) return dp[i][j][k];
        int res = (1 + k) * (1 + k) + helper(boxes, i + 1, j, 0, dp);
        for (int m = i + 1; m <= j; ++m) {
            if (boxes[m] == boxes[i]) {
                res = max(res, helper(boxes, i + 1, m - 1, 0, dp) + helper(boxes, m, j, k + 1, dp));
            }
        }
        return dp[i][j][k] = res;
    }
};

參考:
https://blog.csdn.net/STILLxjy/article/details/85106608

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章