回溯算法leetcode

回溯算法可以解决的问题:组合问题,切割问题,子集问题排列问题,棋盘问题

回溯算法是对树形或者图形结构执行一次深度优先遍历,实际上类似枚举的搜索尝试过程,在遍历的过程中寻找问题的解。

深度优先遍历有个特点:当发现已不满足求解条件时,就返回,尝试别的路径。此时对象类型变量就需要重置成为和之前一样,称为「状态重置」。

许多复杂的,规模较大的问题都可以使用回溯法,有「通用解题方法」的美称。实际上,回溯算法就是暴力搜索算法,它是早期的人工智能里使用的算法,借助计算机强大的计算能力帮助我们找到问题的解。

组合问题

39. 组合总和

给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。
candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是唯一的。 
class Solution(object):
    def combinationSum(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        nums = sorted(candidates)
        res = []
        def recursive(idx, targ, cur):
            for i in range(idx, len(nums)):
                ni = nums[i]
                if ni < targ:
                    recursive(i, targ-ni, cur+[ni])
                else:
                    if ni == targ:
                        res.append(cur+[ni])
                    break
        recursive(0, target, [])
        return res

40. 组合总和 II

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用一次。

注意:解集不能包含重复的组合。 
class Solution(object):
    def combinationSum2(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        nums = sorted(candidates)
        res = []
        def recursive(idx, targ, cur):
            for i in range(idx, len(candidates)):
                ni = nums[i]
                if ni < targ:
                    if i == idx or ni != nums[i-1]:
                        recursive(i+1, targ-ni, cur+[ni])
                else:
                    if ni == targ:
                        res.append(cur+[ni])
                    break
        recursive(0, target, [])
        return res

 216. 组合总和 III   LeetCode-python 216.组合总和 III - 简书

找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
说明:所有数字都是正整数。
解集不能包含重复的组合。 
class Solution(object):
    def combinationSum3(self, k, n):
        """
        :type k: int
        :type n: int
        :rtype: List[List[int]]
        """
        res = []
        def recursive(k, n, index, path):
            if k == 0 or n < 0:
                if n == 0: 
                    res.append(path)
                return
            for i in range(index, 10):
                recursive(k-1, n-i, i+1, path+[i])
        recursive(k, n, 1, [])
        return res

77. 组合

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
class Solution(object):
    def combine(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: List[List[int]]
        """
        def recursive(start, end, k, cur, result):
            if len(cur) == k:
                result.append(cur)
                return None
            for i in range(start,end+1):
                recursive(i+1,end,k,cur+[i],result)
            return None

        if k > n:
            return []
        res = []
        recursive(1,n,k,[],res)
        return res

排列问题

46. 全排列

给定一个不含重复数字的数组nums ,返回其所有可能的全排列 。你可以按任意顺序返回答案。
class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        res = []
        path = []
        def backtrack(nums, path):
            if len(path) == len(nums):
                res.append(path)
            for i in range(len(nums)):
                if nums[i] in path:
                    continue
                backtrack(nums, path+[nums[i]])
        backtrack(nums, [])
        return res

47. 全排列 II

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
class Solution(object):
    def permuteUnique(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        nums.sort()
        res = []
        def dfs(nums, path):
            if not nums:
                res.append(path)
                return 
            for i in range(len(nums)):
                if i>0 and nums[i]==nums[i-1]:
                    continue
                dfs(nums[:i]+nums[i+1:], path+[nums[i]])
        dfs(nums, [])
        return res


子集问题

78. 子集


 LeetCode 78 子集 python_孤行-CSDN博客

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
class Solution(object):
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = [[]]
        for i in range(len(nums)-1, -1, -1):
            for subres in res[:]: #切片的作用是使得res不变
                res.append(subres+[nums[i]])
    
        return res
方法二:创建一个内函数 通过遍历start到nums的长度 遍历递归调用函数 然后加入到res中
class Solution(object):
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = []
        def temp(start, num):
            res.append(num)
            for i in range(start, len(nums)):
                temp(i+1, num+[nums[i]])
        temp(0, [])
        return res

90. 子集 II

class Solution(object):
    def subsetsWithDup(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        nums.sort() # sort the nums to find the equivalent nums
        res = []
        def temp(start, num):
            res.append(num)
            for i in range(start, len(nums)):
                if i>start and nums[i] == nums[i-1]:
                    continue # pass the same number
                else:
                    temp(i+1, num+[nums[i]])
        temp(0, [])
        return res

剑指 Offer 38. 字符串的排列

青蛙跳台阶的思路一样,无论给定的字符串长度多少,其排列出来的组合样式均可以分解为“第一个字符+剩下的字符”的样式。可以通过遍历分别赋予第一位上不同的字符,那“剩下的字符”又可以如上分解。

(此解法特别慢,需要优化)

class Solution(object):
    def permutation(self, s):
        """
        :type s: str
        :rtype: List[str]
        """
        l = []
        if len(s) <= 1:
            return [s]
        n = len(s)
        for i in range(n):
            for j in self.permutation(s[:i]+s[i+1:]):
                temp = s[i] + str(j)
                if temp not in l:
                    l.append(temp)
        return l

784. 字母大小写全排列

17. 电话号码的字母组合

class Solution(object):
    def letterCombinations(self, digits):
        """
        :type digits: str
        :rtype: List[str]
        """
        # 创建字母对应的字符列表的字典
        dic = {2: ['a', 'b', 'c'],
               3: ['d', 'e', 'f'],
               4: ['g', 'h', 'i'],
               5: ['j', 'k', 'l'],
               6: ['m', 'n', 'o'],
               7: ['p', 'q', 'r', 's'],
               8: ['t', 'u', 'v'],
               9: ['w', 'x', 'y', 'z'],
               }
        # 存储结果的数组
        res = []
        if len(digits) == 0: 
            return []
        # 递归出口,当递归到最后一个数的时候result拿到结果进行for循环遍历
        if len(digits) == 1:
            return dic[int(digits[0])]
        # 递归调用
        result = self.letterCombinations(digits[1:])
        # result是一个数组列表,遍历后字符串操作,加入列表
        for r in result:
            for j in dic[int(digits[0])]:
                res.append(j + r)
        return res

22. 括号生成  (回溯法(其实也是一种DFS))

class Solution(object):
    def generateParenthesis(self, n):
        """
        :type n: int
        :rtype: List[str]
        """
        res = []
        def backtrack(prefix, left, right):
            if len(prefix) == 2 * n:
                res.append(prefix)
                return
            # 控制左括号的数量,避免出现'(((((('的情况
            if left < n:
                backtrack(prefix + '(', left + 1, right)
            # 控制右括号的数量
            if right < left:
                backtrack(prefix + ')', left, right + 1)
        backtrack('', 0, 0)
        return res

79. 单词搜索 (深度优先搜索,搜索过的地方要有标记,以免重复搜索)

class Solution(object):
    def exist(self, board, word):
        """
        :type board: List[List[str]]
        :type word: str
        :rtype: bool
        """
        n, m = len(board), len(board[0])
        
        def dfs(board, x, y, word):
            if not word:
                return True
            if 0<=x<n and 0<=y<m and board[x][y] == word[0] and board[x][y]!='#':
                t, board[x][y] = board[x][y], '#'    
                res =  dfs(board, x, y+1, word[1:]) or dfs(board, x, y-1, word[1:]) or dfs(board, x+1, y, word[1:]) or dfs(board, x-1, y, word[1:])
                board[x][y] = t
                return res
                         
            return False
        for i in range(n):
            for j in range(m):
                if dfs(board,i,j,word):
                    return True
        return False

113. 路径总和 II

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def pathSum(self, root, targetSum):
        """
        :type root: TreeNode
        :type targetSum: int
        :rtype: List[List[int]]
        """
        res = []
        def dfs(target, root, path):
            if not root.left and not root.right:
                if target == root.val:
                    res.append(path+[root.val])
            if root.left:
                dfs(target-root.val, root.left, path+[root.val])
            if root.right:
                dfs(target-root.val, root.right, path+[root.val])
        if not root:
            return []
        dfs(targetSum, root, [])
        return res

131. 分割回文串

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
class Solution:
    def partition(self, s: str) -> List[List[str]]:
        length = len(s)
        res = []
        def dfs(start, tmp):
            if start >= length:
                res.append(tmp)
            for i in range(start, length):
                substring = s[start:i + 1]
                if substring == substring[::-1]: #子串是回文串
                    dfs(i + 1, tmp+[substring])                 
        dfs(0, [])
        return res

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值