【Leetcode】546. Remove Boxes

题目地址:

https://leetcode.com/problems/remove-boxes/

给定一个长 n n n数组 A A A,每次可以将连续的一段相等的数删去,得分是这一段数的个数的平方。问将其数全部删去得分最大是多少。

思路是动态规划。设 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]是要清空 A [ i : j ] A[i:j] A[i:j]这个区间,最后是删除了 k k k个数,并且使得 A [ i ] A[i] A[i]是最后一个被删除的数的情况下,得到的最大分数。首先对于任意方案,如果 A [ i ] A[i] A[i]不是最后删除的,那么我们可以将删除 A [ i ] A[i] A[i]的那一步放到最后去做,这样并不影响得分。所以 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]可以枚举到所有情况。设 g [ i ] [ j ] g[i][j] g[i][j]是清空 A [ i : j ] A[i:j] A[i:j]的所有方案的最大得分,即 g [ i ] [ j ] = max ⁡ 1 ≤ k ≤ j − i + 1 f [ i ] [ j ] [ k ] g[i][j]=\max_{1\le k\le j - i + 1}f[i][j][k] g[i][j]=max1kji+1f[i][j][k]。对于 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k],我们枚举 A [ i ] A[i] A[i]是单独删除的,还是和别的数一起删的。
1、如果其是单独删的,那么删掉它得分是 1 1 1,其右边的数删除的最大得分是 g [ i + 1 ] [ j ] g[i+1][j] g[i+1][j],即 f [ i ] [ j ] [ 1 ] = 1 + g [ i + 1 ] [ j ] f[i][j][1]=1+g[i+1][j] f[i][j][1]=1+g[i+1][j]
2、如果其不是单独删的,我们枚举最后一次删除的时候,除了 A [ i ] A[i] A[i]以外最左边被删除的数,设其是 A [ u ] A[u] A[u],那么 u = i + 1 , i + 2 , . . . , j u=i+1,i+2,...,j u=i+1,i+2,...,j,并且要保证 A [ u ] = A [ i ] A[u]=A[i] A[u]=A[i](颜色相同才能一起删)。这样将区间 [ i : j ] [i:j] [i:j]的删除过程分为了两步,即删除 A [ i + 1 : u − 1 ] A[i+1:u-1] A[i+1:u1]和删除 A [ i ] , A [ u : j ] A[i],A[u:j] A[i],A[u:j](这里可以看成 A [ i ] A[i] A[i] A [ u : j ] A[u:j] A[u:j] j − u j-u ju个数拼成了一个新区间去删除。之所以可以这么做,是因为对于任意方案,我们总可以重排,使得 A [ i + 1 : u − 1 ] A[i+1:u-1] A[i+1:u1]先删,这样其余的删除操作就可以看成是在 [ A [ i ] , A [ u ] , . . . , A [ j ] ] [A[i],A[u],...,A[j]] [A[i],A[u],...,A[j]]这样的新数组上操作了),第一部分的最大得分是 g [ i + 1 : u − 1 ] g[i+1:u-1] g[i+1:u1],而第二部分的最大得分,由于最后一步是左边连续删除了 k k k个,所以是 A [ u : j ] A[u:j] A[u:j]是左边连续删除了 k − 1 k-1 k1个,而对于 A [ u : j ] A[u:j] A[u:j]是左边连续删除了 k − 1 k-1 k1个这个的最大得分是 f [ u ] [ j ] [ k − 1 ] f[u][j][k-1] f[u][j][k1],现在我们是最后删 k k k个,所以得分应该是 f [ u ] [ j ] [ k − 1 ] − ( k − 1 ) 2 + k 2 f[u][j][k-1]-(k-1)^2+k^2 f[u][j][k1](k1)2+k2。所以综上: f [ i ] [ j ] [ k ] = { 1 + g [ i + 1 ] [ j ] , k = 1 max ⁡ u > i ∧ A [ u ] = A [ i ] { g [ i + 1 ] [ u − 1 ] + f [ u ] [ j ] [ k − 1 ] − ( k − 1 ) 2 + k 2 } , k > 1 f[i][j][k]=\begin{cases}1+g[i+1][j], k=1\\\max_{u>i\land A[u]=A[i]}\{g[i+1][u-1]+ f[u][j][k-1]-(k-1)^2+k^2 \} ,k>1 \end{cases} f[i][j][k]={1+g[i+1][j],k=1maxu>iA[u]=A[i]{g[i+1][u1]+f[u][j][k1](k1)2+k2},k>1当然这里,如果 g g g那里的区间长度小于 0 0 0,则 g g g 0 0 0。代码如下:

import java.util.Arrays;

public class Solution {
    public int removeBoxes(int[] A) {
        int n = A.length;
        // f[i][j][k]是清空A[i : j]并且最后一步是删除了A[i]且恰好删了k个数的所有方案里最大的得分
        int[][][] f = new int[n][n][n + 1];
        // g[i][j]是清空A[i : j]的最大得分
        int[][] g = new int[n][n];
        // 先初始化为最小值
        for (int i = 0; i < n; i++) {
            for (int[] row : f[i]) {
                Arrays.fill(row, -1 << 30);
            }
            
            Arrays.fill(g[i], -1 << 30);
        }
        
        // 枚举区间长度为1的情况
        for (int i = 0; i < n; i++) {
            f[i][i][1] = g[i][i] = 1;
        }
        
        // 枚举区间长度大于1的情况,先枚举区间长度
        for (int len = 2; len <= n; len++) {
        	// 再枚举左端点
            for (int i = 0; i + len - 1 < n; i++) {
            	// 算出右端点
                int j = i + len - 1;
                // 枚举k = 1的情况
                f[i][j][1] = 1 + g[i + 1][j];
                // 更新g[i][j]
                g[i][j] = Math.max(g[i][j], f[i][j][1]);
                
                // 枚举k大于1的情况
                for (int k = 2; k <= len; k++) {
                	// 枚举最后一次删除的时候,删除的所有数里左起第二个数是谁;
                	// 由于最后删除的数的个数是k个,所以j - u + 2 >= k
                    for (int u = i + 1; u <= j - k + 2; u++) {
                    	// 这个第二个数一定要与A[i]相等
                        if (A[u] != A[i]) {
                            continue;
                        }
                        
                        // 预存一下g的部分
                        int t = i + 1 <= u - 1 ? g[i + 1][u - 1] : 0;
                        // 更新f
                        f[i][j][k] = Math.max(f[i][j][k], t + f[u][j][k - 1] - (k - 1) * (k - 1) + k * k);
                    }
                    
                    // 更新g
                    g[i][j] = Math.max(g[i][j], f[i][j][k]);
                }
            }
        }
        
        return g[0][n - 1];
    }
}

时间复杂度 O ( n 4 ) O(n^4) O(n4),空间 O ( n 3 ) O(n^3) O(n3)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值