【贪心算法】贪心算法二

贪心算法二

  • 1.最长递增子序列
  • 2.递增的三元子序列
  • 3.最长连续递增序列

在这里插入图片描述

点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃

1.最长递增子序列

题目链接: 300. 最长递增子序列

题目分析:

在这里插入图片描述

听懂这道题一定要把动态规划里面这道题解法搞清楚,我们的贪心策略其实是基于动态规划的解法,就是动态规划的解法的过程中发现可以用贪心优化的地方。还有优选算法那里的二分查找搞清楚。我们这里的贪心策略是要用这两个东西。

算法原理:

  1. 回顾 dp 的解法

状态表示:dp[i] 表示:以 i 位置的元素为结尾的所有子序列中, 最长递增子序列的长度

状态转移方程:dp[i] = max(dp[j] + 1) (j < i && nums[j] < nums[i])

更新dp[i] 的值,就是拿着nums[i] 去前面找,当找到一个位置发现这个位置的值,nums[j] < nums[i] 说明 i 可以拼在 j 的后面,此时就用这个dp[j]也就是以 j 位置为结尾的最长递增子序列的长度 然后 + 1 更新 dp[i] 的值。当把前面都找完此时dp[i]的值就是以 i 位置的元素为结尾的所有子序列中, 最长递增子序列的长度。

最核心的操作中,我们会发现一个性质:我们在考虑最长递增子序列的 “长度” 的时候,并不关心你这个序列长什么样子,我们仅关心你的 “最后一个元素” 是谁。

  1. 贪心优化

接下来我们用一个例子模拟一下贪心过程

从前到后扫描每一个元素,当扫描第一个位置的元素时候其实我们得到一个长度为1 的序列长什么样子。(但是我们只关心递增子序列长度为x中最后一个元素,并不关心序列长什么样子),这一点在上面已经说过了。

在这里插入图片描述

扫描到3的时候发现,3是接不到7后面,所以3这个元素单独形成一个长度为1的序列,现在又找到一个长度为1的序列最后一个元素是3。此时贪心策略就来了,当我发现长度为1递增子序列有两个的时候,较大的就没有必要存了。

原因就是,所有能接到7后面的数,铁定能接到3这个数的后面,所以我们不需要存较大的7,仅需存较小的3就可以判断后面的数是否能拼到长度为1的序列后面。

这里就是我们的第一个贪心策略,存最后一个元素的时候,仅需存储最小值。

在这里插入图片描述

扫描8的时候,此时第二个贪心策略来了。我们其实有两种策略,第一种让8单独形成一个长度为1的序列,第二种要么让8拼到3的后面形成一个长度为2的序列。此时我们贪心选择第二种策略。因为要找最长递增子序列。

在这里插入图片描述

扫描到4,发现4能放到长度为1的3后面,但是不放,太浪费了,所以往下放,发现4可以自己形成一个长度为2,但是发现4小于8,所以贪心把8干掉,把4放好。

上面的过程就是,发现4能放到长度为1的3后面,但是不放。往下放,发现4能不能放到8后面,就把4放到这里,同时利用第二个贪心策略只存最小值的时候,把8干掉,4留下。

在这里插入图片描述

扫描到7,也是一样,7能拼到3后面就不放,7能拼到4后面也不放,所以7形成一个长度为3的序列

在这里插入图片描述
扫描到2,发现2拼不到3后面,只能把2放到长度为1,但是2比3小,能拼接到3后面一定能拼接到2后面,所以3干掉,保留2

在这里插入图片描述

扫描到14,发现能拼接到2,4,7后面但是都不放,所以14单独形成一个长度为4的序列

在这里插入图片描述

扫描到13,发现能拼接到2,4,7后面但是不放,不能放14后面,就放14后面,同时13比14小,14干掉,13保留

在这里插入图片描述

当整个数组扫描完,我们发现长度仅从1更新到4,所以最长递增子序列的长度就是4。

虽然这里拼接的序列并不是最终的序列,但是能统计到4,就是我们的最长递增子序列的长度。

这里我们总结一下贪心策略:

我们的贪心策略就体现在两个地方:存什么,存哪里

在这里插入图片描述

这里的贪心策略的提出就是交换论证法的思想,比如能拼接7的后面的数,铁定能拼接到3的后面,这不就是交换论证吗。

