【贪心算法】贪心算法二

news2024/11/16 10:42:07

贪心算法二

  • 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;
                    else
                        right = 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.coloradmin.cn/o/2157571.html

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

相关文章

828华为云征文 | 使用Flexus X实例搭建Dubbo-Admin服务

一、Flexus X实例简介 华为云推出的Flexus云服务&#xff0c;作为专为中小企业及开发者设计的新一代云服务产品&#xff0c;以其开箱即用、体验卓越及高性价比而著称。其中的Flexus云服务器X实例&#xff0c;更是针对柔性算力需求量身打造&#xff0c;能够智能适应业务负载变化…

pick你的第一个人形机器人——青龙强化学习环境测试

文章目录 一、环境配置二、开始训练三、训练成果 最近感受到的大趋势是具身智能&#xff0c;强化学习&#xff0c;模仿学习做人形机器人&#xff0c;这个赛道很火&#xff0c;颇有前些年全力投入做自动驾驶的架势&#xff0c;正好最近用强化学习解决POMDP问题接触到了强化学习&…

Java研学-数据字典(一)

一 需求分析 1 分析 在项目中会有很多的下拉框&#xff0c;这些下拉框的特点&#xff0c;就是以键值对的形式存在&#xff0c;其中 value&#xff08;如 id&#xff1a;1&#xff0c;2… &#xff09;&#xff0c;key&#xff08;展示给用户的内容&#xff09;&#xff0c;数据…

SSC338D/SSC338Q CA7*2+IPU5M/Multi-sensorISP: HDR/3DNR

SSC338D/SSC338Q系列产品是高度集成的多媒体片上系统&#xff08;SoC&#xff09;产品&#xff0c;适用于IP摄像机、车载摄像机和USB摄像机等高分辨率智能视频录制应用。该芯片包括32位双核RISC处理器、高级图像信号处理器&#xff08;ISP&#xff09;、高性能MJPEG/H.264/H.26…

Maven-三、聚合

Maven 文章目录 Maven前言创建聚合模块设置管理的子模块总结 前言 在使用了maven进行多模块开发后&#xff0c;随着模块变多会变得难以管理&#xff0c;所以需要使用聚合模块进行统一管理。 分模块开发的项目中会有多个模块&#xff0c;那么可以单独使用一个模块专门管理整个工…

毫米波雷达预警功能 —— 倒车预警(RCTA)

文档声明&#xff1a; 以下资料均属于本人在学习过程中产出的学习笔记&#xff0c;如果错误或者遗漏之处&#xff0c;请多多指正。并且该文档在后期会随着学习的深入不断补充完善。感谢各位的参考查看。 笔记资料仅供学习交流使用&#xff0c;转载请标明出处&#xff0c;谢谢配…

【Web】御网杯信息安全大赛2024 wp(全)

目录 input_data admin flask 如此多的FLAG 一夜醒来之全国CTF水平提升1000倍&#x1f60b; input_data 访问./.svn后随便翻一翻拿到flag admin dirsearch扫出来 访问./error看出来是java框架 测出来是/admin;/路由打Spring View Manipulation(Java)的SSTI https:/…

HTML中直接创建一个“onoff”图形开关包括css+script

1. HTML中直接创建一个“onoff”图形开关 下面是一个完整的HTML文档示例 在HTML中直接创建一个“onoff”图形开关&#xff08;通常指的是一个类似于物理开关的UI组件&#xff0c;可以切换开或关的状态&#xff09;&#xff0c;并不直接支持&#xff0c;因为HTML主要用于内容的…

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

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

STM32篇:按键点亮LED灯

输入&#xff08;按键&#xff09;&#xff1a;KEY1---PA0 KEY2---PA1 输出&#xff08;LED灯&#xff09;&#xff1a;LED1---PB8 LED2---PB9

数字孪生技术如何推动企业可持续发展:监控与优化企业可持续目标的新视角

