leetcode刷题详解十三

452. 用最少数量的箭引爆气球
  • 思路:

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    我们就根据上图这个例子来分析一下:

    1. 气球1和气球2是重叠的,需要一个箭,然后我们分析气球3
    2. 当气球1和气球2重叠的时候可以看到,气球1和气球2的空间应该合并成[2,6]然后再和气球3作比较
    3. 从上面特点可以看出,我们只需要关注气球的最右边界,找到右边界值最小的,成为新的右边界,然后再和气球3比
    4. 所以每次右边界改变就行

    以上就是这套题的全部思路,一般这种题第一肯定是先排序再说其他。

  • 代码

    static bool compare(vector<int>& v1, vector<int>& v2){return v1[0] < v2[0] || (v1[0] == v2[0] && v1[1] > v2[1]);}int findMinArrowShots(vector<vector<int>>& points) {int n = points.size();sort(points.begin(), points.end(), compare);for(int i = 0; i < n; i++){cout<<points[i][0]<<","<<points[i][1]<<" "<<endl;}int count = 1;for(int i = 0; i < n - 1 ; i++){if(points[i][1] < points[i + 1][0]){count++;}else{points[i + 1][1] = min(points[i][1], points[i+1][1]);}}return count;}
    
435. 无重叠区间
  • 思路

    很简单,计算能连续的区间有多少个,取差就行

    注意是移除最小区间数量,也就意味着我们尽可能少的移动区间,所以可以想一下,当你的intervals[i][1]约小,你能减少的区间就越小,当你的intervals[i][1]越大,表明你要移除更多的区间才行。

  • 代码

    bool static cmp(vector<int>& v1, vector<int>& v2){//return v1[0] < v2[0] || (v1[0] == v2[0] && v1[1] < v2[1]);return v1[1] < v2[1];}int eraseOverlapIntervals(vector<vector<int>>& intervals) {int n = intervals.size();//sort(intervals.begin(), intervals.end(), cmp);sort(intervals.begin(), intervals.end(), cmp);int end = INT_MIN;int count = 0;for(int i = 0; i < n ; i++){cout<<intervals[i][0]<<" "<<intervals[i][1]<<endl;}for(int i = 0; i < n ; i++){if(end <= intervals[i][0]){end = intervals[i][1];cout<<"end:"<<end<<endl;count++;}}cout<<"count:"<<count<<endl;return n - count;}
    
763. 划分字母区间
  • 思路

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    在遍历的过程中相当于是要找每一个字母的边界,如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点了。此时前面出现过所有字母,最远也就到这个边界了。

  • 代码

    vector<int> partitionLabels(string S) {int len = S.size();vector<int> distance(26);/*求每个字母*/for(int i = 0; i < len; i++){distance[S[i] - 'a'] = i;}int start = 0;int end = 0;vector<int> res;for(int i = 0; i < len; i++){end = max(end,  distance[S[i] - 'a']);if(i == end){int tmp = end - start + 1;start = end + 1;res.push_back(tmp);}}return res;}
    
56. 合并区间
  • 思路

    这个题比之前那个射气球好点在于重叠不用考虑几个区间都重叠部分,只要有重叠就可以合并

    要特别注意这个用例:[[2,3],[4,5],[6,7],[8,9],[1,10]]

  • 代码

    static bool cmp(vector<int>& v1, vector<int>& v2){return v1[0] < v2[0] || (v1[0] == v2[0]) && (v1[1] < v2[1]);}vector<vector<int>> merge(vector<vector<int>>& intervals) {int len = intervals.size();if(len <= 1){return intervals;}vector<vector<int>> tmp1;sort(intervals.begin(), intervals.end(), cmp);int i = 0;/*每个元素是长度为2的int数组*/vector<int> tmp2(2);/*首先初始化里面的数组,让其为第一个索引的数组值*/tmp2[0] = intervals[0][0];tmp2[1] = intervals[0][1];/*用for也行*/while(i < len - 1){/*在这里的判断条件不是intervals[i][1] >= intervals[i+1][0]*//*因为这种类型都要保存右边最大的那个索引,参考射气球的那一道题*//*因此我认为记录最大索引值,是这种题的精髓*/if(tmp2[1] >= intervals[i+1][0]){tmp2[1] = max(intervals[i+1][1], tmp2[1]); }else{tmp1.push_back(tmp2);tmp2[0] = intervals[i+1][0];tmp2[1] = max(intervals[i+1][1],tmp2[1]);}i++;}tmp1.push_back(tmp2);return tmp1;}
    
53. 最大子序和
  • 思路

    这道题之所以困扰我这么久并不是因为状态状态转移方程,这个其实很好理解

    而是max即返回连续最大和 与 dp之间的关系

    我之前一直以为要返回dp数组某个值,导致动态规划出现问题,但是其实这道题的max和dp是平行的,max是一个独立的变量,

    比如-2 1 -3这个例子,当i=3时dp的值行该是max(dp[i-1]+nums[i-1], nums[i-1])注意这个求得可不是某个区间的最大值,而某个区间的最大值在max中存储,因此还需要一步max=max(dp[i], max),这道题最关键的就是这一步。

  • 代码

    int maxSubArray(vector<int>& nums) {int n = nums.size();if(n <= 1){return nums[0];}vector<int> dp(n+1, -10000);int max_num = nums[0];dp[1] = nums[0];for(int i = 2; i < n+1; i++){dp[i] = max(dp[i-1] + nums[i-1], nums[i-1]);max_num = max(max_num, dp[i]);}return max_num;}
    
134. 加油站
  • 这题第一反应肯定是每个索引作为一个起点走一遍,这种方法也不能说出,但可能面试官不认,所以你得弄点新活儿。

    思路:①一定能跑完全程,表明总加油数大于等于油耗数。②计算每个站的为起始点的剩余油量,会发现一个规律就是从站i开始到站j邮箱里面的油就是站i到站j的剩余油量相加,即cost[i]+…+cost[j]。③如果前面邮箱是负的,那么后面肯定是正的,因为要跑完全程啊,就得那么多,肯定要大于等于0才行。

    因此,如果区间i-j的剩余油量和为负数,那么就从j+1开始算起。

  • 代码

    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int n = gas.size();int rest_sum = 0;int rest_total = 0;int start = 0;for(int i = 0; i < n; i++){rest_sum += gas[i]-cost[i];//这个rest_total就是说计算所有剩余邮箱的和是否小于0的,放在里面不用再循环一下了,一次循环就解决了rest_total += gas[i] - cost[i];if(rest_sum < 0){rest_sum = 0;start = i + 1;}}//只有剩余邮箱和小于0才会饶不了一圈if(rest_total < 0){return -1;}return start;}
    

DFS(回溯算法)(必须背熟)

需要经常的刷

对于回溯算法的总结和概括,有两个说的特别好。

分别是:拉不拉东和代码随想录

接下来我准备总结一下他俩的精华

  • 回溯算法的定义

    回溯算法又叫做回溯搜索算法,主要是一种搜索方式,主要用在决策树类型的问题上。因此如果用回溯算法,就要遍历所有可能性,然后会返回所有可能,针对这些可能我们再做打算。因此可以看到,回溯是和递归相辅相成的,回溯可以说是递归的副产物。

  • 回溯的效率

    回溯算法的效率不高。

    因为回溯会访问每一个节点,根据这个节点在访问下一个节点,因此本质上就是穷举。穷举本身能解决很多问题,有时候很多问题不得不用穷举来做做。

  • 回溯算法解决的问题

    1. 组合问题:N个数里面按一定规则找出k个数的集合

    2. 排列问题:N个数按一定规则全排列,有几种排列方式

    3. 切割问题:一个字符串按一定规则有几种切割方式

    4. 子集问题:一个N个数的集合里有多少符合条件的子集

    5. 棋盘问题:N皇后,解数独等等

      注意,排列和组合是不同的概念。排列是要注意顺序,而组合不用。

  • 对回溯法的理解

    回溯法解决的问题都可以抽象为树形结构

    算法从宽度和深度两个层面递进,集合的大小就是树的宽度,递归的深度就是树的深度。

  • 模板

    回溯就是决策树的遍历过程,在这个过程中需要思考三个问题:

    1. 路径。已经做出的选择
    2. 选择列表。当前可以做的选择
    3. 结束条件。到达决策树底层,直接return

    函数起名为back_tracing

    返回值一般为void

    参数的选取不固定,要具体问题具体分析

    下图表现得最为直观:

    图片

    代码模板如下:

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

排列问题

46. 全排列
	vector<vector<int>> res;vector<int> temp;vector<vector<int>> permute(vector<int>& nums) {vector<bool> use_check(nums.size(), false);back_tracing(nums, use_check);return res;}void back_tracing(vector<int>& nums, vector<bool>& use_check){if(temp.size() == nums.size()){res.push_back(temp);return;}for(int i = 0; i < nums.size(); i++ ){//列表中的这个元素用过了,直接跳过if(use_check[i] == true){continue;}//列表中的这个元素还没有用use_check[i] = true;temp.push_back(nums[i]);back_tracing(nums, use_check);temp.pop_back();use_check[i] = false;}}
  • 主要的问题

    • 对于vector来说我们不需要new,因为vectorr的空间是自动增长的,它自己管理的,也是自己释放,不需要new

    • 这道题对节点问题的处理主要在于判断是否是用过的节点。针对这中情况我们设一个vector,长度和给的列表长度一样长,里面初始化为false。如果某个元素用过了我们就用true表示。

      当递归到决策树的最后一个节点后,会回溯,撤销处理结果,因此这个时候我们需要重新吧所有的全部初始化为false,重新使用。放入路径中的元素也全部拿出来,这里用的是vector c++11 的pop_back()方法。

    • 不用去想具体实现步骤,就是只关注那个功能区写具体代码就行。

47. 全排列 II

这道题和前面那道题的区别是这道题不能重复,因为给的序列可能会重复

vector<vector<int>> res;vector<int> temp;vector<vector<int>> permuteUnique(vector<int>& nums) {vector<bool> user_check_vec(nums.size(), false);sort(nums.begin(), nums.end());back_tracing(nums, user_check_vec);return res;}void back_tracing(vector<int>& nums, vector<bool> vec){if(temp.size() == nums.size()){res.push_back(temp);return;}for(int i = 0; i < nums.size(); i++){if(i > 0 && nums[i-1] == nums[i] && vec[i -1] == false){continue;}if(vec[i] == true){continue;}vec[i] = true;temp.push_back(nums[i]);back_tracing(nums,vec);//回溯temp.pop_back();vec[i] = false;}}
  • 注意的问题

    最开始我是这样想的,为了让第一个加入进去的元素不重复,我用一个map保存不重复的元素,用一个我设置为true。反正这样子不行,不去想了,有点难。

    然后就是作者的思路:

    if(i > 0 && nums[i-1] == nums[i] && vec[i-1] == false){continue;
    }
    

    这句话保证了不重复,是不是非常精妙!

    nums[i-1] == nums[i]这句话保证了这次选的元素和上次选的一样,但是可能是同一层也有可能是同一个枝。我们要吧同一层的去掉,因此还要加上vec[i-1] == false。这句话保证了在递归算法中,与当前元素相同的前一个元素是没有用过的!!!

    切记,递归函数上面的代码不要想着回溯
    !

    当然做这道题之前一定要先排序,先排序!!!

组合问题

重复的话就是排列问题,i不用指定。后面的基本都是i=start

77. 组合

下面这幅图就是本题的思路

77.组合1.png
vector<vector<int>> res;
vector<int> temp;
vector<vector<int>> combine(int n, int k) {back_tracing(n ,k, 1);return res;
}void back_tracing(int n, int k, int start){if(temp.size() == k){res.push_back(temp);return;}for(int i = start; i <= n; i++){temp.push_back(i);back_tracing(n, k, i+1);temp.pop_back();}
}

重点,第二次写还是遇到了相同的问题

这是一道基本的组合问题,最最基本。这道题出问题的点在于不能出现像[2,2]或者[3,2]这样的组合

对于[2,2]这样的,我们必须要保证同一个树枝下,上一个要小下一个才行,

对于[3,2]这样的,我们必须保证同一层,前一个要小于后一个才行

不然的话写这道题的时候最开始会出现[[1,1],[1,2],[1,3],[1,4],[2,2],[2,3],[2,4],[3,2],[3,3],[3,4],[4,2],[4,3],[4,4]]这样的答案,苦死很久没发现为什么

其实问题出在for循环中 back_tracing(n, k, i+1);这段代码

对于同一树枝下的递归来说,我们考虑for时候,主要放在循环变量i上,而不是start上,因为start是控制层的递进。而i是控制递归的递进!!

第二次写补充: for 选择 in 选择列表 其实由于是组合问题,所以每次选择列表都要少一个数,因为不能重复!所以选择列表必须要i+1

在组合问题中,需要设置一个start变量。因为在递归层中,start决定从哪个索引开始遍历

每次从集合中选取元素,可选择的范围都在进行收缩,调整可选择的范围靠的就是start

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

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

相关文章

进阶C语言-字符函数和字符串函数

字符函数和字符串函数 &#x1f388;1.函数介绍&#x1f50e;1.1strlen函数&#x1f52d;1.1.1strlen函数的模拟实现&#x1f4d6;1.计数器法&#x1f4d6;2.递归法&#x1f4d6;3.指针-指针 &#x1f50e;1.2strcpy函数&#x1f52d;1.2.1strcpy函数的模拟实现 &#x1f50e;1…

Windows系统IIS服务配置与网站搭建,结合内网穿透实现公网访问

文章目录 1.前言2.Windows网页设置2.1 Windows IIS功能设置2.2 IIS网页访问测试 3. Cpolar内网穿透3.1 下载安装Cpolar内网穿透3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5.结语 1.前言 在网上各种教程和介绍中&#xff0c;搭建网页都会借助各种软件的帮助&#xf…

PyQt6第一个程序HelloWorld实现

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计12条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

1+x中级网络运维实验题

任务 1&#xff1a; 设备命名 为了方便后期维护和故障定位及网络的规范性&#xff0c;需要对网络设备进行规范化命名。请根据 Figure 3-1 实验考试拓扑对设备进行命名。命名规则为&#xff1a;城市-设备的设置地点-设备的功能属性和序号-设备型号。例如&#xff1a;处于杭州校…

河涌空中、地面双联动巡防系列--下沙涌篇

“广州街坊空中巡防队”是第十届志愿服务广州交流会青年志愿服务专项行动精品项目大赛资助项目&#xff0c;由广州市志愿者行动指导中心、广州市羊城志愿服务基金会主办&#xff0c;广州市黄埔区平安促进会承办。 在党建引领下&#xff0c;对黄埔区辖区内针对河涌开展空中安全巡…

低功耗无线SOC芯片Si24R03

Si24R03是一款高度集成的低功耗无线SOC芯片&#xff0c;芯片为QFN32 5x5mm封装&#xff0c;集成了资源丰富的MCU内核与2.4G收发器模块&#xff0c;最低功耗可达1.6uA&#xff0c;极少外围器件&#xff0c;大幅降低系统应用成本&#xff0c;同时配套有成熟的开发调试软件和丰富的…

asp.net基于WEB层面的区域云LIS系统平台源码

随着计算机技术在检验管理方面的广泛应用&#xff0c;以及各种先进的检验仪器在检验医学领域的使用,检验科室对信息化管理提出了更高的要求。正是在这样的背景下开发出了实验室信息管理系统&#xff08;简称LIS&#xff09; 结合当今各检验科管理及实验室规模的不同状况&#x…

多媒体信号处理复习笔记 --脑图版本

多媒体信号处理复习笔记 --脑图版本 依据 [2020多媒体信号处理复习笔记] 考前复习时使用Xmind制作 例图: PDF下载 BaiduYunPan 提取码&#xff1a;jbyw CSDN 下载

广州华锐视点提供AI虚拟主播定制,为品牌注入新活力!

随着科技的飞速发展&#xff0c;人工智能已经逐渐渗透到我们生活的方方面面。在这个信息爆炸的时代&#xff0c;如何让您的品牌在众多竞争对手中脱颖而出&#xff0c;成为行业的佼佼者&#xff1f;答案就是——AI虚拟主播&#xff01; 广州华锐视点提供AI数字人定制服务&#x…

快手自动评论助手:开发流程与所需技术的深度解析

先来看实操成果&#xff0c;↑↑需要的同学可看我名字↖↖↖↖↖&#xff0c;或评论888无偿分享 一、引言 随着互联网的发展&#xff0c;越来越多的人开始使用快手这款短视频平台。在这个平台上&#xff0c;用户可以分享自己的生活点滴&#xff0c;观看他人的精彩瞬间。然而&am…

解决noauth authentication required异常

今天在使用redis数据库的时候&#xff0c;突然给报了个这个错误&#xff0c;上网一查才知道是因为 Redis 服务器需要密码进行身份验证&#xff0c;因此&#xff0c;我们需要通过auth password 进行身份验证。不过我这个密码还是试了很多次才想起来的&#xff0c;哦好像是听网课…

利用 LD_PRELOAD劫持动态链接库,绕过 disable_function

目录 LD_PRELOAD 简介 程序的链接 动态链接库的搜索路径搜索的先后顺序&#xff1a; 利用LD_PRELOAD 简单的劫持 执行id命令 反弹shell 引申至 PHP 绕过disable_function 方法1&#xff1a;使用蚁剑的扩展工具绕过disable_function 方法2&#xff1a;利用 mail 函数…