这里已经说明为什么贪心策略是对的,但是我们分析一下贪心的时间复杂度,存什么肯定是拿一个数组去存,下标为0存长度为1的最小值、下标为1存长度为2的最小值…,最耗时的就是存哪里,如果是来了一个数从前往后扫描比较时间复杂度是O(n),那整体时间复杂度还是O(N^2),这个好像和动规是一样的。那还贪心什么呢?比动规还难理解。

我们还可以发现,我们贪心得到的数组,其实还有优化的地方

  1. 利用二分优化

我们发现存长度为x的最小值数组里面的值是递增有序的。此时我们在找存哪里插入位置的时候,可以用二分快速找到插入位置。

假设来一个x,我们要找的是所有大于等于x的最小值,右边都是大于等于x,左边是小于x,这就有了二段性。就可以用二分查找了。

在这里插入图片描述

证明数组是递增的。

直接证明:

第一个元素来了直接就是一个点,第二个元素来发现能拼在第一个元素后面所以重新开一个点,如果不能放就把这个元素覆盖到原始元素,这里有个不等关系,这个元素大于前一个元素,小于后一个元素。递增是不会改变的。

在这里插入图片描述

回归一下二分,定义一个left,right,mid,如果mid落在左边 left = mid + 1,如果mid落在右边有可能是结果 right = mid,等到循环解决,left或者right就是要插入的位置。

在这里插入图片描述

这里有个细节问题,再用二分的时候要考虑边界情况,因为我们要找的是大于等于nums[i]的最小值的位置,left和right其实是在这个数组中找,有没有这个数比这个数组中所有数都大,那此时应该是数组重新开一个空间,放在这个新开位置里,所以二分之前先判断 nums[i] > ret.back(),此时不用二分,直接放在数组后一个位置。否则在二分寻找插入位置。

