回溯就是穷举,for循环的嵌套,有固定的结构
def track(参数,通常就是起点,结果):
if 终止条件:
return
for 遍历:
track(起点+1之类)
经典的回溯题,主要是for里面的剪枝,能将时间从336降到40
def combine77(n, k) :
def track(i,res):
if len(res)==k:
res2 = res.copy()
all.append(res2)
return
for j in range(i,n+1-k+len(res)+1):
res.append(j)
track(j+1,res)
res.pop()
all =[]
track(1,[])
return all
跟前面套路一模一样,多了和的限制条件,就可以再剪枝的时候多一层判断
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
def track(i,res):
if sum(res)>n:
return
if len(res)==k:
if sum(res)==n:
res2 = res.copy()
all.append(res2)
return
for j in range(i,10-k+len(res)+1):
res.append(j)
track(j+1, res)
res.pop()
all=[]
track(1,[])
return all
终止条件:就是长度=数字长度
回溯的点:要找到for,就是数字,不一样的点就是还要对数字对应的字符遍历,所以里面还有一层
def track(res,s):
if len(res)==len(digits):
all.append("".join(res))
return
for i in range(s,len(digits)):
tmp = dict[digits[i]]
for j in range(0,len(tmp)):
res.append(tmp[j])
track(res,i+1)
res.pop()
这么看好像上面的不对,,,嗯,,还是有点理不清楚
def track1(res,s):
if len(res)==len(digits):
all.append("".join(res))
return
tmp = dict[digits[s]]
for j in range(len(tmp)):
res.append(tmp[j])
track(res,s+1)
res.pop()
从大到小排比从小到大排快的多,72到48,因为会少很多2,2,往大找的遍历
def combinationSum39(candidates, target):
def track(sum,res,s):
if sum>=target:
if sum==target:
all.append(res.copy())
return []
for i in range(s,len(candidates)):
res.append(candidates[i])
sum = sum+candidates[i]
track(sum,res,i)
res.pop()
sum = sum-candidates[i]
all=[]
candidates = sorted(candidates,reverse=True)
track(0,[],0)
return all
与前面的题不同,多了一个去重,如果用 not in 判断,会超出时间限制
所以需要加if,注意if的判断是i>s,不是i>0,
def combinationSum40(candidates, target):
def track(sum, res, s):
if sum == target:
if res not in all:
all.append(res.copy())
return
if sum > target:
return
for i in range(s, len(candidates)):
if i > s and candidates[i] == candidates[i - 1]:
continue
sum = sum + candidates[i]
res.append(candidates[i])
track(sum, res, i + 1)
sum = sum - candidates[i]
res.pop()
all = []
candidates = sorted(candidates)
track(0, [], 0)
return all
这题一开始没想明白,以为是求所有组合,关键是遍历分割线的位置,一直到最后终止
def partition131(s):
def track(res,st):
if st==len(s):
all.append(res.copy())
return
for i in range(st+1,len(s)+1):
tmp = s[st:i]
if tmp==tmp[::-1]:
res.append(tmp)
track(res,i)
res.pop()
all = []
track([],0)
return all
跟分割回文串的思路一样 ,就是遍历分割的位置,外面加一层len判断,速度从48到40,但里面加一次不知道为什么反而更慢了,变成了52,没想明白,总感觉速度和网速有关系
def restoreIpAddresses9302( s):
def track(res,st):
if st==len(s):
if len(res)==4:
all.append(res[0]+"."+res[1]+"."+res[2]+"."+res[3])
return
if len(res)>3:
return
for i in range(st+1,len(s)+1):
tmp = s[st:i]
if len(tmp)>1 and int(tmp[0])==0:
break
if int(tmp)<256:
res.append(str(tmp))
track(res,i)
res.pop()
all = []
if len(s)>12:
return all
track([],0)
return all
if len(s)-st>(4-len(res))*3:
return
这没啥好说的就是最基本的回溯
def subsets(self, nums: List[int]) -> List[List[int]]:
def track(res,i):
#if res not in all:
all.append(res.copy())
for j in range(i,len(nums)):
res.append(nums[j])
track(res,j+1)
res.pop()
all = []
track([],0)
return all
比前面的题多了一个去重,同层一样的话就跳过
def subsetsWithDup90(nums):
def track(res, i):
if res not in all:
all.append(res.copy())
for j in range(i, len(nums)):
if j>i and nums[j]==nums[j-1]:
continue
res.append(nums[j])
track(res, j + 1)
res.pop()
all = []
nums = sorted(nums)
track([], 0)
return all
感觉这题的关键是先排序,如果不排序所有的找完再排序找最小组合,会超时,,先排序,有一个结果就退出
刚开始通过删增的方式,要注意插入的位置,避免重复
题解用的use感觉更方便一点,思路差不多,好像也没有抓住这道题的主要方法
def findItinerary332(tickets):
def track(rest,res,cur):
if len(rest)==0:
res.append(cur)
if res not in all:
all.append(res.copy())
res.pop()
return
for i in range(len(rest)):
#if i==1 and cur=="JFK":
if len(rest)==5:
print(cur)
tmp = rest[i]
if tmp[0]==cur:
res.append(cur)
#res.append(tmp[1])
rest.pop(i)
track(rest,res,tmp[1])
if len(all)>0:
break
rest.insert(i,tmp)
cur = res.pop()
tickets = sorted(tickets)
rest = tickets
all=[]
track(rest, [], "JFK")
all = sorted(all)
print(all)
return all[0]
#(all)
终点是判断isvaild,for遍历是对列,自己写是list转str,应该直接写成str,但发现写成str也没有快
def solveNQueens51(n):
def isvaild(res,i,j):
for ki in range(n):
if res[ki][j]=="Q":
return False
if res[i][ki]=="Q":
return False
ki = i-1
kj = j-1
while(ki>-1 and kj>-1):
if res[ki][kj]=="Q":
return False
ki = ki -1
kj = kj-1
ki = i-1
kj = j+1
while(ki>-1 and kj
好难啊,真的不会,看题解都要看几遍
def solveSudoku37(board):
def isvalid(board, i, si, sj):
for ki in range(9):
if board[ki][sj]==str(i):
return False
if board[si][ki] == str(i):
return False
startRow = (si // 3) * 3
startCol = (sj // 3) * 3
for ki in range(startRow,startRow + 3):
for kj in range(startCol,startCol + 3):
if (board[ki][kj] == str(i) ):
return False
return True
def track(board):
for i in range(9):
for j in range(9):
if board[i][j]!=".":
continue
for k in range(1,10):
if isvalid(board,k,i,j):
board[i][j] = str(k)
if track(board): return True
board[i][j]="."
return False
print(board)
return True
# for i in range(9):
# res.append([0] * 9)
track(board)
print(board)
return True
回溯三部曲,终止条件,遍历的内容,按照模板写就行,