LeetCode刷题笔记【22】:回溯专题-5(递增子序列、全排列、全排列 II)

news2024/11/17 13:43:37

文章目录

  • 前置知识
  • 491.递增子序列
    • 题目描述
    • 错误思路, 踩的坑
    • 反思&正确思路
  • 46.全排列
    • 题目描述
    • 用`unordered_set used`记录用过的数
    • 用数组代替unordered_set
  • 47.全排列 II
    • 题目描述
    • 解题思路
    • 代码
  • 总结

前置知识

参考前文

参考文章:
LeetCode刷题笔记【18】:回溯专题-1(回溯算法基础知识、用回溯算法解决组合问题)
LeetCode刷题笔记【19】:回溯专题-2(组合总和III、电话号码的字母组合)
LeetCode刷题笔记【20】:回溯专题-3(组合总和、组合总和II、分割回文串)
LeetCode刷题笔记【21】:回溯专题-4(复原IP地址、子集、子集II)

491.递增子序列

题目描述

截图

LeetCode链接:https://leetcode.cn/problems/non-decreasing-subsequences/

错误思路, 踩的坑

回溯, 过程是**“遍历节点”**, 具体操作就是将上一个数通过函数参数传入, 判断当前数相比于上一个数是否增加;
如果增加, 加入path, 并加入ans;
很明显过程中涉及到"去重操作".
通过和前两天题目中的操作一样的i!=index && nums[i]==nums[i-1]来去重

class Solution {
private:
    vector<vector<int>> ans;
    vector<int> path;
    void backtrack(vector<int>& nums, int index, int pre){
        if(index>nums.size())
            return;
        if(path.size()>=2)
            ans.push_back(path);
        for(int i=index; i<nums.size(); ++i){
            if((i!=index && nums[i]==nums[i-1])
                || (path.size()!=0 && nums[i]<pre))
                continue;
            path.push_back(nums[i]);
            backtrack(nums, i+1, nums[index]);
            path.pop_back();
        }
        return;
    }
public:
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backtrack(nums, 0, INT_MIN);
        return ans;
    }
};

反思&正确思路

但是以上即使优化过, 但还是无法通过[1,2,3,4,5,6,7,8,9,10,1,1,1,1,1], 或者[4,4,3,2,1,4,4]
这是因为我们虽然做了去重检测, 但是只能去除连续的重复问题
在之前的一些题目里面, 我们这么做没有问题, 那是因为我们会先sort一遍

但是在本题中我们需要输入数组nums本身的顺序, 不能sort
所以这个**“检测某个数字有没有在树的本层出现”**的功能, 就只能用unordered_set<int> used来实现了

class Solution {
private:
    vector<vector<int>> ans;
    vector<int> path;
    void backtrack(vector<int>& nums, int index){
        if(index>nums.size())
            return;
        if(path.size()>=2)
            ans.push_back(path);
        unordered_set<int> used;
        for(int i=index; i<nums.size(); ++i){
            // if(used.count(nums[i]) || (path.size()!=0 && nums[i]<pre))
            //     continue;
            if(used.find(nums[i])!=used.end() || (!path.empty() && nums[i]<path.back()))
                continue;
            used.insert(nums[i]);
            path.push_back(nums[i]);
            backtrack(nums, i+1);
            path.pop_back();
        }
        return;
    }
public:
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backtrack(nums, 0);
        return ans;
    }
};

46.全排列

题目描述

在这里插入图片描述

LeetCode链接:https://leetcode.cn/problems/permutations/description/

unordered_set used记录用过的数

思路: 还是回溯, 但是过程中用一个unordered_set<int> used记录已经用了哪些数, 如果已经用过了就略过, 过程中在加入path的时候也加入used

class Solution {
private:
    vector<vector<int>> ans;
    vector<int> path;
    unordered_set<int> used;
    void backtrack(vector<int>& nums){
        if(nums.size()==path.size()){
            ans.push_back(path);
            return;
        }
        for(int i=0; i<nums.size(); ++i){
            if(used.find(nums[i]) != used.end())
                continue;
            used.insert(nums[i]);
            path.push_back(nums[i]);
            backtrack(nums, i+1);
            path.pop_back();
            used.erase(nums[i]);
        }
    }
public:
    vector<vector<int>> permute(vector<int>& nums) {
        backtrack(nums);
        return ans;
    }
};

用数组代替unordered_set

尝试用数组代替unordered_set

class Solution {
private:
    vector<vector<int>> ans;
    vector<int> path;
    void backtrack(vector<int>& nums, vector<bool>& used){
        if(nums.size()==path.size()){
            ans.push_back(path);
            return;
        }
        for(int i=0; i<nums.size(); ++i){
            if(used[i])
                continue;
            used[i] = true;
            path.push_back(nums[i]);
            backtrack(nums, used);
            path.pop_back();
            used[i] = false;
        }
    }
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<bool> used(nums.size(), false);
        backtrack(nums, used);
        return ans;
    }
};

47.全排列 II

题目描述

