CodeTop整理-回溯篇

目录

46. 全排列

47. 全排列 II

22. 括号生成

39. 组合总和

51. N皇后

40. 组合总和 II

78. 子集

37. 解数独

131. 分割回文串

93. 复原IP地址

79. 单词搜索

44. 通配符匹配

77. 组合


46. 全排列
# 46. 全排列
# 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
# 输入:nums = [1,2,3]
# 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

from typing import List
class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        ans=[]
        path=[]
        valid=[False]*len(nums)
        def dfs(h):
            if(h==len(nums)):
                ans.append(path[::])
                return

            for i in range(len(nums)):
                if not valid[i]:
                    valid[i]=True
                    path.append(nums[i])
                    dfs(h+1)
                    valid[i]=False
                    path.pop()
        dfs(0)
        return ans

nums = [1,2,3]
s=Solution()
r=s.permute(nums)
print(r)
47. 全排列 II
# 47. 全排列 II
# 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
# 输入:nums = [1,1,2]
# 输出:
# [[1,1,2],
#  [1,2,1],
#  [2,1,1]]


from typing import List
class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        valid=[False]*len(nums)
        path=[]
        res=[]
        nums.sort()
        def dfs(h):
            if(h==len(nums)):
                res.append(path[::])
                print(path)
                return
            for i in range(len(nums)):
                if(i>0 and nums[i-1]==nums[i] and valid[i-1]):
                    continue
                if  not valid[i]:
                    valid[i]=True
                    path.append(nums[i])
                    dfs(h+1)
                    valid[i]=False
                    path.pop()
        dfs(0)
        return res
# nums = [1,2,3]
nums = [1,1,2]
s=Solution()
r=s.permuteUnique(nums)
print(r)
22. 括号生成
rom typing import List
# 这种方法超时了
# class Solution:
#     def generateParenthesis(self, n: int) -> List[str]:
#         res=[]
#         t=[]
#         s=['(',')']*n
#         valid=[False]*2*n
#         def is_valid(s1):   #判断有效括号
#             b=0
#             for c in s1:
#                 if c=='(':
#                     b+=1
#                 else:
#                     b-=1
#                 if b<0:
#                     return False
#             return b==0
#
#         def dfs(h):      #排列组合
#             if(h==2*n):
#                 s1=''.join(t)
#                 if(is_valid(s1)):
#                     res.append(s1)
#                 return
#
#             for i in range(len(s)):
#                 if not valid[i] :
#                     valid[i]=True
#                     t.append(s[i])
#                     dfs(h+1)
#                     t.pop()
#                     valid[i] = False
#         dfs(0)
#         return list(set(res))

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        res=[]
        t=[]
        def is_valid(s1):   #判断有效括号
            b=0
            for c in s1:
                if c=='(':
                    b+=1
                else:
                    b-=1
                if b<0:
                    return False
            return b==0

        def dfs(h):      #排列组合
            if(h==2*n):
                s1=''.join(t)
                if(is_valid(s1)):
                    res.append(s1)
                return

            for i in '()':
                t.append(i)
                dfs(h+1)
                t.pop()
        dfs(0)
        return list(set(res))
s=Solution()
r=s.generateParenthesis(3)
print(r)

39. 组合总和
# 39. 组合总和
# 给你一个 无重复元素 的整数数组candidates 和一个目标整数target,找出candidates中可以使数字和为目标数target 的 所有不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
#
# candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
#
# 对于给定的输入,保证和为target 的不同组合数少于 150 个。
# 输入:candidates = [2,3,6,7], target = 7
# 输出:[[2,2,3],[7]]
# 解释:
# 2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
# 7 也是一个候选, 7 = 7 。
# 仅有这两种组合。

class Solution:
    # def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
    def combinationSum(self, candidates, target):
        ans=[]
        def dfs(s,target,t):
            if target==0:
                ans.append(t)
            if target<0:
                return

            for i in range(s,len(candidates)):
                if i>0 and candidates[i-1]==candidates[i]:
                    continue
                dfs(i,target-candidates[i],t+[candidates[i]])
        dfs(0,target,[])
        return ans
s=Solution()
candidates = [2,3,6,7]
target = 7
r=s.combinationSum(candidates,target)
print(r)
51. N皇后
# 51. N 皇后
# 按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
#
# n皇后问题 研究的是如何将 n个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
#
# 给你一个整数 n ,返回所有不同的n皇后问题 的解决方案。
#
# 每一种解法包含一个不同的n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
#
# 输入:n = 4
# 输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
# 解释:如上图所示,4 皇后问题存在两个不同的解法。


#按行开始遍历,每次选中某列;
#声明3个集合,c记录已经遍历过的行,d1记录满足i-j斜线的对角线;d2记录满足i+j的斜线

