组合排列——回溯法的实践

2023-11-02

一、模板

对于回溯问题,可以给一个模板

result = []

def backtracking(参数)
 {
     if (终止条件) {
         result.add(路径)
         return;
     }

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

二、46题全排列

2.1 题目

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

 2.2 解析

这个问题可以看作有 n个排列成一行的空格,我们需要从左往右依此填入题目给定的 n 个数,每个数只能使用一次。那么很直接的可以想到一种穷举的算法,即从左往右每一个位置都依此尝试填入一个数,看能不能填完这 n 个空格,在程序中我们可以用「回溯法」来模拟这个过程。

我们定义递归函数 backtrack(first, output) 表示从左往右填到第 first 个位置,当前排列为 output。 那么整个递归函数分为两个情况:

    如果 first==n,说明我们已经填完了 n个位置(注意下标从 0 开始),找到了一个可行的解,我们将 output 放入答案数组中,递归结束。
    如果 first<n,我们要考虑这第 first 个位置我们要填哪个数。根据题目要求我们肯定不能填已经填过的数,因此很容易想到的一个处理手段是我们定义一个标记数组 vis[] 来标记已经填过的数,那么在填第 first 个数的时候我们遍历题目给定的 n 个数,如果这个数没有被标记过,我们就尝试填入,并将其标记,继续尝试填下一个位置,即调用函数 backtrack(first + 1, output)。回溯的时候要撤销这一个位置填的数以及标记,并继续尝试其他没被标记过的数。

  2.3 代码

class Solution {

public: // dfs + 回溯
    int len;
    vector<bool> status; // 记录是否选择过
    vector<vector<int>> ret; // 最终的路径数组
    vector<int> track;
    void backTrack(vector<int> &nums)
    {
        if (track.size() == len) { // 满足长度,直接返回
            ret.push_back(track);
            return;
        }
        for (int i = 0; i < len; i++) {
            if (!status[i]) {
                status[i] = true;
                track.push_back(nums[i]);
                backTrack(nums);
                track.pop_back();
                status[i] = false;
            }
        }
    }

    vector<vector<int>> permute(vector<int> &nums)
    {
        len = nums.size();
        status.resize(len, false); // 初始化,都没使用过
        backTrack(nums);
        return ret;
    }
};

三、78题子集

3.1 题目

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

 3.2 解析

     直接套公式

 3.3 代码

class Solution {
private:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking(vector<int>& nums, int startIndex) {
        result.push_back(path); // 收集子集,要放在终止添加的上面,否则会漏掉自己
        if (startIndex >= nums.size()) { // 终止条件可以不加
            return;
        }
        for (int i = startIndex; i < nums.size(); i++) {
            path.push_back(nums[i]);
            backtracking(nums, i + 1);
            path.pop_back();
        }
    }
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        result.clear();
        path.clear();
        backtracking(nums, 0);
        return result;
    }
};

四、39题组合

4.1 题目

给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。

candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是唯一的。对于给定的输入,保证和为 target 的唯一组合数少于 150 个。

4.2  解析

使用模板,搜索回溯

4.3 代码

class Solution {
private:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking(vector<int> &candidates, int target, int sum, int startIndex)
    {
        if (sum > target) {
            return;
        }
        if (sum == target) { // 满足结束条件
            result.push_back(path);
            return;
        }

        for (int i = startIndex; i < candidates.size(); i++) {
            sum += candidates[i];
            path.push_back(candidates[i]);
            backtracking(candidates, target, sum, i);  // 不用i+1了,表示可以重复读取当前的数
            sum -= candidates[i];
            path.pop_back();
        }
    }

public:
    vector<vector<int>> combinationSum(vector<int> &candidates, int target)
    {
        result.clear();
        path.clear();
        backtracking(candidates, target, 0, 0);
        return result;
    }
};

参考:

力扣

力扣

力扣

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

组合排列——回溯法的实践 的相关文章