在这里插入图片描述

LeetCode链接:https://leetcode.cn/problems/permutations-ii/description/

解题思路

参考上一题<46. 全排列>
原本的条件是**“不包含重复数字”, 现在是"可包含重复数字"**
在这里插入图片描述
从图中可以看出: 我们需要"在同层中进行去重"
那么就需要一方面if(i>0 && nums[i]==nums[i-1] && !used[i-1]) continue;
另一方面一定要先sort.

代码

class Solution {
private:
    vector<vector<int>> ans;
    vector<int> path;
    void backtrack(vector<int>& nums, vector<bool>& used){
        if(path.size()==nums.size()){
            ans.push_back(path);
            return;
        }
        for(int i=0; i<nums.size(); ++i){
            if(i>0 && nums[i]==nums[i-1] && !used[i-1])// 这一层有多个相同的数, 目前处理的不是这些个中的第一个, 并且其中的第一个还没用呢
                continue;
            if(!used[i]){
                used[i] = true;
                path.push_back(nums[i]);
                backtrack(nums, used);
                used[i] = false;
                path.pop_back();
            }
        }
        return;
    }
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<bool> used(nums.size(), false);
        sort(nums.begin(), nums.end());
        backtrack(nums, used);
        return ans;
    }
};

总结

回溯问题, 一方面模板大纲结构是确定的, 另一方面, 模板中的几个关键点需要注意:
① 是否需要去重, 如同层去重
1.1 要不要先sort
1.2 用used表 / 前后位比较
1.3 要不要先sort
② i=?
2.1 i=index
2.2 i=index+1
2.3 i=0
(这里也就也涉及是否要在参数中传递index)
③ 我们是要叶子节点还是遍历全部节点
3.1 最好先画一下树再决定
3.2 一般有套路, 但是具体到题目和解法, 可能会有多种做法
3.3 到终止条件后是否return

总而言之, 最好先画一下树用以理清思路, 并且注意过程中的这些关键点.
如果能记得清楚, 可以记一下不同类型的题目需要怎么做, 但不一定记得清楚, 所以最好还是画树和遍历结果, 具体问题具体分析.

本文参考:
递增子序列
全排列
全排列 II

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

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

相关文章

在Windows10里面mysql怎么配置环境变量

有小伙伴知道怎么给mysql配置环境变量吗&#xff0c;为了方便用户们的操作&#xff0c;最好在下载安装好mysql之后&#xff0c;给它配置一个环境变量&#xff0c;下面小编就给大家详细介绍一下mysql怎么配置环境变量&#xff0c;不太清楚的小伙伴快来看看吧。 mysql配置环境变…

【LeetCode-中等题】39. 组合总和

文章目录 题目方法一&#xff1a;递归回溯 题目 这题的nums数组里面不存在重复元素&#xff0c;所以也就无需做去重操作 但同一个元素可以被无限次取&#xff0c;说明每次递归中的for循环的开始位置就是自己 nums数组里面存在重复元素&#xff0c;去重版本&#xff1a; 方法一…

【Linux权限管理】文件:毁灭我与我无关

一.预备知识 1.LInux用户分类 一台Linux机器的用户分为两类&#xff1a; 超级用户和普通用户。 注意我这里说的用户的并不是一个固定的人&#xff0c;例如你本身就有root账号&#xff0c;但你也可以使用自己创建普通账号。当你使用root账号时&#xff0c;你就是一个超级用户…

高等数学教材重难点题型总结(四)不定积分

难点在于量级&#xff0c;不定积分一定要多练多见才能游刃有余~ 1.利用求导公式验证等式 2.计算不定积分

WebRTC中 setup:actpass、active、passive

1、先看一下整个DTLS的流程 setup:actpass、active、passive就发生在Offer sdp和Anser SDP中 Offer的SDP是setup:actpass,这个是服务方&#xff1a; v0\r o- 1478416022679383738 2 IN IP4 127.0.0.1\r s-\r t0 0\r agroup:BUNDLE 0 1\r aextmap-allow-mixed\r amsid-semanti…

csharp开发日常之Activator.CreateInstance构造函数生成实例

目录 一、需求&#xff1a;项目中经常需要动态生成对象&#xff0c;而非采用new关键字方式&#xff0c;例如Java里面的根据类全限定名反射生成对象实例。 二、方案&#xff1a;采用Activator.CreateInstance 三、代码例子演示 1、代码结构 2、创建接口 3、创建IObjcet接口的…

索尼 toio™ 应用创意开发征文|教育与游戏的完美融合:toio™核心Q宝引领数字学习新潮流

引言 在科技与创意碰撞的时代&#xff0c;索尼toio™核心Q宝不仅是一款吸引人的娱乐玩具&#xff0c;更是一种融合编程与教育的创新平台。我一直寻找一个能够将编程和教育完美结合的方式&#xff0c;而toio™给了我这个机会。接下来&#xff0c;我将详细介绍如何用toio™开发一…

【云计算网络安全】解析DDoS攻击:工作原理、识别和防御策略 | 文末送书

