【问题标题】:Recurive Backtracking: Leet Code - Remove Boxes (Python)递归回溯:Leetcode - 删除框(Python)
【发布时间】:2021-10-17 10:49:05
【问题描述】:

我正在研究这个 leetcode:https://leetcode.com/problems/remove-boxes/,而我的回答对于某些测试用例来说只是略微偏离。任何建议将不胜感激。

问题概述如下:

给你几个不同颜色的盒子,用不同的正数表示。

您可能会经历几轮来移除盒子,直到没有盒子为止。每次可以选择一些颜色相同的连续框(即由k个框组成,k >= >1),去掉它们,得到k * k个点。

返回你可以获得的最高分。

示例 1:

Input: boxes = [1]
Output: 1 => (1*1)

示例 2:

Input: boxes = [1,1,1]
Output: 9 => (3*3)

示例 3:

Input: boxes = [1,3,2,2,2,3,4,3,1]
Output: 23
Explanation:
[1, 3, 2, 2, 2, 3, 4, 3, 1] 
----> [1, 3, 3, 4, 3, 1] (3*3=9 points) 
----> [1, 3, 3, 3, 1] (1*1=1 points) 
----> [1, 1] (3*3=9 points) 
----> [] (2*2=4 points)

我决定使用递归回溯来尝试解决这个问题,我的代码如下:

from copy import deepcopy as copy
class Solution: 
    # Main function
    def backtrack(self, boxes, score, seen={}):
        # Make list hashable
        hashable = tuple(boxes)
        
        if len(boxes) == 0:
            return score
        
        if hashable in seen:
            return seen[hashable]
        
        pos_scores = []
        
        loop_start = 0
        loop_end = len(boxes)
        
        while(loop_start < loop_end):
            # keep original boxes for original 
            box_copy = copy(boxes)
            
            # Returns the continous from starting point
            seq_start, seq_end = self.find_seq(box_copy, loop_start)
            
            # Return the box array without the seqence, and the score from removal
            new_boxes, new_score = self.remove_sequence(box_copy, seq_start, seq_end)
            
            # Backtrack based off the new box list and new score
            pos_scores.append(self.backtrack(box_copy, score+new_score, seen))
            
            # Next iteration will use a fresh copy of the boxes
            loop_start = seq_end
            
        seen[hashable] = max(pos_scores)
        return seen[hashable]
        
    def remove_sequence(self, boxes, start, end):
        rem_counter = 0

        for i in range(start, end):
            boxes.pop(i - rem_counter)
            rem_counter += 1

        dist = (end - start)
        score = dist * dist
        return boxes, score
    
    def find_seq(self, boxes, start):
        color = boxes[start]
        end = start

        for i in range(start, len(boxes)):
            if boxes[i] == color:
                end += 1
            else:
                break

        return start, end
    
    def removeBoxes(self, boxes) -> int:
        return self.backtrack(boxes, 0, {})

我的问题是我的代码适用于较小的示例,但对于较大的示例则稍有偏差。我相信我的代码几乎在那里,但我认为我错过了一个极端情况。任何提示将非常感谢。例如,我得到了 [1,1,2,1,2] 以及大多数测试用例的正确答案。但是我对第三个例子的回答是 21,而不是 23。

【问题讨论】:

  • 不幸的是,您存储由剩余序列索引的seen 分数的方法是有缺陷的,因为与不同分数相关联的不同路径可能导致相同的剩余 - e。 G。第三个示例中的剩余序列 [1, 1] 可以达到分数 17 以及分数 19,并且您的代码正在散列次最大值 17。
  • 谢谢!我只需要添加hashable = tuple(boxes), score
  • @Armali,如果您将此作为答案发布,我会接受!
  • 由于我只是指出了您的代码中的一个缺陷并且您自己找到了解决方案,因此我建议您将解决方案作为自我回答发布,这是完全可以接受的。

标签: python dynamic-programming backtracking recursive-backtracking


【解决方案1】:

根据@Armali 的评论,上面代码的解决方案是使用

        hashable = tuple(boxes), score

【讨论】: