代码随想录算法训练营day24~25-回溯算法01~02

目录

1. T77:组合

2. T216:组合总和Ⅲ

3. T17:电话号码的字母组合

3.1 显式回溯

3.2 隐式回溯


1. T77:组合

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

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

提示:

  • 1 <= n <= 20

  • 1 <= k <= n

S:

以n、k和当前层起始计数(从1开始)为参数,组合中 元素个数 == k 为终止条件,不设置局部返回值

如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了

C++:

    vector<vector<int>> combine(int n, int k) {
        backtracking(n, k, 1);
        return res;
    }
private:
    vector<vector<int>> res;
    vector<int> path;
    void backtracking(int n, int k, int startIndex) {
        if (path.size() == k) {
            res.push_back(path);
            return;
        }
        // for (int i = startIndex; i <= n; ++i) {
        for (int i = startIndex; i <= n - (k - path.size()) + 1; ++i) {
            path.push_back(i);
            backtracking(n, k, i + 1);
            path.pop_back();
        }
    }

Java:

    List<List<Integer>> res;
    // List<Integer> path;
    LinkedList<Integer> path;
    public List<List<Integer>> combine(int n, int k) {
        res = new ArrayList<>();
        path = new LinkedList<>();//最初有点怀疑:这里的初始化是否能传入backtracking🚩——能!
        backtracking(n, k, 1);
        return res;
    }
    private void backtracking(int n, int k, int startIndex) {
        if (path.size() == k) {
            // res.add(path);
            res.add(new ArrayList<>(path));
            return;
        }
        // for (int i = startIndex; i <= n; ++i) {
        for (int i = startIndex; i <= n - (k - path.size()) + 1; ++i) {
            path.add(i);
            backtracking(n, k, i + 1);
            // path.remove(path.size() - 1);
            path.removeLast();
        }
    }

2. T216:组合总和Ⅲ

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

  • 只使用数字1到9

  • 每个数字 最多使用一次 

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

提示:

  • 2 <= k <= 9

  • 1 <= n <= 60

S:跟上一题一样的套路,就是终止条件不同

C++:本来是按照下面写的(能通过),但看了题解才意识到求和的过程也可以回溯~

    vector<vector<int>> combinationSum3(int k, int n) {
        backtracking(k, n, 1);
        return res;
    }
private:
    vector<vector<int>> res;
    vector<int> path;
    void backtracking(int k, int n, int startIndex) {
        if (path.size() == k) {
            if (getPathSum(path) == n) {
                res.push_back(path);
                // return;//栈溢出
            }
            return;//🚩无论是否符合都要return
        }
        for (int i = startIndex; i <= 9 - (k - path.size()) + 1; ++i) {
            path.push_back(i);
            backtracking(k, n, i + 1);
            path.pop_back();
        }
    }
    int getPathSum(vector<int> path) {
        int sum = 0;
        for (int i = 0; i < path.size(); ++i) {
            sum += path[i];
        }
        return sum;
    }

求和回溯:

    vector<vector<int>> combinationSum3(int k, int n) {
        backtracking(k, n, 0, 1);
        return res;
    }
private:
    vector<vector<int>> res;
    vector<int> path;
    void backtracking(int k, int n, int sum, int startIndex) {
        if (path.size() == k) {
            // if (getPathSum(path) == n) {
            if (sum == n) {
                res.push_back(path);
                // return;//在这里return->栈溢出
            }
            return;//无论是否符合都要return
        }
        for (int i = startIndex; i <= 9 - (k - path.size()) + 1; ++i) {
            path.push_back(i);
            backtracking(k, n, sum + i, i + 1);//隐式回溯
            path.pop_back();
        }
    }

Java:

    List<List<Integer>> res;
    LinkedList<Integer> path;
    public List<List<Integer>> combinationSum3(int k, int n) {
        res = new ArrayList<>();
        if (n == 0 || k == 0) return res;
        path = new LinkedList<>();//🚩要是没有初始化,下面.size()->NullPointerException
        backtracking(k, n, 0, 1);
        return res;
    }
    private void backtracking(int k, int targetSum, int sum, int startIndex) {
        if (path.size() == k) {
            if (sum == targetSum) {
                res.add(new LinkedList<>(path));//必须申请新的内存空间,否则都是指向同一个对象,插入结果集后又变了
            }
            return;
        }
        for (int i = startIndex; i <= 9 - (k - path.size()) + 1; ++i) {
            path.add(i);
            backtracking(k, targetSum, sum + i, i + 1);
            path.removeLast();
        }
    }