from typing import List
class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        res=[]
        q=[-1]*n
        t=['.']*n

        c=set()
        d1=set()
        d2=set()
        def gen_board():
            board=[]
            for k in range(n):
                t[q[k]]='Q'
                board.append(''.join(t))
                t[q[k]]='.'
            return board

        def dfs(i):
            if i==n:
                print(q)
                board=gen_board()
                res.append(board)
            else:
                for j in range(n):
                    if j in c or i+j in d1 or i-j in d2:
                        continue
                    q[i]=j
                    c.add(j)
                    d1.add(i+j)
                    d2.add(i-j)
                    dfs(i+1)
                    c.remove(j)
                    d1.remove(i+j)
                    d2.remove(i-j)
        dfs(0)
        return res

s=Solution()
r=s.solveNQueens(4)
print(r)
40. 组合总和 II
# 40. 组合总和 II
# 给定一个候选人编号的集合candidates和一个目标数target,找出candidates中所有可以使数字和为target的组合。
# candidates中的每个数字在每个组合中只能使用一次。
# 注意:解集不能包含重复的组合。
# 输入: candidates = [10,1,2,7,6,1,5], target = 8,
# 输出:
# [
# [1,1,6],
# [1,2,5],
# [1,7],
# [2,6]
# ]


class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()
        ans=[]
        t=[]
        def dfs(s,target):
            if target==0:
                ans.append(t[::])
                return
            if target<0:
                return 
            for i in range(s,len(candidates)):
                if(i>s and candidates[i-1]==candidates[i]):
                    continue
                t.append(candidates[i])
                dfs(i+1,target-candidates[i])
                t.pop() 
        dfs(0,target)
        return ans 
78. 子集
# 78. 子集
# 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
# 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
# 输入:nums = [1,2,3]
# 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

from typing import List
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        res=[]
        t=[]

        def dfs(h):
            res.append(t[::])
            for i in range(h,len(nums)):
                if(i>0 and nums[i-1]==nums[i]):
                    continue
                t.append(nums[i])
                dfs(i+1)
                t.pop()
        dfs(0)
        return res

nums = [1,2,3]
s=Solution()
r=s.subsets(nums)
print(r)
37. 解数独
# 1、space 记录空格数的pair对,及对应的位置(i,j)
# 2、row[9][9] 标识行已经被添加的数
# 3、col[9][9] 标识列已经被添加的数
# 4、block[3][3][9] 标识控制块已经被添加的数
# 5、遍历一遍board,初始化space,row,col,block