随机推荐

  • 在openeuler22.03平台上基于atmoz/sftp容器运行老版本的openssh服务器

    在国产化openeuler22 03平台上容器化openssh默认为8 8p1 为进行安全加固 我们将其升级到了9 3了 但部分应用的sftp客户端版本老旧 无法连接到新版服务器 故本文尝试在国产开源操作系统搭建老版本的openssh服务器
  • 更新服务器列表不显示进度条,Ajax 请求服务器更新进度条

    Ajax Progress Bar var xmlHttp var key var bar color gray 进度条的颜色 var span id block var clear function createXMLHttpReques
  • 【C++】泛型编程

    为了让函数或者类有更好的复用性 C 引入了摸板的技术 让不同的数据类型 能使用到相同的函数或者类中去 这种编程的思想也叫做泛型编程 一 摸板 void Swap int left int right int temp left left r
  • Pandas系列学习(二):数据读取与输出

    平时工作中 主要会涉及到csv excel和sql等数据的导入与导出比较多 pandas库也内置了相应的函数进行处理读取与输出这些文件 首先 看看pd read csv 函数的语法格式如下 1 pd read csv pd read csv
  • ArcGIS:读取nc格式文件并导出为tif格式文件,降雨或温度NC等数据

    使用ArcGIS读取nc文件步骤 1 打开ArcGIS 在多维工具下选择 创建NetCDF栅格图层 2 输入nc文件 其他参数可忽略 点击确定 3 创建好后 右键点击图层 点击属性 选择 NetCDF 然后选择波段纬度 接着点击纬度对应的值
  • [XenServer] 修改默认安装XenServer系统盘(4G)大小

    安装XenServer系统盘默认大小为4G 安装前我们可以调整大小 注 此教程只适用于在全新安装XenServer的时候使用 已经安装过XenServer的无法修改系统盘 4G 大小 注 如果带数据重装 安装的时候一定要保证XenServe
  • day o1

    一java的发展史 1995年Sun公司发布Java1 0版本 1997年发布Java 1 1版本 1998年发布Java 1 2版本 2000年发布Java 1 3版本 2002年发布Java 1 4版本 2004年发布Java 1 5版
  • C2143 C4430 C2238错误

    原因是头文件互相包含了 错误1 error C2143 语法错误 缺少 在 lt 的前面 错误2 error C2238 意外的标记位于 之前 错误3 error C4430 缺少类型说明符 假定为int 注意 C 不支持默认int
  • SylixOS下定时器使用

    1 适用范围 本文档介绍SylixOS下实现定时器功能的方法 使用者应熟悉SylixOS以及SylixOS下的编程规范 2 实现方案 SylixOS提供标准定时器接口 用户可在应用层直接调用 下面列出定时器的创建 启动 停止以及删除等操作
  • VM关闭防火墙操作

    VM关闭防火墙操作 链接外网配置 setup 配置ip等 设置开启网卡 进入ifcfg eth0 vim etc sysconfig network scripts ifcfg eth0 修改 ONBOOT yes 重启网卡 service
  • 一、C语言进阶:文件操作

    1 文件操作 1 1 文件的输入输出 输出 使用printf 和命令行重定向 gt 实现文件输出 输入 使用scanf 和命令行重定向 lt 实现文件输入 include
  • Sass/Scss样式复用

    在团队开发中 复用代码能减少冗余 抹平编写风格的差异 或者在编写同主题的组件 统一文字 颜色 间隔等样式 复用样式代码是必不可少的 Sass提供四种样式复用的方法 import extend media mixin import Sass
  • Flutter 切换tabbar 视图重新渲染解决方法

    gt 底部tabbar点击page切换时 会重新加载页面 重新请求接口浪费资源 为解决这个尴尬处境 有个简易的办法在bottomtabbar类中 对 return scaffold body 加入indexedstack body Inde
  • e4a锁屏接收服务器信息,Arduino+ESP8266接收服务器信息

    上一篇文章 Arduino ESP8266上传数据到服务器 我们介绍了Arduino如何将数据上传到服务器上 与之相对应的是如何终端读取服务器的数据 在这一篇文章中我们将进行详细的讲解 为了便于说明 我们先演示一下如何 手动 的上传 读取数
  • Linux系统管理:虚拟机ESXi安装

    目录 一 理论 1 VMware Workstation 2 VMware vSphere Client 3 ESXi 二 实验 1 ESXi 7安装 一 理论 1 VMware Workstation 它是一款专业的虚拟机软件 可以在一台
  • Qt 命令行编译,VC命令行编译,调用nsis

    QT bat脚本 rd q s dist mkdir dist qmake exe helloworld pro spec win32 g CONFIG qtquickcompiler o dist cd dist mingw32 make
  • make[1]: *** Waiting for unfinished jobs....

    安装node js环境时候 make报错 报错信息 make 1 Waiting for unfinished jobs rm 490f1fcf42b2afac71d1c00fb593c736d4a65552 intermediate ma
  • Python执行JS代码的三种方式

    1 使用 js2py 基本操作 import js2py 执行单行js语句 js2py eval js console log abcd gt gt gt abcd 执行js函数 add js2py eval js function add
  • 基于session和token的身份认证方案

    一 基于session的身份认证方案 1 方案图示 2 比较通用的鉴权流程实现如下 在整个流程中有两个拦截器 第一个拦截器 AuthInteceptor是为了每一次的请求的时候都先去session中取user对象 如果session中有 就
  • 组合排列——回溯法的实践

    一 模板 对于回溯问题 可以给一个模板 result def backtracking 参数 if 终止条件 result add 路径 return for 选择 本层集合中元素 树中节点孩子的数量就是集合的大小 处理节点 backtra