力扣動態規劃 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] (3*3=9 分) 
----> [1, 3, 3, 3, 1] (1*1=1 分) 
----> [1, 1] (3*3=9 分) 
----> [] (2*2=4 分)
 

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

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/remove-boxes

方法 1:暴力方法【超時】
算法

暴力方法是顯然的,我們試圖移除每一個可能的元素,並計算得分以及剩下的序列繼續遞歸。

最後,dpdp 的更新式爲:\text{dp[l][r][k]} = max(\text{dp[l][r][k]}, \text{dp[l][i][k+1]} + \text{dp[i+1][r-1][0]})dp[l][r][k]=max(dp[l][r][k],dp[l][i][k+1]+dp[i+1][r-1][0])。

最後,dp[0][n-1][0] 就是最後的結果。實現如下,使用 calculatePoints 函數用遞歸更好的計算結果。

Java


public class Solution {
    public int removeBoxes(int[] boxes) {
        return remove(boxes);
    }
    public int remove(int[] boxes)
    {
        if(boxes.length==0)
            return 0;
        int res=0;
        for(int i=0,j=i+1;i<boxes.length;i++)
        {
            while(j<boxes.length && boxes[i]==boxes[j])
                j++;
            int[] newboxes=new int[boxes.length-(j-i)];
            for(int k=0,p=0;k<boxes.length;k++)
            {
                if(k==i)
                    k=j;
                if(k<boxes.length)
                    newboxes[p++]=boxes[k];
            }
            res=Math.max(res,remove(newboxes)+(j-i)*(j-i));
        }
        return res;
    }
}


複雜度分析

時間複雜度:O(n!),f(n) 是找到 n個盒子有 nn 種不同顏色的方案,顯然 f(n-1)f(n)=n×f(n−1),所以結果 n! 是時間複雜度。
空間複雜度:O(n^2)

方法 2:記憶化搜索

算法

記憶化搜索

令dp[i][j]表示從j開始,長度爲i的字符串。
dp[i][j] = Math.max(dp[i-1][j] + 1, 最後一個字符與前面任意多個相同字符聯合起來得分的最大值);
所以對於dp,需要使用深度搜索找到 最後一個字符,與前面任意多個字符聯合起來的最大得分。

Java

 

class Solution {

    public int removeBoxes(int[] boxes) {
        int[][][] dp = new int[100][100][100];
        return calculatePoints(boxes, dp, 0, boxes.length - 1, 0);
    }

    public int calculatePoints(int[] boxes, int[][][] dp, int l, int r, int k) {
        if (l > r) return 0;
        if (dp[l][r][k] != 0) return dp[l][r][k];
        while (r > l && boxes[r] == boxes[r - 1]) {
            r--;
            k++;
        }
        dp[l][r][k] = calculatePoints(boxes, dp, l, r - 1, 0) + (k + 1) * (k + 1);
        for (int i = l; i < r; i++) {
            if (boxes[i] == boxes[r]) {
                dp[l][r][k] = Math.max(dp[l][r][k], calculatePoints(boxes, dp, l, i, k + 1) + calculatePoints(boxes, dp, i + 1, r - 1, 0));
            }
        }
        return dp[l][r][k];
    }
}


複雜度分析

時間複雜度:O(n^4)要填滿所有 dp 數組。
空間複雜度:O(n^3),dp 的數組大小。
 

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