代码随想录 Day29 回溯算法 491.递增子序列 46.全排列 47.全排列 II

491.递增子序列

class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& nums, int startIndex) {if (path.size() > 1) {result.push_back(path);// 注意这里不要加return,要取树上的节点}unordered_set<int> uset; // 使用set对本层元素进行去重for (int i = startIndex; i < nums.size(); i++) {if ((!path.empty() && nums[i] < path.back())|| uset.find(nums[i]) != uset.end()) {continue;}uset.insert(nums[i]); // 记录这个元素在本层用过了,本层后面不能再用了path.push_back(nums[i]);backtracking(nums, i + 1);path.pop_back();}}
public:vector<vector<int>> findSubsequences(vector<int>& nums) {result.clear();path.clear();backtracking(nums, 0);return result;}
};

思路:

1. 本题是不能进行排序的,因为进行排序以后就不是原来的子串了。

2. 本题的去重逻辑是使用了unorderset,因为不能进行排序,所以说不能使用原来的方法即使用used[]进行判断去重。

3. unordered_set 是对于本层的元素进行寻找查看有没有重复的元素,所以说是在backtracking的公共区域进行定义而不是for循环中。还有就是为什么unordered_set只需要进行insert而不需要进行取出,因为每层都有一个只要保证不重复就可以了。

46.全排列

class Solution {
public:vector<vector<int>> result;vector<int> path;void backtracking (vector<int>& nums, vector<bool>& used) {// 此时说明找到了一组if (path.size() == nums.size()) {result.push_back(path);return;}for (int i = 0; i < nums.size(); i++) {if (used[i] == true) continue; // path里已经收录的元素,直接跳过used[i] = true;path.push_back(nums[i]);backtracking(nums, used);path.pop_back();used[i] = false;}}vector<vector<int>> permute(vector<int>& nums) {result.clear();path.clear();vector<bool> used(nums.size(), false);backtracking(nums, used);return result;}
};

思路:

1. 排列相较于组合问题就是不需要设置startIndex变量作为初始开始位置,不是不能重复,而是需要设置used数组,确保如果数据已经在排列中的时候就不需要再放入到排列中。

47.全排列 II

class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking (vector<int>& nums, vector<bool>& used) {// 此时说明找到了一组if (path.size() == nums.size()) {result.push_back(path);return;}for (int i = 0; i < nums.size(); i++) {// used[i - 1] == true,说明同一树枝nums[i - 1]使用过// used[i - 1] == false,说明同一树层nums[i - 1]使用过// 如果同一树层nums[i - 1]使用过则直接跳过if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {continue;}if (used[i] == false) {used[i] = true;path.push_back(nums[i]);backtracking(nums, used);path.pop_back();used[i] = false;}}}
public:vector<vector<int>> permuteUnique(vector<int>& nums) {result.clear();path.clear();sort(nums.begin(), nums.end()); // 排序vector<bool> used(nums.size(), false);backtracking(nums, used);return result;}
};// 时间复杂度: 最差情况所有元素都是唯一的。复杂度和全排列1都是 O(n! * n) 对于 n 个元素一共有 n! 中排列方案。而对于每一个答案,我们需要 O(n) 去复制最终放到 result 数组
// 空间复杂度: O(n) 回溯树的深度取决于我们有多少个元素

思路:

1. 在通过之前几道题目的训练以后,本题就显得相当简单了。只是需要注意小的细节。

回溯总结:关于组合和排列

回溯问题可以分为一般的回溯,向下可以分为组合或是排列问题,细分细节注意需要去重的情况。

组合回溯:

//组合问题
vector<int> path;
vector<vector<int>> result;
void backtracking(vector<int>& nums, int startIndex){if(终止条件){result.push_back(path);
//在组合问题中,往往也会不使用终止条件以及return,而是只进行将一维数组放入到二维数组中去
//因为当for循环的不断的执行,会超出数值的范围这个时候就不会再继续循环,并且也可以执行下一层}for(int i = startIndex; i < nums.size(); i++){
// 需要从startIndex开始,这样的话,之前的元素就不能被选中,就不会出现组合内重复的问题了path.push_back(nums[i]);backtracking(nums, i + 1);
//进行树的深度的加深path.pop_back();
//回溯的时候推出元素。}
}vector<vector<int>> answer(vector<int>& nums){backtracking(nums, 0);
//需要对于数组从0开始进行遍历return result;
}

排列回溯:

//排列问题
vector<int> path;
vector<vector<int>> result;
void backtracking(vector<int>& nums, vector<bool>& used){if(path.size() == nums.size()){
//排列问题就是当所有的元素都取到的时候就进行翻入数值,进行返回。result.push_back(path);return ;}for(int i = 0; i < nums.size(); i++){
// 排列问题开始的位置是0,因为去过的元素也会再次被取到,因为这样的话排列是不同的。if(used[i] == true) continue;
//但是如果说这个元素是已经在排列中取过了,那么就不需要再取了。path.push_back(nums[i]);used[i] = true;backtracking(nums, used);
//进行树的深度的加深path.pop_back();used[i] = false;
//回溯的时候推出元素}
}vector<vector<int>> answer(vector<int>& nums){vector<bool> used(nums.size(), false);
//设置一个和数组元素大小一样的bool类型的数组,并且初始化为falsebacktracking(nums, 0);
//需要对于数组从0开始进行遍历return result;
}

去重的做法1:

通过将元素放入到unordered_set中,并且在每一层都在set中去寻找,如果在该层已经使用过该元素了,那么就不需要该元素了(组合问题去重)

//去重问题方法1
vector<int> path;
vector<vector<int>> result;
void backtracking(vector<int>& nums, int startIndex){result.push_back(path);unordered_set<int> uset;
//unordered_set 放在这个位置这样的话就是为了在每个树层中不允许出现相同的元素,下文有逻辑for(int i = startIndex; i < nums.size(); i++){if(i > 0 && uset.find(nums[i]) != uset.end()) continue;uset.insert(nums[i]);
//将需要放到nums中的元素放入到uset中去
//但是在回溯返回的时候并不需要进行推出,因为我们在每一个树层都定义了一个unordered_setpath.push_back(nums[i]);backtracking(nums, i + 1);
//进行树的深度的加深path.pop_back();//回溯的时候推出元素}
}vector<vector<int>> answer(vector<int>& nums){backtracking(nums, 0);return result;
}

去重问题方法2:

去重问题的方法,使用一个used数组进行标记,使得元素在同一树层中不会出现重复的元素

//去重问题方法2
vector<int> path;
vector<vector<int>> result;
void backtracking(vector<int>& nums, int startIndex, vector<bool> used){result.push_back(path);return ;for(int i = startIndex; i < nums.size(); i++){if(used[i] == true) continue;used[i] = true;path.push_back(nums[i]);backtracking(nums, i + 1);
//进行树的深度的加深path.pop_back();used[i] = false;
//回溯的时候推出元素}
}vector<vector<int>> answer(vector<int>& nums){vector<bool> used(nums.size(), false);backtracking(nums, 0);return result;
}

需要注意的细节点:

1. 在刚开始学的时候可能会出现一些变量写错位置的情况可能是笔误的问题也可能是理解不够到位的问题。

2. 对于数组都是需要采用引用的形式,一方面这样的效率是更高的不用进行复制在操作,另外一方面这样的话就是原数组进行操作不会出现更改原数组但是数组没有变化的情况。

3. 具体问题还需要进行具体分析上述只是提供一个思路。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/784894.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Keil MDK 5.37 及之后版本 安装 AC5(ARMCC) 编译器详细步骤

由于 Keil 5.37 及之后版本不再默认安装 AC5(ARMCC) 编译器&#xff0c;这就会导致由 AC5 编译的工程无法正常编译&#xff0c;往往输出窗口会提示以下信息&#xff1a;*** Target ‘STM32xxxx‘ uses ARM-Compiler ‘Default Compiler Version 5‘ which is not available. —…

苹果应用上架流程解析

苹果上架要求是苹果公司对于提交应用程序到苹果商店上架的要求和规定。这些要求主要是为了保证用户体验、应用程序的质量和安全性。以下是苹果上架要求的详细介绍&#xff1a;1. 应用程序的内容和功能必须符合苹果公司的规 苹果上架要求是苹果公司对于提交应用程序到苹果商店上…

基于单片机控制的高速数据采集与处理系统研究

摘要针对现有单片机的数据处理速率较低不利于高速数据采集与处理的问题,文中研究并设计基于单片机控制的高速数据采集与处理系统。在数据采集方面,使用A/D 高速采样芯片实现高速数据采集。为满足高速数据处理与存储的需要,文中使用PC 终端的IDE 接口硬盘作为系统的存储装置。…

用Python标准GUI库Tkinter绘制分形图

用Python标准GUI库Tkinter绘制分形图 分形图是一种通过迭代规则生成自相似图案的艺术形式。 分形图包括曼德勃罗集、科赫曲线、谢尔宾斯基三角等代码等。 Tkinter是Python的标准GUI库&#xff0c;可以用于创建窗口、控件和其他图形界面元素。绘制分形图像&#xff0c;如曼德…

iPhone设备中如何分析和解决应用程序崩溃日志的问题

​ 目录 如何在iPhone设备中查看崩溃日志 摘要 引言 导致iPhone设备崩溃的主要原因是什么&#xff1f; 使用克魔助手查看iPhone设备中的崩溃日志 奔溃日志分析 总结 摘要 本文介绍了如何在iPhone设备中查看崩溃日志&#xff0c;以便调查崩溃的原因。我们将展示三种不同的…

C语言—指针数组

从键盘任意输入一个整型表示的月份值&#xff0c;用指针数组编程输出该月份的英文表示&#xff0c;若输入的月份值不在1&#xff5e;12之间&#xff0c;则输出“Illegal month”。 **输入格式要求&#xff1a;"%d" 提示信息&#xff1a;"Input month number:&q…

从零开始 使用OMNET++结合VEINS,INET和SUMO的联合仿真

背景知识 当我们探索未来的交通系统和智能交通解决方案时&#xff0c;车辆到一切&#xff08;Vehicle-to-Everything, V2X&#xff09;通信技术显得尤为重要。V2X是指在车辆与车辆&#xff08;V2V&#xff09;、车辆与基础设施&#xff08;V2I&#xff09;、车辆与行人&#x…

0 决策树基础

目录 1 绪论 2 模型 3 决策树面试总结 1 绪论 决策树算法包括ID3、C4.5以及C5.0等&#xff0c;这些算法容易理解&#xff0c;适用各种数据&#xff0c;在解决各种问题时都有良好表现&#xff0c;尤其是以树模型为核心的各种集成算法&#xff0c;在各个行业和领域都有广泛的…

优化页面加载时间:改善用户体验的关键

✨✨ 祝屏幕前的您天天开心&#xff0c;每天都有好运相伴。我们一起加油&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 目录 引言 一、为什么页面加载时间重要&#xff1f; 二、如何减少页面加载时间&#xff1f; …

分布式文件系统DFS

定义与概述 分布式文件系统&#xff08;Distributed File System, DFS&#xff09;是一种特殊的文件系统&#xff0c;其管理的物理存储资源并非直接连接在本地节点上&#xff0c;而是通过计算机网络与各个节点相连。这些节点可以简单地理解为一台台独立的计算机。DFS将分布在网…

干部任免管理系统开发(二) 数据库表的建设

前言: 字段照搬Lrmx文件内容 数据库表字段的设计基本上就是照搬Lrmx文件内容,没有什么过多的技术含量,也可以根据自己的需要对照Lrmx文件的格式自己去定义字段了。 软件的功能截图如下&#xff1a;核心就是能够任免审批表内容读取到数据库&#xff0c;生成lrmx和word格式方便做…

Nginx 部署静态文件

部署静态文件&#xff08;如HTML、CSS和JavaScript文件&#xff09;到一个Docker容器中&#xff0c;并使用Nginx作为web服务器是一个常见的做法。这种方式可以提高应用的性能和可靠性。下面是如何使用Docker和Nginx部署静态文件的一个基本步骤&#xff1a; 第一步&#xff1a;…

Netlink与RTNetlink的简单使用

Netlink与RTNetlink的简单使用 近期项目要求通过程序去配置下发网口路由&#xff0c;所以去了解了一下netlink机制。 一、netlink通信机制 netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口。 目前&a…

java中的抽象类

抽象类是指包含了抽象方法的类。在java中&#xff0c;抽象方法指的是用abstract关键字进行修饰的方法&#xff0c;抽象方法与普通的方法的最大区别就是抽象方法没有方法体&#xff0c;也就是说抽象方法是没有具体的实现的。这也就意味着在抽象类的子类中调用抽象方法时&#xf…

蓝桥杯软件测试赛项--自动化测试

目录 Lanqiao_RJCS 1.自动化测试(Selenium+python) 分值:50 1.1. Webdriver初始化

Python脚本:pve平台自动获取名字、类型、节点、备注、状态。

此脚本可自动获取pve平台的信息。有兴趣或者有需要大家可以看看。 #anthor:bbxwg #explain:pve平台自动获取名字、类型、节点、备注、状态。 #Date:2024-3-29import os import subprocess import json import re from datetime import datetime#lkh:获取虚拟机IP地址函数 def …

SiteSucker Pro mac 5.3.2激活版 网站扒站神器

SiteSucker是一个Macintosh应用程序&#xff0c;可以从互联网自动下载网站。它通过将站点的网页、图像、PDF、样式表和其他文件异步复制到本地硬盘驱动器&#xff0c;复制站点的目录结构来实现此目的。只需输入一个URL&#xff08;统一资源定位器&#xff09;&#xff0c;按回车…

JavaScript 入门指南(三)BOM 对象和 DOM 对象

BOM 对象 BOM 简介 BOM&#xff08;browser Object Model&#xff09;即浏览器对象模型BOM 由一系列对象组成&#xff0c;是访问、控制、修改浏览器的属性的方法BOM 没有统一的标准&#xff08;每种客户端都可以自定标准&#xff09;。BOM 的顶层是 window 对象 window 对象 …

习题2-5 求平方根序列前N项和

本题要求编写程序&#xff0c;计算平方根序列 的前N项之和。可包含头文件math.h&#xff0c;并调用sqrt函数求平方根。 输入格式: 输入在一行中给出一个正整数N。 输出格式: 在一行中按照“sum S”的格式输出部分和的值S&#xff0c;精确到小数点后两位。题目保证计算结果不…

1.10 类、方法、封装、继承、多态、装饰器

一、介绍类 类(class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例 实例化&#xff1a;创建一个类的实例&#xff0c;类的具体对象。 对象&#xff1a;通过类定义的数据结构实例。对象包括两个数据成员&#x…