• 【LeetCode】移除盒子 [H](记忆化搜索)


    546. 移除盒子 - 力扣(LeetCode)

    一、题目

    给出一些不同颜色的盒子 boxes ,盒子的颜色由不同的正数表示。

    你将经过若干轮操作去去掉盒子,直到所有的盒子都去掉为止。每一轮你可以移除具有相同颜色的连续 k 个盒子(k >= 1),这样一轮之后你将得到 k * k 个积分。

    返回 你能获得的最大积分和 。

    示例 1:
    输入:boxes = [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 分)

    示例 2:
    输入:boxes = [1,1,1]
    输出:9

    示例 3:
    输入:boxes = [1]
    输出:1

    提示:

    • 1 <= boxes.length <= 100
    • 1 <= boxes[i] <= 100

    二、代码

    1. class Solution {
    2. public int removeBoxes(int[] boxes) {
    3. int n = boxes.length;
    4. if (n == 1) {
    5. return 1;
    6. }
    7. int[][][] dp = new int[n][n][n];
    8. return process(boxes, 0, n - 1, 0, dp);
    9. }
    10. // arr[L...R]消除,而且前面跟着K个boxes[L]这个数
    11. // 返回:所有东西都消掉,最大得分
    12. public int process(int[] boxes, int l, int r, int k, int[][][] dp) {
    13. if (l > r) {
    14. return 0;
    15. }
    16. if (dp[l][r][k] != 0) {
    17. return dp[l][r][k];
    18. }
    19. // 常数优化点
    20. // 找到l+1~r范围上前面连续等于boxes[l]的最后的位置
    21. int last = l;
    22. for (int i = l + 1; i <= r; i++) {
    23. if (boxes[i] != boxes[i - 1]) {
    24. break;
    25. }
    26. last++;
    27. }
    28. // 统计算上l前面的k个boxes[l],再加上l+1~r的连续等于boxes[l]的最长前缀的个数,算一共有多少个连续前缀boxes[l]。注意这里没有算l位置的这个数,后面要自己加1
    29. int pre = k + (last - l);
    30. // 选择一:将l前面k个boxes[l]和l~last的连续的boxes[l]合并,得分是(pre + 1) * (pre + 1)
    31. // 然后将后面的last+1~r范围的数自己合并,递归调用为process(boxes, last + 1, r, 0, dp)
    32. int p1 = (pre + 1) * (pre + 1) + process(boxes, last + 1, r, 0, dp);
    33. // 选择二:将lasr+1~i-1范围内的数自己区合并,递归调用为process(boxes, last + 1, i - 1, 0, dp)
    34. // 当lasr+1~i-1范围合并全都消掉之后,last+1前面的连续相同的pre+1个boxes[l]就和i~r范围的数相邻了,然后就将这两个分去合并消除,递归调用为process(boxes, i, r, pre + 1, dp)
    35. int p2 = Integer.MIN_VALUE;
    36. // 尝试所有符合要求的i位置,来找到所有可能情况的最大得分
    37. for (int i = last + 1; i <= r; i++) {
    38. int temp = 0;
    39. if (boxes[i] == boxes[l]) {
    40. temp = process(boxes, last + 1, i - 1, 0, dp) + process(boxes, i, r, pre + 1, dp);
    41. }
    42. p2 = Math.max(p2, temp);
    43. }
    44. /**
    45. 这两种选择就是以前面连续相同的boxes[l]作为基准,要么就前缀连续相同的数自己合并,再将剩下部分自己合并
    46. 要么将整个范围中间的部分去合并消除,中间消除之后再将两边部分的数在一起合并消除
    47. 这两种选择就可以将所有可能的情况都涵盖了,不会漏掉
    48. */
    49. dp[l][r][k] = Math.max(p1, p2);
    50. return dp[l][r][k];
    51. }
    52. }

    三、解题思路 

    采用记忆化搜索的思路,关键是如何建立递归模型。

  • 相关阅读:
    VSCode将一份代码同步到多台服务器的解决方案
    ERP、CRM、SRM、PLM、HRM、OA……都是啥意思
    【结构体内功修炼】枚举和联合的奥秘(三)
    【工作小技巧】刚入职的软件测试工程师怎么快速上手新岗位
    LeetCode-404. Sum of Left Leaves [C++][Java]
    牛客网SQL大厂真题—SQL158:每类视频近一个月的转发量/率
    Fiddler 系列教程(一)初识Fiddler,我们能用fiddler做什么?
    Golang swagger :missing required param comment parameters
    PDF文件怎么打开
    区间素数筛
  • 原文地址:https://blog.csdn.net/cy973071263/article/details/127106545