Leetcode 回溯算法

做题记录

组合:N个数找K个数的集合

切割:字符中有几种切割方式

子集:N个数有几个符合条件的子集

排列:N个数按规则有几种排列(组合无序,排列有序)

棋盘:N皇后、解数独···

一个元素不能重复使用,所以需要startIndex,调整下一层递归的起始位置。

void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

77. 组合

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()

216. 组合总和 III

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()

17. 电话号码的字母组合

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]

39. 组合总和

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()

40. 组合总和 II

本题中数组有重复元素,所以要对相同元素进行去重。

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()

131. 分割回文串

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()

93. 复原 IP 地址

只能切割三次,使用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

78. 子集

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()

90. 子集 II

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()

46. 全排列

设置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()

47. 全排列 II

树层上不可以取相同元素,树枝上可以取相同元素。

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()

491. 递增子序列

定义一个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()

332. 重新安排行程

终止条件是:我们回溯遍历的过程中,遇到的机场个数,如果达到了(航班数量+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)

51. N 皇后

判断同列,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

37. 解数独

判断行,列,小方块

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

52. N皇后 II

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值