数字孪生助力可持续发展的新机遇 在全球推进可持续发展战略的背景下&#xff0c;企业需要创新型的技术工具来实现高效管理&#xff0c;数字孪生技术成为了实现这一目标的重要工具。数字孪生通过虚拟与现实的互动&#xff0c;将物理世界中的企业活动、运营数据及生产流程进行精…

FreeSWITCH 简单图形化界面29 - 使用mod_xml_curl 动态获取配置、用户、网关数据

FreeSWITCH 简单图形化界面29 - 使用mod_xml_curl 动态获取配置、用户、网关数据 FreeSWITCH GUI界面预览安装FreeSWITCH GUI先看使用手册1、简介2、安装mod_xml_curl模块3、配置mod_xml_curl模块3、编写API接口4、测试一下5、其他注意的地方 FreeSWITCH GUI界面预览 http://m…

LDO选型

LDO原理 mos管工作在可变电阻区&#xff0c;输出端电压会因为输出负载的变化而变化&#xff0c;则可通过误差放大器来控制Rds从而维持输出电压不变&#xff0c;行成一个动态平衡。 低压差 线性调整率 负载调整率 电源&#xff08;纹波&#xff09;抑制比 瞬态响应 外部元器件作…

神经网络(二):卷积神经网络

文章目录 一、图像的本质1.1单通道图像&#xff1a;灰度图1.2多通道图像 二、卷积神经网络2.1基本结构2.2卷积层2.2.1卷积操作2.2.2填充padding2.2.3步幅strides2.2.4多通道图像卷积&#xff1a;单卷积核2.2.5多通道图像卷积&#xff1a;多卷积核2.2.5卷积层的参数与激活函数 2…

算法练习题24——leetcode3296移山所需的最小秒数(二分模拟)

【题目描述】 【代码示例&#xff08;java&#xff09;】 class Solution {// 计算让工人们将山的高度降到0所需的最少时间public long minNumberOfSeconds(int mountainHeight, int[] workerTimes) {long left 0; // 最少时间初始为0long right 0; // 最大时间初始化为0// …

Linux,uboot,kernel启动流程,S5PV210芯片的启动流程,DRAM控制器初始化流程

一、S5PV210芯片的DRAM控制器介绍、初始化DDR的流程分析 1、DRAM的地址空间 1)从地址映射图可以知道&#xff0c;S5PV210有两个DRAM端口。 DRAM0的内存地址范围&#xff1a;0x20000000&#xff5e;0x3FFFFFFF&#xff08;512MB&#xff09;&#xff1b;DRAM1:的内存地址范围…

AI大模型教程 Prompt提示词工程 AI原生应用开发零基础入门到实战【2024超细超全,建议收藏】

在AGI&#xff08;通用人工智能&#xff09;时代&#xff0c;那些既精通AI技术、又具备编程能力和业务洞察力的复合型人才将成为最宝贵的资源。为此&#xff0c;我们提出了‘AI全栈工程师’这一概念&#xff0c;旨在更精准地描述这一复合型人才群体&#xff0c;而非过分夸大其词…

全栈项目小组【算法赛】题目及解题

题目&#xff1a;全栈项目小组【算法赛】 题目&#xff1a; 解题思路 1.遍历简历信息&#xff1a;我们需要读取所有简历&#xff0c;根据期望薪资和岗位类型进行分类和统计。 2.分类统计&#xff1a;使用哈希表来存储每个薪资下的前端&#xff08;F&#xff09;和后端&#…

传统产品经理如何快速转行成为顶尖的AI产品经理?

前言 产品经理本身便是一个需要不断学习、不断实践的岗位&#xff0c;即使是AI产品经理&#xff0c;也不能脱离产品经理岗位的本质。 另外&#xff0c;要想知道具体如何转行成为顶尖的AI产品经理&#xff0c;我们首先要明确两个问题&#xff0c;即&#xff1a; 什么是AI产品…

HTML5简介的水果蔬菜在线商城网站源码系列模板3

文章目录 1.设计来源1.1 主界面1.2 商品列表1.3 商品信息1.4 购物车1.5 其他页面效果 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.ne…