我最近一直在练习leetcode,刚刚做了"组合和"问题(删节,完整的陈述可以在 https://leetcode.com/problems/combination-sum/找到)。
给定一个不同整数候选数组和一个目标整数 目标,返回所有唯一候选组合的列表,其中 所选数字的总和与目标相加。您可以返回组合 任何订单。
可以从候选人中选择相同的号码,数量不限 次。如果频率至少为以下一种,则两个组合是唯一的 选择的数字是不同的。
我使用一种简单的回溯方法正确解决了这个问题,该方法构建了一个部分解决方案,然后使用以下帮助程序函数将其附加到数组和数组中(部分是一个列表)
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
ans = []
def helper(candidates, target, partial):
if target == 0:
ans.append(partial[:])
return
if target < 0:
return
for i in range(0,len(candidates)):
partial.append(candidates[i])
helper(candidates[i:], target-candidates[i], partial)
partial.pop()
candidates.sort()
helper(candidates,target,[])
return ans
这段代码有效,我很满意。但是,如果我将最后一行更改为:
partial = partial[:-1]
该解决方案不再有效。特别是,元素不会像我想要的那样被删除,我的 ans 数组最终会得到包含大量不正确元素的解决方案。直觉上,我希望这些服务于从部分中删除最后一个元素的相同目的。
我怀疑这与我缺少的参考文献和列表切片有关。为什么当我解决电话号码的leetcode问题组合(见 https://leetcode.com/problems/letter-combinations-of-a-phone-number/)时没有这个问题,该号码要求枚举来自数字 - 字母电话映射的所有可能字符串,给定一串数字?
在这里,我使用了相同的帮助程序函数结构:
def letterCombinations(self, digits: str) -> List[str]:
ans = []
MAPPING = ('0', '1', "abc", "def", 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz')
def helper(s, partial_sol):
if len(s) == 0:
ans.append(partial_sol)
return
else:
for i in MAPPING[int(s[0])]:
partial_sol = partial_sol + i
helper(s[1:], partial_sol)
partial_sol = partial_sol[:-1]
if len(digits) == 0:
return ans
helper(digits, "")
return(ans)
我的解决方案是正确的。请注意,虽然我使用了 [:-1] 方法,该方法不适用于列表上的第一个问题,但在字符串上遇到了这个问题。所以我可以看到字符串与列表发生的一切都是不同的(就像在电话号码问题中一样,partial 是字符串而不是列表),我只是不知道它到底是什么,或者为什么。
简而言之,我的问题是:
- 为什么当我从弹出部分更改为以下时,我的组合总和解决方案不起作用:
partial = partial[:-1]
- 为什么该解决方案不适用于组合总和(使用列表),但适用于电话号码中的字母(使用字符串)?
你是对的,它与引用和list
切片有关。
partial.pop()
修改绑定到就地partial
的list
。
partial = partial[:-1]
制作了list
的浅拷贝,并将partial
重新绑定到新的list
。
这是一个重要的区别,因为重新绑定不会更改引用原始list
的任何其他别名,其中包括调用者对同一list
的绑定。为了使两者的行为几乎相同(pop
效率更高,并且与切片不同,会在空list
上出错),您可以使用:
partial[:] = partial[:-1]
它将原始list
的内容重新分配给浅拷贝的内容,或者,具有与pop
相同(可能略好)的性能:
# Errors on empty list like pop
del partial[-1]
# Or to silently do nothing when applied to an empty list:
del partial[-1:]
直接删除元素而不返回它。
这些都不能与str
一起使用,因为str
是不可变的;不可能就地修改相同str
的别名,您只能创建新str
并重新绑定给定名称,这不适用于这种情况。一个简单的解决方案是使你的代码可以使用str
将其转换为list
,或者,如果str
中仅出现ASCII/拉丁语-1字符,则将其编码为bytes
,然后转换为bytearray
,这是可变的,可能允许您使用更直接地期望可变序列的代码。