简体   繁体   English

超过 LeetCode 40 时间限制

[英]LeetCode 40 time limit exceeded

I'm working on LeetCode 40. Combination Sum II我正在研究 LeetCode 40。组合总和 II

Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sum to target.给定一组候选编号(candidates)和一个目标编号(target),找出候选编号总和为 target 的所有唯一组合。

Each number in candidates may only be used once in the combination.候选中的每个数字在组合中只能使用一次。

Note: The solution set must not contain duplicate combinations.注意:解决方案集不得包含重复的组合。

My code below works until the candidates collection gets too big, then I get back "time limit exceeded".我下面的代码一直有效,直到候选人集合变得太大,然后我得到“超出时间限制”。 All of the recursion is creating too many loops I think.我认为所有的递归都创建了太多的循环。 I can obviously copy tutorials to get the answer but I'm trying to figure out how my code could be updated to work in order to understand better how recursion works.我显然可以复制教程来获得答案,但我试图弄清楚我的代码如何更新才能工作,以便更好地理解递归是如何工作的。

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()
        answers = []
        strings = []
        total = sum(candidates)
        if total < target:
            return []
        def backtrack(total, array, index):
            if total == 0:
                string = ''
                for each in array:
                    string += str(each)
                if string not in strings:
                    answers.append(array)
                    strings.append(string)
                    return
            if index >= len(candidates):
                return
            for each in range(index, len(candidates)):
                backtrack(total - candidates[each], array + [candidates[each]], each + 1)
                backtrack(total, array, each + 1)
        backtrack(target, [], 0)
        return answers

It is a good idea to sort the candidates, but you do not use it.对候选项进行排序是个好主意,但您不要使用它。 You should recuser only if total-candidate[i]>0, break if <0 and return if =0仅当 total-candidate[i]>0 时才应撤回,如果 <0 则中断,如果 =0 则返回

Some issues that are a hit to performance:一些影响性能的问题:

  • When total becomes negative, it is useless to continue the recursive process: it will only get more negative.total变为负时,继续递归过程是没有用的:它只会变得更负。

  • The second call to backtrack is implementing the same idea as the for loop.backtrack的第二个调用是实现与for循环相同的想法。 Consider that in the loop all possible values for each + 1 will be passed to backtrack(total, array, each + 1) .考虑在循环中, each + 1的所有可能值都将传递给backtrack(total, array, each + 1) But then also note that one level deeper in the recursion tree, all of these -- except the first -- are made again !但还要注意,在递归树中更深一层,所有这些——除了第一个——都被重新制作 So either remove backtrack(total, array, each + 1) or else keep it, and remove the for loop.所以要么删除backtrack(total, array, each + 1)要么保留它,然后删除for循环。

  • When two consecutive values are the same, and the recursive call has been made for the first of these two, it is useless to make a recursive call with the duplicate value.当两个连续的值相同,并且已经对这两个中的第一个进行了递归调用时,使用重复值进行递归调用是没有用的。 At that moment there is one fewer value to choose from, and the total is the same, so there cannot come any new combinations from that.在那一刻,可供选择的值少了一个,而且总数是一样的,所以不能从中产生任何新的组合。 So if we go for the for loop (see previous point), then only make recursive calls for distinct values (the first time they occur).因此,如果我们将 go 用于for循环(请参阅前一点),那么只对不同的值进行递归调用(它们第一次出现)。

  • The string concatenation for finding duplicate results, works with the test cases, but it is a bit doggy, because digits get clued together.用于查找重复结果的字符串连接适用于测试用例,但它有点棘手,因为数字被连接在一起。 For instance, when 1, 2, 3 is stringified, it becomes "123".例如,当1, 2, 3被字符串化时,它变为“123”。 But also 1, 23 would be stringified like that, and this could lead to false negatives.但是 1, 23 也会像这样被字符串化,这可能会导致假阴性。 So this is actually a bug in the code that goes undetected on LeetCode.所以这实际上是 LeetCode 上未被检测到的代码中的错误。 You can solve this by using separator characters.您可以通过使用分隔符来解决此问题。

Here is your code adapted with those points taking into account:这是考虑到这些要点的代码:

class Solution: 
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()
        answers = []
        strings = []
        total = sum(candidates)
        if total < target:
            return []
        def backtrack(total, array, index):
            if total == 0:
                string = ''
                for each in array:
                    string += "_" + str(each)  # Separate the values
                if string not in strings:
                    answers.append(array)
                    strings.append(string)
                    return
            if index >= len(candidates) or total < 0:  # give up when total becomes negative
                return
            current = -1
            for each in range(index, len(candidates)):
                if candidates[each] != current: # Avoid duplicates
                    current = candidates[each]
                    backtrack(total - current, array + [current], each + 1)
                # Don't make another recursive call here. The for-loop is already skipping candidates
        backtrack(target, [], 0)
        return answers

There is still room for improvement.仍有改进的余地。 You could think of the following points:你可以想到以下几点:

  • Your code currently checks that the total is not greater than the overall sum.您的代码当前检查总数不大于总和。 You could extend this, and verify that the total is not greater than the remaining sum, during the recursive process.您可以扩展它,并在递归过程中验证总数不大于剩余总和。 You would prepare a list with all these "remaining" sums before starting the recursion, and then check the total against the relevant value in that list.在开始递归之前,您将准备一个包含所有这些“剩余”总和的列表,然后根据该列表中的相关值检查总数。

  • if string not in strings is not so efficient when strings is a list. if string not in stringsstrings是列表时效率不高。 It would be better to use a set for strings .最好为strings使用一个集合。

  • Instead of using strings as identifiers, you could create tuples instead of sub lists.您可以创建元组而不是子列表,而不是使用字符串作为标识符。 These are hashable, so if you store them in an overall set instead of list, you will not get duplicates.这些是可散列的,所以如果你将它们存储在一个整体集合而不是列表中,你将不会得到重复。 Then at the very end you can convert that set of tuples to the final list of lists.然后在最后,您可以将该组元组转换为最终的列表列表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM