回溯算法总结(一)组合问题

回溯算法总结


`


前言

主要借鉴【代码随想录】,大部分为笔记,由于自己学习整理。


一、回溯算法是什么

回溯算法也可叫回溯搜索法,它是⼀种搜索的⽅式;
回溯是递归的副产品,只要有递归就会有回溯。本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法⾼效⼀些,可以加⼀些剪枝的操作,但也改不了回溯法就是穷举的本质。

回溯法解决的问题都可以抽象为树形结构,因为回溯法解决的都是在集合中递归查找⼦集,集合的⼤⼩就构成了树的宽度,递归的深度,都构成的树的深度。
递归就要有终⽌条件,所以必然是⼀颗⾼度有限的树(N叉树)

二、回溯算法主要解决的问题

1)组合问题:N个数⾥⾯按⼀定规则找出k个数的集合
2)切割问题:⼀个字符串按⼀定规则有⼏种切割⽅式
3)⼦集问题:⼀个N个数的集合⾥有多少符合条件的⼦集
4)排列问题:N个数按⼀定规则全排列,有⼏种排列⽅式
5)棋盘问题:N皇后,解数独等等

三、回溯算法三部曲

  • 递归函数的返回值以及参数
  • 回溯函数终⽌条件
  • 单层搜索的过程

四、回溯算法模板

def backtracking(参数):
	if (终止条件):
		存放结果
		return
	for (本层集合中元素((树中节点孩⼦的数量就是集合的⼤⼩)):
		处理节点
		backtracking(路径,选择列表)
		回溯,撤销处理结果

五、一些例子

lc77

5.1 lc77 组合

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。

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

class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        ans = []
        temp = []
        #参数n,k,还有startIndex,用于记录从哪里开始遍历,题目是任意顺序
        #即在集合[1,2,3,4]取1之后,下⼀层递归,就要在[2,3,4]中取数了,那么下⼀
        #层递归如何知道从[2,3,4]中取数呢,靠的就是startIndex。
        def backtrack(n, k, startIndex):
            if len(temp) == k:
                ans.append(temp[:])
                return
    #for循环选择的起始位置之后的元素个数已经不⾜我们需要的元素个数了
    #那么就没有必要搜索
            for i in range(startIndex, n - (k - len(temp)) + 2):
                temp.append(i)
                backtrack(n, k, i+1)
                temp.pop()
        backtrack(n, k, 1)
        return ans

剪枝操作:
1、已选的元素个数,len(temp)
2、还需要选的元素个数,k - len(temp)
3、在集合n中,至多要从该起始位置 到n - (k - len(temp)) + 1,开始遍历。·(组合问题),上面里面+2是因为边界要+1.
(因为for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了)

5.2 lc216组合总和 III

lc216
找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:

  • 只使用数字1到9
  • 每个数字 最多使用一次

返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。

class Solution:
    def combinationSum3(self, k: int, n: int) -> List[List[int]]:
        ans = []
        temp = []
        def backtrack(n, k, sum, startIndex):
            if sum > n:
                return
            if len(temp) == k and sum == n:
                ans.append(temp[:])
            for i in range(startIndex, 9 - (k - len(temp))+2):
                sum += i
                temp.append(i)
                backtrack(n, k, sum, i+1) #使用i+1调整startIndex
                temp.pop()
                sum -= i 
        backtrack(n, k, 0, 1)
        return ans

5.3 lc17. 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
在这里插入图片描述

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        if not digits:
            return list()
        
        phoneMap = {
            "2": "abc",
            "3": "def",
            "4": "ghi",
            "5": "jkl",
            "6": "mno",
            "7": "pqrs",
            "8": "tuv",
            "9": "wxyz",
        }
        def backtrack(index: int):
            if index == len(digits):
                combinations.append("".join(combination))
            else:
                digit = digits[index]
                for letter in phoneMap[digit]:
                    combination.append(letter)
                    backtrack(index + 1)
                    combination.pop()

        combination = list()
        combinations = list()
        backtrack(0)
        return combinations
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
回溯算法是一种通过穷举所有可能的解来问题算法。它通常用于解决组合、排列、子集和搜索等问题。在回溯算法中,我们通过递归的方式尝试所有可能的选择,并在每一步进行剪枝,以避免无效的搜索。 在给出的引用中,有三个例子展示了使用回溯算法解决不同的问题。第一个例子是找出给定数组中的所有递增子序列。通过递归和剪枝的方式,我们可以找到所有满足条件的子序列。 第二个例子是生成给定字符串中的所有字母大小写组合。通过递归和剪枝的方式,我们可以生成所有可能的组合。 第三个例子是生成有效的括号组合。通过递归和剪枝的方式,我们可以生成所有满足括号匹配规则的组合。 总的来说,回溯算法是一种非常灵活和强大的算法,可以用于解决各种组合和搜索问题。在实际应用中,我们可以根据具体问题的特点来设计回溯算法的实现。 #### 引用[.reference_title] - *1* [python 回溯算法总结](https://blog.csdn.net/weixin_45548695/article/details/124146238)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [python数据结构与算法--回溯算法](https://blog.csdn.net/Melo0705/article/details/99728116)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小杜在学习

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

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

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

打赏作者

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

抵扣说明:

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

余额充值