回溯是一种试探性算法,每次都选择走不走下一步,很像一种后悔药。在子集问题上一般是给定一个有重复数字或者,没有重复数字的数组,然后找到所有符合条件的不重复的子集。
本质上是一种深度优先搜索算法。
题解示例是给一个没有重复数字的数组,找出所有的不重复(顺序不同也被视为同一个答案)的子集。
# Time: O(n * 2^n), Space: O(n)
def subsetsWithoutDuplicates(nums):
subsets, curset = [], []
helper(0, nums, subsets, curset)
return subsets
def helper(i, nums, subsets, curset):
if i >= len(nums):
subsets.append(curset[:])
return
# include current i - index value
curset.append(nums[i])
helper(i + 1, nums, subsets, curset)
# clear up to reset the status
curset.pop()
# not include i value
helper(i + 1, nums, subsets, curset)
如果给出的数组中有重复数字,如何进行求解:和上面的情况不同之处在于,首先要对数组排序,然后在进行回溯的时候,一种是一个一个迭代添加,另一个情况是跳过所有重复的元素。仅此不同而已。
# Time: O(n * 2^n), Space: O(n)
def subsetsWithDuplicates(nums):
nums.sort()
subsets, curset = [], []
helper(0, nums, subsets, curset)
return subsets
def helper(i, nums, subsets, curset):
if i >= len(nums):
subsets.append(curset[:])
return
# include i index value
curset.append(nums[i])
helper(i + 1, nums, subsets, curset)
# clear up to reset the status
curset.pop()
# not include i value with all the duplicates
while i + 1 < len(nums) and nums[i + 1] == nums[i]:
i += 1
helper(i + 1, nums, subsets, curset)
class Solution(object):
def subsets(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
res = []
curset = []
def dfs(idx):
if idx >= len(nums):
res.append(curset[:])
return
# curset include the idx num
curset.append(nums[idx])
dfs(idx + 1)
# backtracking, not include the num
curset.pop()
dfs(idx + 1)
dfs(0)
return res
问题中的数组中有重复的数字,和无重复数组的关键不同在于,需要先对数组排序,然后在回溯的时候,只有在回溯前加入该数字,回溯后,迭代index的位置,直到不重复的数字index为止。