做题记录
组合:N个数找K个数的集合
切割:字符中有几种切割方式
子集:N个数有几个符合条件的子集
排列:N个数按规则有几种排列(组合无序,排列有序)
棋盘:N皇后、解数独···
一个元素不能重复使用,所以需要startIndex,调整下一层递归的起始位置。
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
class Solution(object):
def combine(self, n, k):
self.path=[]
self.res=[]
self.check(n,k,1)
return self.res
def check(self,n,k,start):
if len(self.path)==k:
self.res.append(self.path[:])
return
for i in range(start,n+1):
self.path.append(i)
self.check(n,k,i+1)
self.path.pop()
class Solution(object):
def combinationSum3(self, k, n):
self.path=[]
self.res=[]
self.check(k,n,0,1)
return self.res
def check(self,k,n,sum_,start):
if len(self.path)==k and sum_==n:
self.res.append(self.path[:])
return
for i in range(start,10):
sum_+=i
self.path.append(i)
self.check(k,n,sum_,i+1)
sum_-=i
self.path.pop()
class Solution(object):
def letterCombinations(self, digits):
self.path=''
self.res=[]
if not digits:return self.res
self.keyborad={'2':'abc','3':'def','4':'ghi',
'5':'jkl','6':'mno','7':'pqrs','8':'tuv','9':'wxyz'}
self.check(digits,0)
return self.res
def check(self,digits,start):
if start==len(digits):#
self.res.append(self.path)
return
letters=self.keyborad[digits[start]]
for letter in letters:
self.path+=letter
self.check(digits,start+1)
self.path=self.path[:-1]
class Solution(object):
def combinationSum(self, candidates, target):
self.res=[]
self.path=[]
self.check(candidates,target,0,0)
return self.res
def check(self,candidates,target,sum_,start):
if sum_==target:
self.res.append(self.path[:])
return
elif sum_>target:return
for i in range(start,len(candidates)):
sum_+=candidates[i]
self.path.append(candidates[i])
self.check(candidates,target,sum_,i)
sum_-=candidates[i]
self.path.pop()
本题中数组有重复元素,所以要对相同元素进行去重。
class Solution(object):
def combinationSum2(self, candidates, target):
self.path=[]
self.res=[]
candidates.sort()
self.check(candidates,target,0,0)
return self.res
def check(self,candidates,target,sum_,start):
if sum_==target:
self.res.append(self.path[:])
return
for i in range(start,len(candidates)):
if i>start and candidates[i]==candidates[i-1]:continue#去重
if sum_+candidates[i]>target:return
sum_+=candidates[i]
self.path.append(candidates[i])
self.check(candidates,target,sum_,i+1)
sum_-=candidates[i]
self.path.pop()
class Solution(object):
def partition(self, s):
self.path=[]
self.res=[]
self.check(s,0)
return self.res
def isback(self,s,l,r):
while l<r:
if s[l]==s[r]:
l+=1
r-=1
else:return False
return True
def check(self,s,start):
if start>=len(s):#如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
self.res.append(self.path[:])
return
for i in range(start,len(s)):
if self.isback(s,start,i):
self.path.append(s[start:i+1])
else:continue
self.check(s,i+1)
self.path.pop()
只能切割三次,使用point记录逗号数量,当point==3时,判断子集是否合法
class Solution(object):
def restoreIpAddresses(self, s):
self.res=[]
self.back(s,0,0)
return self.res
def back(self,s,start,point):
if point==3:
if self.isvalid(s,start,len(s)-1):
self.res.append(s[:])
return
for i in range(start,len(s)):
if self.isvalid(s,start,i):
s=s[:i+1]+'.'+s[i+1:]
self.back(s,i+2,point+1)
s=s[:i+1]+s[i+2:]
else:break
def isvalid(self,s,l,r):
if l>r:return False
if s[l]=='0' and l!=r:return False
if not 0<=int(s[l:r+1])<=255:return False
return True
class Solution(object):
def subsets(self, nums):
self.path=[]
self.res=[]
self.back(nums,0)
return self.res
def back(self,nums,start):
self.res.append(self.path[:])
if start==len(nums):
return
for i in range(start,len(nums)):
self.path.append(nums[i])
self.back(nums,i+1)
self.path.pop()
class Solution(object):
def subsetsWithDup(self, nums):
self.res=[]
self.path=[]
nums.sort()
self.back(nums,0)
return self.res
def back(self,nums,start):
self.res.append(self.path[:])
if start==len(nums):return
for i in range(start,len(nums)):
if i >start and nums[i]==nums[i-1]:#去重
continue
self.path.append(nums[i])
self.back(nums,i+1)
self.path.pop()
设置used数组,判断该元素是否使用过
class Solution(object):
def permute(self, nums):
self.res=[]
self.path=[]
self.used=[False]*len(nums)
self.back(nums)
return self.res
def back(self,nums):
if len(self.path)==len(nums):
self.res.append(self.path[:])
return
for i in range(len(nums)):
if self.used[i]==True:continue
self.used[i]=True
self.path.append(nums[i])
self.back(nums)
self.used[i]=False
self.path.pop()
树层上不可以取相同元素,树枝上可以取相同元素。
used[i - 1] == true,说明同一树枝nums[i - 1]使用过
used[i - 1] == false,说明同一树层nums[i - 1]使用过
如果同一树层nums[i - 1]使用过则直接跳过
class Solution(object):
def permuteUnique(self, nums):
self.path=[]
self.res=[]
self.used=[False]*len(nums)
nums.sort()
self.back(nums)
return self.res
def back(self,nums):
if len(self.path)==len(nums):
self.res.append(self.path[:])
return
for i in range(len(nums)):
if i>0 and nums[i]==nums[i-1] and self.used[i-1]==False:
continue
if self.used[i]==False:
self.used[i]=True
self.path.append(nums[i])
self.back(nums)
self.used[i]=False
self.path.pop()
定义一个set记录本层元素是否重复使用,新的一层set都会重新定义(清空),所以要知道set只负责本层
class Solution(object):
def findSubsequences(self, nums):
self.path=[]
self.res=[]
self.back(nums,0)
return self.res
def back(self,nums,start):
if len(self.path)>1:
self.res.append(self.path[:])
uset=set()
for i in range(start,len(nums)):
if (len(self.path)!=0 and nums[i]<self.path[-1]) or nums[i] in uset:
continue
uset.add(nums[i])
self.path.append(nums[i])
self.back(nums,i+1)
self.path.pop()
终止条件是:我们回溯遍历的过程中,遇到的机场个数,如果达到了(航班数量+1),那么我们就找到了一个行程,把所有航班串在一起了。
class Solution(object):
def findItinerary(self, tickets):
from collections import defaultdict
dic=defaultdict(list)
for item in tickets:
dic[item[0]].append(item[1])
for air in dic:
dic[air].sort()
self.path=['JFK']
self.back(tickets,dic,'JFK')
return self.path
def back(self,tickets,dic,start):
if len(self.path)==len(tickets)+1:
return True
for _ in dic[start]:
end=dic[start].pop(0)
self.path.append(end)
if self.back(tickets,dic,end):
return True
self.path.pop()
dic[start].append(end)
判断同列,45度,135度
class Solution(object):
def solveNQueens(self, n):
self.res=[]
self.chess=[['.']*n for _ in range(n)]
self.back(n,0)
return self.res
def back(self,n,row):
if row==n:
tmp_res=[]
for tmp in self.chess:
tmp_str=''.join(tmp)
tmp_res.append(tmp_str)
self.res.append(tmp_res)
return
for col in range(n):
if self.isvaild(row,col,n):
self.chess[row][col]='Q'
self.back(n,row+1)
self.chess[row][col]='.'
def isvaild(self,row,col,n):
for i in range(row):
if self.chess[i][col]=='Q':return False
i=row-1
j=col-1
while i>=0 and j>=0:
if self.chess[i][j]=='Q':return False
i-=1
j-=1
i=row-1
j=col+1
while i>=0 and j<n:
if self.chess[i][j]=='Q':return False
i-=1
j+=1
return True
判断行,列,小方块
class Solution(object):
def solveSudoku(self, board):
self.back(board)
def back(self,board):
for i in range(len(board)):
for j in range(len(board[0])):
if board[i][j]=='.':
for k in range(1,10):
if self.isvalid(i,j,k,board):
board[i][j]=str(k)
if self.back(board):return True
board[i][j]='.'
return False
return True
def isvalid(self,row,col,k,board):
for i in range(9):
if board[i][col]==str(k):return False
for j in range(9):
if board[row][j]==str(k):return False
stratrow=(row/3)*3
startcol=(col/3)*3
for i in range(stratrow,stratrow+3):
for j in range(startcol,startcol+3):
if board[i][j]==str(k):return False
return True
class Solution(object):
def totalNQueens(self, n):
self.res=0
self.chess=[['.']*n for _ in range(n)]
self.back(n,0)
return self.res
def back(self,n,row):
if row==n:
self.res+=1
return
for col in range(n):
if self.isvalid(row,col,n):
self.chess[row][col]='Q'
self.back(n,row+1)
self.chess[row][col]='.'
def isvalid(self,row,col,n):
for i in range(row):
if self.chess[i][col]=='Q':return False
i=row-1
j=col-1
while i>=0 and j>=0:
if self.chess[i][j]=='Q':return False
i-=1
j-=1
i=row-1
j=col+1
while i>=0 and j<n:
if self.chess[i][j]=='Q':return False
i-=1
j+=1
return True