zoukankan      html  css  js  c++  java
  • 77. 组合

    77. 组合

    题目链接:77. 组合(中等)

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

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

    示例 1:

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

    示例 2:

    输入:n = 1, k = 1
    输出:[[1]]

    提示:

    • 1 <= n <= 20

    • 1 <= k <= n

    解题思路

    所有回溯问题都可以抽象为一个树,解决这个问题的方法就是对这棵树进行 深度优先遍历,找出所有符合条件的结果。

    回溯法模板

    来自代码随想录

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

    for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历。

    所以针对此题,当 n=4,k=2时,可以先选出1,然后从2、3、4中分别挑出一个元素,得到12、13、14。继续选出2,然后从3、4中分别挑出一个元素,得到23、24。接着选出3,然后挑出4,的得到34。最后选取4,后面没有可以挑选的元素,结束。

    代码(C++)

    class Solution {
    public:
        vector<int> path; // 用来存放符合条件结果
        vector<vector<int>> result; // 存放符合条件结果的集合
        void backTracking(int n, int k, int startIndex) {
            if(path.size() == k){
                result.push_back(path);
                return;
            }
            for (int i = startIndex; i <= n; i++) {
                path.push_back(i); // 处理节点
                backTracking(n, k, i + 1); // 递归
                path.pop_back(); // 回溯,撤销处理的节点
            }
        }
        vector<vector<int>> combine(int n, int k) {
            path.clear();
            result.clear();
            backTracking(n, k, 1);
            return result;
        }
    };

    代码(JS)

    let result = [];
    let path = [];
    const backTracking = (n, k, startIndex) => {
        if (path.length === k) {
            result.push([...path]);
            return;
        }
        for (let i = startIndex; i <= n; i++) {
            path.push(i);
            backTracking(n, k, i + 1);
            path.pop();
        }
    }
    ​
    var combine = function(n, k) {
        result = [];
        path = [];
        backTracking(n, k, 1);
        return result;
    };

    剪枝

    虽然回溯法是暴力搜索,但有时候可以通过剪枝进行优化。

    通过分析可以发现上面的代码存在一些多余的操作。对于n=4,k=2,其实我们并不用从4开始遍历,因为要选出的是两个元素,而从4开始的话,仅仅只有一个元素。另如,对于n=4,k=3,我们就不用从3开始遍历,因为要选出的是三个元素,而从3开始的话,仅仅只有两个元素。所以可以通过剪枝对此进行优化。

    一般来说,可以剪枝的地方就在递归中每一层的for循环所选择的起始位置

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

    对于每次遍历,我们相当于在[start, n]这个区间中取出k - path.size()个数,那也就是说[start, n]这个区间中至少要包含k-path.size()个数,也就是n - start + 1 >= k - path.size(),也就是start <= n - (k - path.size()) + 1,说明只要循环变量i至多从n - (k - path.size()) + 1位置开始,就可以确保下面能得到大小为k的组合。

    代码(C++)

    //剪枝优化
    class Solution {
    public:
        vector<int> path;
        vector<vector<int>> result;
        void backTracking(int n, int k, int startIndex) {
            if (path.size() == k) {
                result.push_back(path);
                return;
            }
            //n - startIndex + 1 >= k - path.size()
            //startIndex <= n - (k - path.size()) + 1
            for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) {
                path.push_back(i);
                backTracking(n, k, i + 1);
                path.pop_back();
            }
        }
    ​
        vector<vector<int>> combine(int n, int k) {
            path.clear();
            result.clear();
            backTracking(n, k, 1);
            return result;
        }
    };

    代码(JS)

    let result = [];
    let path = [];
    const backTracking = (n, k, startIndex) => {
        if (path.length === k) {
            result.push([...path]);
            return;
        }
        for (let i = startIndex; i <= n - (k - path.length) + 1; i++) {
            path.push(i);
            backTracking(n, k, i + 1);
            path.pop();
        }
    }
    ​
    var combine = function(n, k) {
        result = [];
        path = [];
        backTracking(n, k, 1);
        return result;
    };

     

     

     

     

  • 相关阅读:
    Catch That Cow POJ 3278(BFS)
    python的各种推导式(列表推导式、字典推导式、集合推导式)
    贝叶斯神经网络
    浅谈贝叶斯
    置换检验
    Python的基本用法
    字符串和编码
    开启新篇章
    无偏博弈类问题
    PAT1103
  • 原文地址:https://www.cnblogs.com/wltree/p/15713864.html
Copyright © 2011-2022 走看看