力扣动态规划 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 的数组大小。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值