class Solution {
public:int lengthOfLIS(vector<int>& nums) {int n = nums.size();vector<int> ret;ret.push_back(nums[0]);for(int i = 1; i < nums.size(); ++i){if(nums[i] > ret.back()) // 如果能接在最后⼀个元素后⾯,直接放ret.push_back(nums[i]);else{// 二分插入位置int left = 0, right = ret.size() - 1;while(left < right){int mid = (left + right) / 2;if(ret[mid] < nums[i])left = mid + 1;elseright = mid;                        }ret[left] = nums[i];}}return ret.size();}
};

2.递增的三元子序列

题目链接:334. 递增的三元子序列

题目分析:

在这里插入图片描述

上面是要找到最长的递增子序列,这里仅需判断一下是否存在长度为3的递增子序列就可以了。

算法原理:

最长递增子序列有两种解法,这里也是有两种解法。

解法一:动规

利用 dp 找到数组中最长递增子序列的长度,判断是否大于等于 3 即可

时间复杂度 O(n^2),会超时的。

解法二:贪心

因为这里我们仅需判断递增子序列长度是否等于3就可以了,因此可以不用二分也是非常快的。我们只要判断长度3这里是否有值就可以了,不需要关心里面是否最小也不需要关心长度4、5、6…的情况。任意来一个x,我们仅需要比较2次,最差每个数都比较2次,总体就是2n,时间复杂度就是O(n),即使用二分也是O(log2n),差别不是很大。

在这里插入图片描述

那如何实现呢?
第一种:可以像最长递增子序列一样用数组
第二种:仅需两个变量a,b

a代表长度为1最小元素,b代表长度为2最小元素。
a初始为第一个元素,b初始为INT_MAX

在这里插入图片描述
来了一个数,先和b比较,一旦这个数大于b,说明可以放在长度3,直接返回true,如果不大于b说明是小于等于b,然后和a做比较,如果大于a说明可以放在b的位置,如果小于a说明可以放在a的位置。

在这里插入图片描述

class Solution {
public:bool increasingTriplet(vector<int>& nums) {int n = nums.size();int a = nums[0], b = INT_MAX;for(int i = 1; i < n; ++i){if(nums[i] > b) return true;else if(nums[i] > a) b = nums[i];else a = nums[i];}return false;// int n = nums.size();// vector<int> ret;// ret.push_back(nums[0]);// for(int i = 1; i < n; ++i)// {//     if(nums[i] > ret.back())//         ret.push_back(nums[i]);//     else//     {//         int left = 0, right = ret.size() - 1;//         while(left < right)//         {//             int mid = (left + right) >> 1;//             if(ret[mid] < nums[i])//                 left = mid + 1;//             else//                 right = mid;//         }//         ret[left] = nums[i];//     }// }// return ret.size() >= 3 ? true : false;}
};

3.最长连续递增序列

题目链接: 674. 最长连续递增序列

题目分析:

在这里插入图片描述

给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。如果是连续的子序列其实就是子数组了,那这道题其实就变得简单了。

算法原理:

我们可以用暴力的思路来解决。用指针i固定一个数,然后再来一个指针j,让这个指针j向后移动,去找以i位置为起点的最长连续的递增序列。

怎么找?很简单,只要j位置元素比j-1位置元素大,j就往后移动,当j位置元素比j-1位置元素小就结束,此时就找完了以i位置为起点的最长连续的递增序列。

在这里插入图片描述

注意此时指针i并不直接向后移动1位,这里有一个小贪心,我们会发现 固定 i 位置然后找到这一段已经是递增并且是最长的,此时如果让i向后移动1位,那找的还是之前 i 位置的递增连续子序列,并且比之前的短,因此 i 移动到 j 位置,以 j 位起点在往后找。

在这里插入图片描述

所以我们这里的策略:贪心 + 双指针

class Solution {
public:int findLengthOfLCIS(vector<int>& nums) {int n = nums.size();int i = 0, j = 0, ret = 0;while(i < n){j = i + 1;// 找到递增区间的末端while(j < n && nums[j] > nums[j - 1]) ++j;ret = max(ret, j - i);i = j;// 直接在循环中更新下⼀个位置的起点}return ret;}
};

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

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

相关文章

从零基础到大模型大师,看完这篇,效率提高99%!!

一、 前置知识 - 数学&#xff1a;主要包括线性代数、概率统计等内容。 - 自然语言处理&#xff1a;主要包括Word2vec、Seq2seq等内容。 - Python&#xff1a;Python语言是大模型应用的编程基础&#xff0c;需要熟练掌握深度学习相关的框架&#xff0c;如PyTorch、TensorFlow。…

【C++ Primer Plus习题】17.1

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: #include <iostream> using namespace std;int main() {char …

智慧城市主要运营模式分析

(一)运营模式演变 作为新一代信息化技术落地应用的新事物,智慧城市在建设模式方面借鉴了大量工程建设的经验,如平行发包(DBB,Design-Bid-Build)、EPC工程总承包、PPP等模式等,这些模式在不同的发展阶段和条件下发挥了重要作用。 在智慧城市发展模式从政府主导、以建为主、…

[数据集][目标检测]中草药类型识别检测数据集VOC+YOLO格式7976张45类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;7976 标注数量(xml文件个数)&#xff1a;7976 标注数量(txt文件个数)&#xff1a;7976 标注…

音乐项目,总结

今天的写的思路都挺简单的但是比较繁琐&#xff0c;这个查找&#xff0c;传文件的话可以了&#xff0c;但是没有用分片传送&#xff0c;然后在写音乐播放的处理&#xff0c;<歌单&#xff0c;二级评论&#xff0c;歌曲歌词滚轮播放>三个还没有实现&#xff0c;时间挺紧张…

[Angular] 从零开始使用 Angular CLI 创建 Angular 项目

一、安装 Node.js &#x1f4da; Node.js 是一个运行 JavaScript 代码的 JavaScript 运行时&#xff0c;它允许我们在服务器端运行 JavaScript 代码。以下是安装 Node.js 的步骤&#xff1a; &#x1f310; 访问 Node.js 国内网站&#xff1a;https://nodejs.cn/ &#x1f4…

【2023工业图像异常检测文献】SimpleNet

SimpleNet:ASimpleNetworkforImageAnomalyDetectionandLocalization 1、Background 图像异常检测和定位主要任务是识别并定位图像中异常区域。 工业异常检测最大的难题在于异常样本少&#xff0c;一般采用无监督方法&#xff0c;在训练过程中只使用正常样本。 解决工业异常检…

【CSS in Depth 2 精译_034】5.4 Grid 网格布局的显式网格与隐式网格(下)

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09; 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位&#xff08;已完结&#xff09; 2.1 相对…

Qt-QTextEdit的输入类控件(30)

目录 描述 相关属性 相关信号 使用 文本内容改变时触发 选中内容时发生改变 光标位置发生改变时触发 可复制&#xff0c;可撤销&#xff0c;可恢复发生改变时触发 undo撤销 redo恢复 copy复制 描述 这是一个多行输入框 有两个很像的&#xff0c;需要注意一下&…

边缘计算网关在工业中的应用

在工业4.0和智能制造的浪潮中&#xff0c;边缘计算网关扮演着至关重要的角色。AIoTedge边缘计算网关&#xff0c;作为工业互联网的关键组件&#xff0c;通过其强大的数据处理能力和智能分析功能&#xff0c;正在改变工业生产的面貌。 边缘计算网关的定义与角色 边缘计算网关是…

Python学习——【4.3】数据容器:str字符串

文章目录 【4.3】数据容器&#xff1a;str字符串一、再识字符串二、字符串的下标&#xff08;索引&#xff09;三、字符串的常用操作四、字符串的遍历五、字符串的特点 【4.3】数据容器&#xff1a;str字符串 一、再识字符串 虽然之前已经学习过字符串&#xff0c;但此处我们需…

自制工具 | 局域网文本、文件传输与共享,跨设备剪切板(预览版)

本文将介绍一款自制文本和文件传输工具&#xff0c;可实现局域网内文本/文件传输与共享。支持传输文本&#xff0c;可一键复制、粘贴&#xff0c;文本字数无限制&#xff0c;以缩略形式展示。支持传输文件&#xff0c;文件大小无限制。工作在局域网&#xff0c;含操作校验&…

买家账号被feng?探讨亚马逊、Lazada和速卖通的解决方案

账号登录的安全注意事项 当亚马逊买家账号在多个手机或电脑上进行登录时&#xff0c;这些设备的独特硬件网络参数&#xff0c;如设备型号、地区码、监管码、主板码、WIFI地址等&#xff0c;均会被亚马逊系统读取并记录。特别是在风控加强期间&#xff0c;平台会深入分析这些参…

MemFire Cloud,让Coding更丝滑

作为一个开发者&#xff0c;每天与代码打交道的你&#xff0c;是否总觉得开发流程太繁琐&#xff1f;后端搭建复杂&#xff0c;接口设计麻烦&#xff0c;甚至连数据库配置都让你心烦不已。别担心&#xff0c;今天要给你推荐一个真正能让开发变得丝滑的工具——MemFire Cloud。如…

【Python数据分析】pandas apply自定义函数+分组操作+分析案例

文章目录 1.apply()1.1函数 操作series对象1.2 apply()函数 > 操作DataFrame对象1.3 向量化函数1.4 apply()函数的案例-泰坦尼克号数据集1.5 apply()函数 结合 lambda表达式使用. 2. 分组操作2.1 分组 聚合操作2.2 分组 转换2.3 分组 过滤2.4 DataFrameGroupby df的分组对…

Java面试题大全(全网最全,持续更新)中级(2)

1. 集合与泛型 1.1. 什么是泛型&#xff1f;泛型的优势是什么&#xff1f; 泛型允许类、接口和方法在定义时不指定具体的类型&#xff0c;在使用时再指定类型。优势&#xff1a; 提高代码复用性。提供类型安全&#xff0c;避免强制类型转换带来的 ClassCastException。 pub…

word批量裁剪图片,并调整图片大小,不锁定纵横比

在word中有若干图片待处理&#xff0c;裁剪出指定内容&#xff0c;调整成指定大小。如下是待处理的图片&#xff1a; 这时&#xff0c;选择视图&#xff0c;选择宏&#xff0c;查看宏 选择创建宏 添加cut_picture代码如下&#xff0c;其中上、下、左、右裁剪的橡塑尺寸根据自己…

李飞飞创业公司World Labs:引领AI新方向的“大世界模型”

引言 随着人工智能的不断进步&#xff0c;AI领域涌现了许多新兴技术和研究方向。在这其中&#xff0c;李飞飞创办的World Labs凭借其独特的“空间智能”和“大世界模型”&#xff08;Large World Model, LWM&#xff09;理念&#xff0c;迅速成为焦点。尤其是在获得了2.3亿美元…

系统架构设计师教程 第10章 10.5 软件架构演化评估方法笔记

10.5 软件架构演化评估方法 ★★★☆☆ 10.5.1 演化过程已知的评估 目的在于通过对架构演化过程进行度量&#xff0c;比较架构内部结构上的差异以及由此导致的外部质量属性上的变化&#xff0c;对该演化过程中相关质量属性进行评估。 1.评估流程 架构演化评估的基本思路是将架…

IDEA快速查看类中有那些方法的快捷键

IDEA快速查看类中有那些方法的快捷键 1.显示类结构弹出窗口 你可以使用以下快捷键来快速查看当前类的方法和成员&#xff1a; Windows/Linux: Ctrl F12 macOS: Option F12 或 ⌥ F12 这会打开一个弹出窗口&#xff0c;显示当前类的结构&#xff0c;包括方法、字段、构造函…