leetcode刷题笔记——【回溯算法】

100 阅读2分钟

代码随想录 (programmercarl.com)

回溯算法也就是递归函数,指的都是一个函数

回溯算法理论基础

将回溯算法看作一个树,for循环就是从左到右,集合元素数量就是树的宽度;递归就是从上到下

image.png

代码模板

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

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

刷题

77. 组合

77. 组合 - 力扣(LeetCode)

最基础的回溯算法,直接套用模板就行,但要注意有一个剪枝的操作,即for循环中i的终止条件,当剩下的元素数量小于k时,就要进行终止了。

描述

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

你可以按 任何顺序 返回答案。

示例 1:

输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]

示例 2:

输入: strs = [""]
输出: [[""]]

示例 3:

输入: strs = ["a"]
输出: [["a"]]

代码

let path = []
let res = []
var combine = function(n, k) {
    res = []
    backtracking(n, k, 1)
    return res
};
const backtracking = (n, k, startIndex)=>{
    if(path.length === k){
        res.push([...path])
        return
    }
    for(let i = startIndex; i <= (n - (k-path.length) + 1); i++){  // 优化的地方
        path.push(i)
        backtracking(n, k, i+1)
        path.pop()
    }
}

216.组合总和3

216. 组合总和 III - 力扣(LeetCode)

描述

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

  • 只使用数字1到9
  • 每个数字 最多使用一次  返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

分析

  1. 每个数字只使用一次——通过递归时传递的startIndex进行控制,每次递归startIndex加一

  2. 列表内不能包含重复的组合——for循环从startIndex开始已经能够实现这个条件

  3. 需要有一个sum来计算每一次递归的所有元素之和,同时可以通过比较sum与n的大小进行剪枝

代码

let res = []
let path = []
var combinationSum3 = function(k, n) {
    res = []
    backtracking(k, n, 1, 0)
    return res
};
const backtracking = (k, n, startIndex, sum) => {
    if(sum > n){ // 剪枝1
        return
    }
    if(sum === n && path.length === k){
        res.push([...path])
    }
    for(let i = startIndex; i<= 10-(k-path.length); i++){ // 剪枝2
        path.push(i)
        backtracking(k, n, i+1, sum+i)
        path.pop()
    }
}