力扣回溯算法经典题-python实现

组合

77.组合

  • 题目:给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的不同组合
class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        def dfs(n, k, path, res, start_index):
            if k == 0:  # 当k等于0时,说明一个组合已经找到,可以放到res中
                res.append(path[:])  # 注意path一定是深拷贝
                return
            for i in range(start_index, n+1):
                path.append(i)
                dfs(n, k-1, path, res, i+1)  # 下一次递归时,k个数变成了k-1个数。每个数字不能重复取,从i+1开始取
                path.pop()
        path, res = [], []
        start_index = 1
        dfs(n, k, path, res, start_index)
        return res
print(Solution().combine(n=4, k=2))

216.组合总和3

  • 题目:找出所有相加之和为 n 的 k 个数的不同组合。只使用数字1到9每个数字最多使用一次
class Solution:
    def combinationSum3(self, k: int, n: int) -> List[List[int]]:
    	def dfs(k, n, path, res, start_index):
    		if k == 0 and n == 0:  # 因为求得是组合总和,因此多了n==0的限制条件
    			res.append(copy.deepcopy(path))
    			return
    		for i in range(start_index, 10): # 相比组合,仅仅只是[1,n],变成了[1,9]
    			path.append(i)
    			dfs(k-1, n-i, path, res, i+1)  # 每个数字不能重复取,从i+1开始取
    			path.pop()
    	path, res = [], []
    	start_index = 1
    	dfs(k, n, path, res, start_index)
    	return res
print(Solution().combinationSum3(k = 3, n = 7))

39.组合总和

  • 题目:给定一个无重复元素的数组nums和一个目标整数 target ,找出 nums中可以使数字和为 target 的所有不同组合。nums中的同一个数字可以无限制重复被选取
    输入:nums = [2,3,6,7], target = 7
    输出:[[2,2,3],[7]]
class Solution:
    def combinnationSum(self, nums: List[int], target: int) -> List[List[int]]:
    	def dfs(nums, path, res, start_index, target):
    		if target == 0:
    			res.append(copy.deepcopy(path))
    			return
    		for i in range(start_index, len(nums)):
    			if nums[i] <= target:  # 判断候选数组里面的数,只有比target小才有意义。
    				path.append(nums[i])
    				dfs(nums, path, res, i, target-nums[i])  # 这里从i开始取,是因为同一个数字可以重复被选择
    				path.pop()
    	path, res = [], []
    	start_index = 0  # 数组下标从0开始
    	dfs(nums,path,res,start_index,target)    			
      	return res

print(Solution().combinnationSum(nums=[2, 3, 6, 7], target=7))

40.组合总和2

  • 题目:给定一个整数数组 nums和一个目标数 target ,找出 nums中可以使数字和为 target 的所有不同组合nums中的每个数字在每个组合中只能使用一次
    输入: nums= [2,5,2,1,2], target = 5,
    输出: [[1,2,2],[5]]
class Solution:
    def combinationSum2(self, nums: List[int], target: int) -> List[List[int]]:
    	nums.sort()  # 先排序,再剪枝,剪掉以相同数字为主的组合。
	    def dfs(nums, path, res, start_index, target):
	   		if target == 0:
	   			res.append(copy.deepcopy(path))
	   			return
	   		for i in range(start_index, len(nums)):
	   		# 经典剪枝操作,排序后,后面相等的数就不必再进行搜索了。i>start_index是为了保证nums[i-1]有意义
	   			if i > start_index and nums[i] == nums[i-1]: 
	   				continue
	   			if nums[i] <= target:
	   				path.append(nums[i])
	   				dfs(nums, path, res, i+1, target-nums[i]) # 因为每个数不能重复取,因此下一次递归从i+1开始
	   				path.pop()
	   	path, res = [], []
	   	start_index = 0
	   	dfs(nums,path,res,start_index,target)    			
	    return res

print(Solution().combinationSum2(nums=[10,1,2,7,6,1,5], target=8))

子集

78.子集

  • 题目:给你一个无重复元素整数数组 nums ,返回该数组所有可能的不同子集
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
      	def dfs(nums, path, res, start_index):
      		res.append(copy.deepcopy(path))
      		for i in range(start_index, len(nums)):
      			path.append(nums[i])
      			dfs(nums, path, res, i+1)  # 每个数字不能重复取
      			path.pop()
      	path, res = [],[]
      	start_index = 0
      	dfs(nums, path, res, start_index)
      	return res
      	   