3. T17:电话号码的字母组合

T17:给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

提示:

  • 0 <= digits.length <= 4

  • digits[i] 是范围 ['2', '9'] 的一个数字。

S:自己试着敲了一遍,通过了,但还要优化

C++:

【self】下面这版虽然能通过,但是存在问题:嵌套for循环和递归终止条件功能重叠

    vector<string> res;
    string combination;
    vector<string> letterCombinations(string digits) {
        if (digits.size() == 0) return res;
        backtracking(digits, digits.size(), 0);
        return res;
    }
private:
    void backtracking(const string& digits, int length, int startIndex) {//也可以不要const和&
        if (combination.size() == length) {
            res.push_back(combination);
            return;
        }
        for (int i = startIndex; i < digits.size(); ++i) {
            int curNum = digits[i] - '0';
            string curLetters = letterMap[curNum];
            for (int j = 0; j < curLetters.size(); ++j) {
                combination.push_back(curLetters[j]);
                // backtracking(digits, length, startIndex + 1);//一度又犯傻!
                backtracking(digits, length, i + 1);
                combination.pop_back();
            }
        }
    }
    const string letterMap[10] = {
        "",//0
        "",//1
        "abc",//2
        "def",
        "ghi",//4
        "jkl",
        "mno",//6
        "pqrs",//7
        "tuv",
        "wxyz"//9
        };

3.1 显式回溯

C++:

    vector<string> res;
    string combination;
    vector<string> letterCombinations(string digits) {
        if (digits.size() == 0) return res;
        backtracking(digits, 0);
        return res;
    }
private:
    void backtracking(string digits, int curIndex) {
        if (curIndex == digits.size()) {
            res.push_back(combination);
            return;
        }
        int digit = digits[curIndex] - '0';
        string curLetters = letterMap[digit];
        for (int i = 0; i < curLetters.size(); ++i) {
            combination.push_back(curLetters[i]);
            // backtracking(digits, i + 1);//🚩栈溢出
            backtracking(digits, curIndex + 1);
            combination.pop_back();
        }
    }

Java:

    List<String> res;
    StringBuilder combination;
    public List<String> letterCombinations(String digits) {
        res = new ArrayList<>();
        if (digits == null || digits.equals("") || digits.length() == 0) return res;
        combination = new StringBuilder();
        backtracking(digits, 0);
        return res;
    }
    private void backtracking(String digits, int curIndex) {
        if (curIndex == digits.length()) {
            res.add(combination.toString());
            return;
        }
        // int curNum = curIndex - '0';//犯傻!
        int curNum = digits.charAt(curIndex) - '0';
        String curLetters = letterMap[curNum];
        for (int i = 0; i < curLetters.length(); ++i) {
            // combination.append(i);//"00","01"
            combination.append(curLetters.charAt(i));
            backtracking(digits, curIndex + 1);
            combination.deleteCharAt(combination.length() - 1);
        }
    }
    private final String[] letterMap = {
        "",
        "",
        "abc",
        "def",
        "ghi",
        "jkl",
        "mno",
        "pqrs",
        "tuv",
        "wxyz"
    };

3.2 隐式回溯

C++:

    vector<string> res;
    // string combination;
    vector<string> letterCombinations(string digits) {
        if (digits.size() == 0) return res;
        backtracking(digits, 0, "");
        return res;
    }
private:
    void backtracking(string digits, int curIndex, string s) {
        if (curIndex == digits.size()) {
            res.push_back(s);
            return;
        }
        int digit = digits[curIndex] - '0';
        string curLetters = letterMap[digit];
        for (int i = 0; i < curLetters.size(); ++i) {
            backtracking(digits, curIndex + 1, s + curLetters[i]);
        }
    }

Java:

    List<String> res;
    public List<String> letterCombinations(String digits) {
        res = new ArrayList<>();
        if (digits == null || digits.equals("") || digits.length() == 0) return res;
        backtracking(digits, 0, "");
        return res;
    }
    private void backtracking(String digits, int curIndex, String s) {
        if (curIndex == digits.length()) {
            res.add(s);
            return;
        }
        int curNum = digits.charAt(curIndex) - '0';
        String curLetters = letterMap[curNum];
        for (int i = 0; i < curLetters.length(); ++i) {
            backtracking(digits, curIndex + 1, s + curLetters.charAt(i));
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值