zoukankan      html  css  js  c++  java
  • 2021.2.24 刷题(回溯-组合问题)

    题目链接:https://leetcode-cn.com/problems/combinations
    题目描述:
    给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。

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

    回溯实质是回溯三部曲:

    1. 回溯函数的参数及返回值
    2. 回溯函数的终止条件
    3. 回溯搜索的遍历过程
      回溯函数的模板:
    void backtracking(参数) {
        if (终止条件) {
            存放结果;
            return;
        }
    
        for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
            处理节点;
            backtracking(路径,选择列表); // 递归
            回溯,撤销处理结果
        }
    }
    

    参考链接:https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw
    解题:

    class Solution {
    public:
        vector<vector<int>> result;
        vector<int> path;
        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) {
            backtracking(n, k, 1);
            return result;
    
        }
    };
    

    剪枝优化:

    例如n = 4,k = 4 ,那么第一层for循环的时候,从元素2开始的遍历都没有意义了。在第二层for循环,从元素3开始的遍历都没有意义了。
    所以,可以剪枝的地方就在递归中每一层的for循环所选择的起始位置。如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了。
    优化过程如下:
    已经选择的元素个数:path.size();
    还需要的元素个数为: k - path.size();
    在集合n中至多要从该起始位置 : n - (k - path.size()) + 1,开始遍历。

    class Solution {
    private:
        vector<vector<int>> result; 
        vector<int> path;
        void backtracking(int n, int k, int startIndex) {
            if (path.size() == k) {
                result.push_back(path);
                return;
            }
            for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) { // 优化的地方
                path.push_back(i); // 处理节点 
                backtracking(n, k, i + 1);
                path.pop_back(); // 回溯,撤销处理的节点
            }
        }
    public:
    
        vector<vector<int>> combine(int n, int k) {
            backtracking(n, k, 1);
            return result;
        }
    };
    

    链接:https://mp.weixin.qq.com/s/Ri7spcJMUmph4c6XjPWXQA

  • 相关阅读:
    数组指针和指针数组的区别
    C++虚函数
    C++容器
    红黑树
    COM RTS/CTS, DTR/DSR
    linux和windows多线程的异同
    socket
    C++vector使用
    select函数详解
    linux下头文件
  • 原文地址:https://www.cnblogs.com/ZigHello/p/14443849.html
Copyright © 2011-2022 走看看