class Solution:
    # def solveSudoku(self, board: List[List[str]]) -> None:
    #     """
    #     Do not return anything, modify board in-place instead.
    #     """
    def solveSudoku(self, board) :
        def dfs(n):
            nonlocal valid
            if(n==len(space)):
                valid=True
                return
            i,j=space[n]

            for digit in range(9):
                if(not row[i][digit] and not col[j][digit] and not block[i//3][j//3][digit]):
                    row[i][digit] = col[j][digit] = block[i//3][j//3][digit]=True
                    board[i][j]=str(digit+1)
                    dfs(n+1)
                    row[i][digit] = col[j][digit] = block[i//3][j//3][digit] = False
                if valid:
                    return

        space = []
        row = [[False]*9 for _ in range(9)]
        col = [[False]*9 for _ in range(9)]
        block = [[[False]*9 for i in range(3)] for j in range(3)]
        valid = False

        for i in range(9):
            for j in range(9):
                if(board[i][j]=='.'):
                    space.append((i,j))
                else:
                    digit=int(board[i][j])-1
                    row[i][digit] = True
                    col[j][digit] = True
                    block[i//3][j//3][digit] = True
        dfs(0)
        # print(board)
131. 分割回文串
# 131. 分割回文串
# 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
# 回文串 是正着读和反着读都一样的字符串。
# 输入:s = "aab"
# 输出:[["a","a","b"],["aa","b"]]
from typing import List
class Solution:
    def partition(self, s: str) -> List[List[str]]:
        n=len(s)
        f=[[True]*n for i in range(n)]

        for i in range(n-1,-1,-1):
            for j in range(i,n):
                f[i][j]=f[i+1][j-1] and s[i]==s[j]
        print(f)

        ans=[]
        t=[]
        def dfs(i):
            if i==len(s):
                ans.append(t[::])
            for j in range(i,len(s)):
                if f[i][j]:
                    t.append(s[i:j+1])
                    dfs(j+1)
                    t.pop()
        dfs(0)
        return ans
s=Solution()
s1 = "aab"
r=s.partition(s1)
print(r)
93. 复原IP地址
# 93. 复原 IP 地址
# 有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。
#
# 例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。
# 给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
#
# 输入:s = "25525511135"
# 输出:["255.255.11.135","255.255.111.35"]

from typing import List
class Solution:
    def restoreIpAddresses(self, s: str) -> List[str]:
        for c in s:
            if not (c in '0123456789'):
                return []
        res=set()
        t=[]
        def is_valid(tmp):
            for c in tmp:
                if c.startswith('0') and len(c)>1:
                    return False
                if int(c)<0 or int(c)>255:
                    return False
            return True


        def dfs(b,h):
            if(h==4):
                if(b!=len(s)):
                    return
                if(is_valid(t)):
                    res.add('.'.join(t))
                return

            for i in range(b+1,len(s)+1):
                t.append(s[b:i])
                dfs(i,h+1)
                t.pop()

        dfs(0,0)
        return list(res)

s1 = "25525511135"
s=Solution()
r=s.restoreIpAddresses(s1)
print(r)
79. 单词搜索
# 79. 单词搜索
#
# 给定一个m x n 二维字符网格board 和一个字符串单词word 。如果word 存在于网格中,返回 true ;否则,返回 false 。
#
# 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
#
# 输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
# 输出:true

class Solution:
    # def exist(self, board: List[List[str]], word: str) -> bool:
    def exist(self, board, word) :

        def dfs(h,i,j):
            if(h==len(word)):
                return True
            valid=False
            if i>=0 and i<len(board) and j >=0 and j <len(board[0]) and not flag[i][j] and word[h]==board[i][j]:
                flag[i][j] = True
                valid=dfs(h+1,i+1,j) or dfs(h+1,i-1,j) or dfs(h+1,i,j-1) or dfs(h+1,i,j+1)
                flag[i][j]=False
            return valid

        find=False
        for i in range(len(board)):
            for j in range(len(board[0])):
                flag = [[False] * len(board[0]) for i in range(len(board))]
                find=dfs(0,i,j)
                if(find):
                    return True
        return find

# board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]]
# word = "ABCCED"
# board = [["a","b"],["c","d"]]
# word = "acdb"
board =[["A","B","C","E"],["S","F","E","S"],["A","D","E","E"]]
word ="ABCESEEEFS"
s=Solution()
r=s.exist(board,word)
print(r)
44. 通配符匹配
# 44. 通配符匹配
# 给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配。
# '?' 可以匹配任何单个字符。
# '*' 可以匹配任意字符串(包括空字符串)。
# 两个字符串完全匹配才算匹配成功。
#
# 说明:
#
# s可能为空,且只包含从a-z的小写字母。
# p可能为空,且只包含从a-z的小写字母,以及字符?和*。
#
# 输入:
# s = "aa"
# p = "a"
# 输出: false
# 解释: "a" 无法匹配 "aa" 整个字符串。

# class Solution:    #超时
#     def isMatch(self, s: str, p: str) -> bool:
#
#         if len(s) == 0 and len(p) == 0:
#             return True
#         if len(s) == 0 :
#             i=0
#             while(i<len(p)):
#                 if p[i]!='*':
#                     break
#                 i+=1
#             if(i==len(p)):
#                 return True
#             return False
#         if len(p) == 0:
#             return False
#
#         if p[0] == '*':
#             return self.isMatch(s, p[1:]) or self.isMatch(s[1:], p)
#         elif (s[0] == p[0] or p[0] == '?'):
#             return self.isMatch(s[1:], p[1:])
#         else:
#             return False

# class Solution:   #超出时限
#     def isMatch(self, s: str, p: str) -> bool:
#
#         if len(s) == 0 and len(p) == 0:
#             return True
#         if len(p) == 0:
#             return False
#         # 判断是否为全*
#         i = 0
#         while (i < len(p)):
#             if (p[i] != '*'):
#                 break
#             i += 1
#         print(s, p,i)
#         if (i == len(p)):
#             return True
#
#         if len(s) == 0:
#             return False
#
#         if i > 0 and p[i - 1] == '*':
#             return self.isMatch(s[1:], p[i - 1:]) or self.isMatch(s, p[i:])
#         if (s[0] == p[0] or p[0] == '?'):
#             return self.isMatch(s[1:], p[1:])
#         return False


class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        f=[[False]*(len(p)+1) for i in range(len(s)+1)]
        f[0][0]=True
        for j in range(1,len(p)+1):
            if p[j-1]!='*':
                break
            f[0][j]=True

        for i in range(1,len(s)+1):
            for j in range(1,len(p)+1):
                if  s[i-1]==p[j-1] or p[j-1]=='?':
                    f[i][j]=f[i-1][j-1]
                elif p[j-1]=='*':
                    f[i][j]=f[i][j-1] or f[i-1][j]

        return f[-1][-1]


s=Solution()
s1="adceb"
p="*a*b"
r=s.isMatch(s1,p)
print(r)
77. 组合
# 77. 组合
# 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
# 你可以按 任何顺序 返回答案。
# 输入:n = 4, k = 2
# 输出:
# [
#   [2,4],
#   [3,4],
#   [2,3],
#   [1,2],
#   [1,3],
#   [1,4],
# ]


from typing import List
class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        res=[]
        t=[]
        def dfs(s,k,n):
            if len(t)==k:
                res.append(t[::])
                return
            if len(t)>k:
                return

            for i in range(s,n):
                t.append(i+1)
                dfs(i+1,k,n)
                t.pop()
        dfs(0,k,n)
        return res

n = 4
k = 2
s=Solution()
r=s.combine(n,k)
print(r)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值