print(Solution().subsets(nums = [1,2,3]))

90.子集2(不剪枝)

  • 题目:给你一个可能包含重复元素整数数组 nums ,请你返回该数组所有可能的不同子集
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
    	nums.sort()  # 排序至关重要,只有排序了,才能消除相同的子集
      	def dfs(nums, path, res, start_index):
      		if path not in res:
      			res.append(copy.deepcopy(path))
      			return 
      		for i in range(start_index, len(nums)):
      			path.append(nums[i])
      			dfs(nums, path, res, i+1)   # 每个数字可以相同,但不能重复取同一个元素。
      			path.pop()
      	path, res = [],[]
      	start_index = 0
      	dfs(nums, path, res, start_index)
      	return res
      	     	
print(Solution().subsets(nums = [1,2,3]))

90.子集2(剪枝)

class Solution:
	nums.sort()  # 排序不可少
    def subsets(self, nums: List[int]) -> List[List[int]]:
      	def dfs(nums, path, res, start_index):
      		res.append(copy.deepcopy(path))
      		for i in range(start_index, len(nums)):
      			# 经典剪枝
      			if i > start_index and nums[i] == nums [i-1]:  
      				continue
      			path.append(nums[i])
      			dfs(nums, path, res, i+1)
      			path.pop()
      	path, res = [],[]
      	start_index = 0
      	dfs(nums, path, res, start_index)
      	return res
      	     	
print(Solution().subsets(nums = [1,2,3]))

全排列

46.全排列

  • 题目:给定一个不含重复数字的数组 nums ,返回其所有可能的不重复的全排列
class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
    	visited = [False for _ in range(len(nums))]
    	def dfs(nums, path, res, visited, depth):
    		if depth == len(nums):
    			res.append(copy.deepcopy(path))
    			return 
    		for i in range(len(nums)):
    			if not visited[i]:
	    			visited[i] = True
	    			path.append(nums[i])
	    			dfs(nums, path, res, visited, depth+1)
	    			visited[i] = False
	    			path.pop()
    	path, res = [], []
    	depth = 0
    	dfs(nums, path, res, visited, depth)
    	return res
    		
print(Solution().permute(nums=[1,2]))

47.全排列2(不剪枝)

  • 题目:给定一个可包含重复数字的序列 nums ,按任意顺序返回所有不重复的全排列
class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
    	visited = [False for _ in range(len(nums))]
    	def dfs(nums, path, res, visited, depth):
    		if depth == len(nums):
    			if path not in res:
	    			res.append(copy.deepcopy(path))
	    			return 
    		for i in range(len(nums)):
    			if not visited[i]:
	    			visited[i] = True
	    			path.append(nums[i])
	    			dfs(nums, path, res, visited, depth+1)
	    			visited[i] = False
	    			path.pop()
    	path, res = [], []
    	depth = 0
    	dfs(nums, path, res, visited, depth)
    	return res
    		
print(Solution().permute(nums=[1,2]))

47.全排列2(剪枝)

  • 题目:给定一个可包含重复数字的序列 nums ,按任意顺序返回所有不重复的全排列。
class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
    	nums.sort()
    	visited = [False for _ in range(len(nums))]
    	def dfs(nums, path, res, visited, depth):
    		if depth == len(nums):
    			res.append(copy.deepcopy(path))
    			return 
    		for i in range(len(nums)):
    			if i > 0 and nums[i] == nums[i-1] and not visited[i-1]:
    				continue
    			if not visited[i]:
	    			visited[i] = True
	    			path.append(nums[i])
	    			dfs(nums, path, res, visited, depth+1)
	    			visited[i] = False
	    			path.pop()
    	path, res = [], []
    	depth = 0
    	dfs(nums, path, res, visited, depth)
    	return res
    		
print(Solution().permute(nums=[1,2]))

总结:

  1. 数组中的元素是否重复
  • 是:要考虑相同元素为首的重复集合(排序,剪枝)
  • 否:不用剪枝
  1. 数组中的元素是否可以重复使用
  • 是:下一次dfs从i开始
  • 否:下一次dfs从i+1开始
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值