文章目录 一、前言二、什么是 DDoS 攻击&#xff1f;三、DDoS 攻击的工作原理四、如何识别 DDoS 攻击五、常见的 DDoS 攻击有哪几类&#xff1f;5.1 应用程序层攻击5.1.1 攻击目标5.1.2 应用程序层攻击示例5.1.3 HTTP 洪水 5.2 协议攻击5.2.1 攻击目标5.2.2 协议攻击示例5.2.3 …

无需公网IP,实现外网远程访问管家婆ERP进销存系统的方法

文章目录 前言 1.管家婆服务2. 内网穿透2.1 安装cpolar内网穿透2.2 设置远程访问 3. 固定访问地址4. 配置固定公网访问地址 前言 管家婆辉煌系列产品是中小企业进销存、财务管理一体化的典范软件&#xff0c;历经十余年市场的洗礼&#xff0c;深受广大中小企业的欢迎&#xff…

跟着视频学习java,发现swagger打不开?怎么解决

前因 现在到处都在卷java&#xff0c;不会java的前端不是好前端。 这不&#xff0c;周围有前端同学开始学java了。 昨天他突然找我问说引入依赖&#xff0c;配置之后swagger打不开了。 分析过程 1、 查看他的swagger版本&#xff0c;让他试了对应路径/swagger-ui/index.h…

直饮水表和智能水表有什么区别?

直饮水表和智能水表是两种不同类型的水表&#xff0c;它们的主要区别在于功能和应用场景。下面小编整理了这两款水表的一些知识点&#xff0c;一起来看下吧! 直饮水表是一种特殊的水表&#xff0c;主要用于家庭和公共场所的直饮水系统中。它可以实时监测水的流量&#xff0c;帮…

JavaScript 之 Symbol 数据类型

一、简介 ​ symbol类型是ES6新引入的一种基本数据类型&#xff0c;该类型具有静态属性和静态方法。其中静态属性暴露了几个内建的成员对象&#xff0c;静态方法暴露了全局的symbol注册。 ​ symbol类型具有以下特点&#xff1a;① 唯一性&#xff1a;每个symbol值都是唯一的…

大厂面试题之影响项目测试进度的因素有哪些?如何解决?

测试进度&#xff0c;是领导层非常关心的问题&#xff0c;测试同学把控好项目测试进度&#xff0c;必然能让面试官为你加分。 在日常测试过程中&#xff0c;要把控好测试进度&#xff0c;了解影响测试进度的因素是必不可少的&#xff0c;那么&#xff0c;影响项目测试进度的因…

【牛客刷题】bfs和dfs (二叉树层序遍历、矩阵最长递增路径、被围绕的区域)

二叉树层序遍历 vector<vector<int> > levelOrder(TreeNode* root) {// write code herevector<int> res;vector<vector<int>> result;if (root nullptr) return result;queue<TreeNode*> que;que.push(root);while (!que.empty()) {int …

LeetCode刷题笔记【25】:贪心算法专题-3(K次取反后最大化的数组和、加油站、分发糖果)

文章目录 前置知识1005.K次取反后最大化的数组和题目描述分情况讨论贪心算法 134. 加油站题目描述暴力解法贪心算法 135. 分发糖果题目描述暴力解法贪心算法 总结 前置知识 参考前文 参考文章&#xff1a; LeetCode刷题笔记【23】&#xff1a;贪心算法专题-1&#xff08;分发饼…

Java8实战-总结19

Java8实战-总结19 使用流映射对流中每一个元素应用函数流的扁平化 使用流 映射 一个非常常见的数据处理套路就是从某些对象中选择信息。比如在SQL里&#xff0c;你可以从表中选择一列。Stream API也通过map和flatMap方法提供了类似的工具。 对流中每一个元素应用函数 流支持…

回归预测 | MATLAB实现PCA-BP主成分降维结合BP神经网络多输入单输出回归预测

回归预测 | MATLAB实现PCA-BP主成分降维结合BP神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现PCA-BP主成分降维结合BP神经网络多输入单输出回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 MATLAB实现PCA-BP主成分降维算法结合BP神经网络多输入单输出回…

java八股文面试[设计模式]——行为型模式

目录 策略模式 观察者模式 责任链模式 模板方法模式 状态模式 行为型模式关注的是各个类之间的相互作用&#xff0c;将职责划分清楚&#xff0c;使得我们的代码更加地清晰。 策略模式 策略模式太常用了 下面设计的场景是&#xff0c;我们需要画一个图形&#xff0c;可选…

leetcode872. 叶子相似的树(java)

叶子相似的树 题目描述递归 题目描述 难度 - 简单 leetcode - 872. 叶子相似的树 请考虑一棵二叉树上所有的叶子&#xff0c;这些叶子的值按从左到右的顺序排列形成一个 叶值序列 。 举个例子&#xff0c;如上图所示&#xff0c;给定一棵叶值序列为 (6, 7, 4, 9, 8) 的树。 如果…