leetcode39、40、47、 78、 77、131
目录
47:全排列
全排列问题:
使用回溯法,需要注意的问题:
不能重复出现,要去重,可以先将数字排序,这样重复的元素肯定是相邻的, 那么我们判断前一个元素和当前元素相同,就conutinue,还有就是用过一个元素 就对这个元素做一个标记,这样看到上一个元素的标记,就不会重复使用了
输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
def permuteUnique(nums:list) ->list:
res=[]
nums.sort()
used=[0 for i in range(len(nums))]
def backtrack(nums,used,path):
for i in range(len(nums)):
if len(path)==len(nums):
res.append(path[:])
return
if used[i]==1: #用过
continue
if i>0 and nums[i]==nums[i-1] and used[i-1]==0: #重复出现的数字,且没有被用过
continue
used[i]=1
# path.append(nums[i])
backtrack(nums,used,path+[nums[i]]) #path:list nums[i]:int
used[i]=0
backtrack(nums,used,[])
return res
print(permuteUnique([1,1,3]))
78:子集
给你一个整数数组nums ,数组中的元素互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
def subset(nums:list) -> list:
res=[]
def backtrack(path,start):
res.append(path[:])
for i in range(start,len(nums)):
backtrack(path+[nums[i]],i+1)
# return res
backtrack([],0)
return res
print(subset([1,2,3]))
39组合总和
---->回溯算法
输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
注意:!!集合元素可重复选取,子集,candicate内元素无序,无重复
result=list()
path=list()
def MakeSum(target:int,candidates:list) ->list:
def backtrack(target,candidates,sum,start):
if sum>target:
return
if sum==target:
result.append(path[:])
return
for i in range(start,len(candidates)):
path.append(candidates[i])
sum+=candidates[i]
backtrack(target,candidates,sum,i)
sum-=candidates[i]
path.remove(candidates[i])
backtrack(target,candidates,0,0) #sum,start=0,0
return result
print(MakeSum(7,[2,3,6,7])
40 组合总和
回溯
输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]
即集合内元素不能被重复,比如这里有一个1,那么一个列表内只能有1个1,1不可以重复使用
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
result=[]
path=[]
candidates.sort()
def backtrack(target,candidates,sum,start):
# if sum>target:
# return
if sum==target:
result.append(path[:])
return
for i in range(start,len(candidates)):
if sum+candidates[i]>target:
break
# if sum + candidates[i] <= target:
if i > start and (candidates[i] == candidates[i - 1]):
continue
if (sum + candidates[i] <= target):
sum+=candidates[i]
path.append(candidates[i])
backtrack(target,candidates,sum,i+1)
sum-=candidates[i]
path.pop() #sum,start=0,0
backtrack(target,candidates,0,0)
return result
77组合
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
示例 1:
输入:n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
from typing import List
def combine(n: int, k: int) -> List[List[int]]:
res=[]
nums=[i for i in range(1,n+1)]
def backtrack(nums,path,start):
if len(path)==k:
# res.append(path) 加入的是一个空列表
res.append(path[:])
return
for j in range(start,n+1-(k-len(path))): #加入了剪枝操作
# for j in range(start,len(nums)): #未加入剪枝操作
path.append(nums[j])
backtrack(nums,path,j+1)
# path.remove(nums[j]) remove(value) 会从列表第一个元素开始,直到value,把value移除,整个列表的移动,因此效率没pop高
path.pop() #回溯 pop(index) 默认pop的是最后一个元素,有返回值返回值是pop出的元素值
backtrack(nums,[],0)
return res
print(combine(n=4,k=2)
131 分割回文串
分割回文串 力扣131
示例 1:
输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]
回溯法
# print([1]+[2])
def partition(s:str) ->list:
res=[]
def ispalindrome(x):
if x[::-1]==x:
return True
def backtrack(start,path):
if start==len(s): #叶子节点收集path
res.append(path[:])
return
for i in range(start,len(s)):
if ispalindrome(s[start:i+1]):
path.append(s[start:i+1])
else:
continue
backtrack(i+1,path)
path.pop()
backtrack(0,[])
return res
print(partition('aab'))