回溯算法:往回探一下,得到所有解

1. 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
在这里插入图片描述
示例:

输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].

说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

class Solution:
    def letterCombinantionsDFS(self, digits, letters, level, out, res):
        if level == len(digits):
            res.append(out)
        else:
            str = letters[int(digits[level]) - int('2')]
            for i in range(len(str)):
                out += str[i]
                self.letterCombinantionsDFS(digits, letters, level+1, out, res)
                out = out[:-1]

    def letterCombinations(self, digits):
        """
        :type digits: str
        :rtype: List[str]
        """
        res = []
        if len(digits) == 0:
            return res
        letters = ["abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"]
        self.letterCombinantionsDFS(digits, letters, 0, '', res)
        return res

2. 生成括号

给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。

例如,给出 n = 3,生成结果为:

[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]

class Solution:
    def generateParenthesis(self, n):
        """
        :type n: int
        :rtype: List[str]
        """
        res = []
        def trackback(s='', left=0, right=0):
            if len(s) == 2 * n:
                return res.append(s)
            if left < n:
                trackback(s + '(', left+1, right)
            if right < left:
                trackback(s + ')', left, right+1)
        trackback()
        return res

3. 全排列

给定一个没有重复数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]
输出:

[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]
  • 解法一
class Solution:
    def computer(self, nums, res, begin, end):
        if begin == end:
            res.append(nums.copy())
        else:
            for i in range(begin, end+1):
                nums[begin], nums[i] = nums[i], nums[begin]
                self.computer(nums, res, begin+1, end)
                nums[begin], nums[i] = nums[i], nums[begin]

    def permute(self, nums: List[int]) -> List[List[int]]:
        res = []
        if len(nums) == 0:
            return res
        self.computer(nums, res, 0, len(nums)-1)
        return res
  • 解法二:
    参考:https://blog.csdn.net/whdAlive/article/details/80422217
class Solution {
        public List<List<Integer>> permute(int[] nums) {
            List<List<Integer>> list = new ArrayList<>();

            backtrack(list,new ArrayList<>(),nums);
            return list;
        }
        private void backtrack(List<List<Integer>> list, List<Integer> temp,int[] nums){
            if(temp.size() == nums.length){
                list.add(new ArrayList<>(temp));
            }else{
                for(int i=0;i<nums.length;i++){
                    if(temp.contains(nums[i]))
                        continue;
                    temp.add(nums[i]);
                    backtrack(list,temp,nums);
                    temp.remove(temp.size()-1);
                }
            }
        }
    }

如果是python,有点小变化。

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        def dfs(nums, tmp, res):
            if len(tmp) == len(nums):
                res.append(copy.deepcopy(tmp))
            else:
                for i in range(len(nums)):
                    if nums[i] in tmp:
                        continue
                    tmp.append(nums[i])
                    dfs(nums, tmp, res)
                    tmp.pop(len(tmp) - 1)

        res = []
        tmp = []
        dfs(nums, tmp, res)
        return res

解法三:

cclass Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        # 回溯算法,复杂度较高,因为回溯算法就是暴力穷举,遍历整颗决策树是不可避免的
        res = []
        def backtrack(path=[], selects=nums):
            if not selects:
                res.append(path[:])
                return
            for i in range(len(selects)):
                path.append(selects[i])
                backtrack(path, selects[:i] + selects[i+1:])
                path.pop()
        backtrack()
        return res

作者:jue-qiang-zha-zha
链接:https://leetcode-cn.com/problems/permutations/solution/46-quan-pai-lie-hui-su-fa-by-jue-qiang-z-jym3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

3.2 全排列(剪枝)

在这里插入图片描述

参考:https://leetcode-cn.com/problems/permutations-ii/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liwe-2/

from typing import List
class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        def dfs(nums, size, depth, path, used, res):
            if depth == size:
                res.append(path.copy())
                return
            for i in range(size):
                if not used[i]:
                    if i > 0 and nums[i] == nums[i - 1] and not used[i - 1]:
                        continue
                    used[i] = True
                    path.append(nums[i])
                    dfs(nums, size, depth + 1, path, used, res)
                    used[i] = False
                    path.pop()
        size = len(nums)
        if size == 0:
            return []
        nums.sort()
        used = [False] * len(nums)
        res = []
        dfs(nums, size, 0, [], used, res)
        return res

4. 组合

给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。

示例:

输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]

class Solution:
    def _combine(self, n, k, start, num, res):
        if len(num) == k:
            res.append(num.copy())
            return
        for i in range(start, n+1):
            num.append(i)
            self._combine(n, k, i+1, num, res)
            num.pop()
        
    def combine(self, n: int, k: int) -> List[List[int]]:
        res = []
        if n <= 0 or k <= 0 or n < k:
            return res
        num = []
        self._combine(n, k, 1, num, res)
        return res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thomas_Cai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值