给出一些不同颜色的盒子,盒子的颜色由数字表示,即不同的数字表示不同的颜色。
你将经过若干轮操作去去掉盒子,直到所有的盒子都去掉为止。每一轮你可以移除具有相同颜色的连续 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 分)
思路:
涉及子串的动态规划一般从子串两端进行递推,即(i,j)子串。
分析如下:
dp[i][j][k]表示从i到j子串并且右端存在与j相同的k个字符其获得的最大点数。
有1,3,2,2,2,3,3
i j dp[i][j][1]
此时有两种可选操作:
1、将j以及其后面的连续相同的串消除获得点数:dp[i][j-1][0]+(k+1)*(k+1)
1,3,2,2,2,4,3,1 ——> dp[i][j][0]+2*2
2、在子串内部寻找与右端相同的字符,将子串划分成两部分,先消除内部,再消除右端:dp[i][p][k+1]+dp[p+1][j-1][0]
1,3,3,1 ——> dp[i][p][k+1]
2,2,2,4 ——> dp[p+1][j-1][0]
dp[i][j][k]最大值为上面两种情况的最大值,代码如下
Python版:
class Solution:
def removeBoxes(self, boxes):
"""
:type boxes: List[int]
:rtype: int
"""
#涉及子串动态规划利用(i,j)进行地推 dp[i][j][k]表示从i到j子串并且右端存在与j相同的k个字符其获得的最大点数。
n = len(boxes)
dp = [[[0]*n for _ in range(n)]for _ in range(n)]
return self.robot(boxes,dp,0,n-1,0)
def robot(self,boxes,dp,x,y,k):
if x > y:
return 0
if dp[x][y][k] > 0:
return dp[x][y][k]
while x < y and boxes[y] == boxes[y-1]:
y -= 1
k += 1
dp[x][y][k] = self.robot(boxes,dp,x,y-1,0) + (k+1)*(k+1)
for i in range(x,y):
if boxes[i] == boxes[y]:
dp[x][y][k] = max(dp[x][y][k],self.robot(boxes,dp,x,i,k+1) + self.robot(boxes,dp,i+1,y-1,0))
return dp[x][y][k]