C++算法 —— 贪心(2)

文章目录

  • 1、柠檬水找零
  • 2、将数组和减半的最少操作次数
  • 3、最大数
  • 4、摆动序列
  • 5、最长递增子序列
  • 6、递增的三元子序列
  • 7、最长连续递增子序列


1、柠檬水找零

860. 柠檬水找零

在这里插入图片描述

如果一开始顾客给了10块,那就直接结束。给了5块那就收下。之后每一个位置,都需要先看看是否能找零,找不到就false。能找零,遇到10块那就找一个5块,遇到20块则有两个方法,10和5,3个5。既然是贪心策略,那么要尽量地保证能找零。如果选择3个5,下一个顾客给了10块就无法继续了,如果是10和5,那么下一个顾客给10块就可以找。所以应当选择10+5。

    bool lemonadeChange(vector<int>& bills) {
        int five = 0, ten = 0;//不会出现找20的情况
        for(auto x : bills)
        {
            if(x == 5) five++;
            else if(x == 10)
            {
                if(five == 0) return false;
                five--;
                ten++;
            }
            else
            {
                if(ten && five)
                {
                    ten--;
                    five--;
                }
                else if(five >= 3)
                {
                    five -= 3;
                }
                else return false;
            }
        }
        return true;
    }

2、将数组和减半的最少操作次数

2208. 将数组和减半的最少操作次数

在这里插入图片描述

要想尽快减到一半,应当选择当前数组最大的那个数来减半,直到数组和减到一半为止。要选择最大的数字,我们可以弄个大根堆,这样堆顶就是最大的数字,拿一个数字减一半后再把它放回堆中排序。

    int halveArray(vector<int>& nums) {
        priority_queue<double> heap;
        double sum = 0.0;
        for(int x : nums)
        {
            heap.push(x);
            sum += x;
        }
        sum /= 2.0;
        int count = 0;
        while(sum > 0)
        {
            double t = heap.top() / 2.0;
            heap.pop();
            sum -= t;
            count++;
            heap.push(t);
        }
        return count;
    }

3、最大数

179. 最大数

在这里插入图片描述

这个题的意思是把数字拼接起来要最大,比如第一个例子有102和210,210 > 102,所以选择210。

这道题的重点就是排序的规则。按照给的例子,我们可以发现,两个数字a和b,如果ab > ba,那么a应当在前,b在后;如果相等,就不做操作;如果ab <ba,和第一个一样,b在前,a在后。贪心策略体现在两者比较时,只是不够明显。

这样的比较随着数字越来越大,不仅麻烦,而且更有可能溢出,所以这里优化为把数字转化成字符串,拼接字符串,比较字典序。另外,如果是两个0,那我们应当返回一个0,这里的做法就是拼接成字符串后,如果其中第一个字符是0,那整体就是0。

    string largestNumber(vector<int>& nums) {
        vector<string> strs;
        for(int x : nums) strs.push_back(to_string(x));
        sort(strs.begin(), strs.end(), [](const string& s1, const string& s2)
        {
            return s1 + s2 > s2 + s1;
        });
        string ret;
        for(auto& s : strs) ret += s;
        if(ret[0] == '0') return "0";
        return ret;
    }

4、摆动序列

376. 摆动序列

在这里插入图片描述

摆动序列的意思就是整个序列的所有数字,之间都假设有一条线,前面的数字比后面的数字大,那么这条线就是下降的;如果前比后小,那就是上升的,子序列要求一上一下,不能两次都是同样的方向。

要最长,要保证长度,那么我们应当让每一次上升,每一次下降,都找到区域内的一个极大值,一个极小值。也就是波峰波谷。确定波峰波谷可以用左右两边的点去相减,波谷减左边数,右边数减波谷,两者异号才是波峰或波谷。但这之中有连续几个数是相等的,相等的这块区间左右两边也各有上升和下降趋势,只有左右两边趋势不一样,才会有波峰波谷。

    int wiggleMaxLength(vector<int>& nums) {
        //贪心
        int n = nums.size();
        if(n < 2) return n;
        int ret = 0, left = 0;
        for(int i = 0; i < n - 1; ++i)
        {
            int right = nums[i + 1] - nums[i];
            if(right == 0) continue;
            if(right * left <= 0) ret++;
            left = right;
        }
        return ret + 1;
    }

5、最长递增子序列

300. 最长递增子序列

在这里插入图片描述

这道题需要先明白动规解法,以及明白二分查找算法后再来看贪心算法。

回顾一下dp算法,dp[i]表示以i位置的元素为结尾的所有子序列中,最长严格递增子序列的长度;状态转移方程是dp[i] = max(dp[j] + 1, dp[j]),如果j < i并且nums[j] < nums[i]才能dp[j] + 1。在这个算法中,我们不考虑dp[j]表示的序列是什么样的,只考虑最后一个元素。

假设一个数组,[7, 3, 8, 4, 7, 2, 14, 13]。从第一个元素开始,7可以作为一个长度为1的子序列,接下来3比7小,不符合条件,所以3也是一个长度为1的子序列,这时候因为7比3大,比7大的一定比3大,所以7这个序列去掉,用3开头的这个序列继续往后找;接下来是8,我们可以得到一个长度为1,开头为8的子序列,也可以得到一个长度为2,开头为3的子序列。然而贪心会认为,既然8这个数字能接到3后面,那么8就不放到这里,把它单独形成一个序列。继续走,得到4,4放到8后面,和一开始的73一样,8被去掉,4单独一个序列;7能接到3后面,4后面,所以它单独成一个序列;2干掉一开始的3;14单独一个序列;13干掉14。最后的序列就是2 - 4 - 7 - 13,长度为4。

这样的思路中,要存的是所有长度为x的递增子序列中,最后一个元素的最小值,存在所有大于等于nums[i]的最小值的位置。

确定一个新数应当存哪里,貌似需要遍历一次找到应当存到哪里,这样再算上整体的一次遍历,时间复杂度就是O(n ^ 2),那么这个贪心和动规区别在哪里?并没有明显地高效。

其实存在哪里可以用二分查找来找到。通过上面的分析来看,我们可以把每个单独成序列的,也就是那个更大的数字都放进一个数组中,它们都会有自己的下标,而要找新数放到数组的那里就用二分查找来定位存到哪里。二分也能保证严格递增。这样时间复杂度就是n * logn了。

    int lengthOfLIS(vector<int>& nums) {
        //贪心
        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//此时nums[i] <= ret.back()最后一个元素
            {
                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();
    }

6、递增的三元子序列

334. 递增的三元子序列

在这里插入图片描述

这是最长递增子序列的简化版,这个只需要数组中有3个元素就行。dp算法找到最长递增子序列的长度,判断是否>= 3就可以,但这个会超时。贪心算法,这里可以不用二分查找,新数只需要最多比较两次即可。数组也不需要创建,用两个变量ab来代替,新数先跟b比较,如果大于b,就返回true;如果小于b,大于a,b换成x;如果小于a,则a变成x。

    bool increasingTriplet(vector<int>& nums) {
        int a = nums[0], b = INT_MAX;
        for(int i = 1; i < nums.size(); ++i)
        {
            if(nums[i] > b) return true;
            else if(nums[i] > a) b = nums[i];
            else a = nums[i];
        }
        return false;
    }

7、最长连续递增子序列

674. 最长连续递增序列

在这里插入图片描述

这题可以用双指针来解决,i先从第一个位置开始,j从第二个位置开始找比i大的,直到比i小,那么这时候就有了一个长度,而i则跳到j的位置,因为j走过的部分都已经确定是递增的,i跳到这其中无论哪一个位置,都只能到j的位置就停止,长度还不如一开始记录的那个,所以i跳到j位置,j再继续往后走。

    int findLengthOfLCIS(vector<int>& nums) {
        int res = 0, n = nums.size(), i = 0;
        while(i < n)
        {
            int j = i + 1;
            while(j < n && nums[j] > nums[j - 1]) ++j;
            res = max(res, j - i);
            i = j;
        }
        return res;
    }

结束。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Rtthread源码分析<1>启动文件和链接脚本

启动文件和链接脚本 1&#xff09;启动文件 ​ 启动文件里面使用的是汇编语言&#xff0c;汇编语言常常可以分为两个部分语法风格和而不同的toolchain有不同的汇编语法风格&#xff0c;通常分配unified 和 非 unified。常见的工具包有 ARM toolchains 和 GNU toolchains 。比…

一篇博客读懂顺序表 —— Sequence-List

目录 一、顺序表的初始定义 1.1新建头文件和源文件 1.2 SeqList.h 中的准备工作 二、顺序表的初始化与销毁 三、首尾插入元素 四、首尾删除元素 五、中间插入元素 六、中间删除元素 七、查找指定元素下标 八、源代码 一、顺序表的初始定义 1.1新建头文件和源文件 当我…

Swift语言配合HTTP写的一个爬虫程序

下段代码使用Embassy库编写一个Swift爬虫程序来爬取jshk的内容。我会使用proxy_host为duoip&#xff0c;proxy_port为8000的爬虫IP服务器。 使用Embassy库编写一个Swift爬虫程序可以实现从网页上抓取数据的功能。下面是一个简单的步骤&#xff1a; 1、首先&#xff0c;需要在X…

虹科示波器 | 汽车免拆检修 | 2010款江铃陆风X8车发动机怠速抖动、加速无力

一、故障现象 一辆2010款江铃陆风X8车&#xff0c;搭载4G6GS4N发动机&#xff0c;累计行驶里程约为20万km。该车在其他修理厂进行发动机大修&#xff0c;维修后试车&#xff0c;发动机怠速抖动、加速无力。用故障检测仪检测&#xff0c;发动机控制模块&#xff08;ECM&#xff…

JumpServer开源堡垒机与万里安全数据库完成兼容性认证

近日&#xff0c;中国领先的开源软件提供商FIT2CLOUD飞致云宣布&#xff0c;JumpServer开源堡垒机已经与万里安全数据库软件GreatDB完成兼容性认证。针对产品的功能、性能、兼容性方面&#xff0c;经过双方共同测试&#xff0c;万里安全数据库软件&#xff08;简称&#xff1a;…

Vue组件化开发,组件的创建,注册,使用,详解Vue,vm,VueComponent,vc

组件化开发 模块是指将一个大的js文件按照模块化拆分规则进行拆分成的每个js文件, 凡是采用模块方式开发的应用都可以称为模块化应用(组件包括模块) 传统方式开发的一个网页通常包括三部分: 结构(HTML)、样式(CSS)、交互(JavaScript) 关系纵横交织复杂&#xff0c;牵一发动全…

组件与Props:React中构建可复用UI的基石

目录 组件&#xff1a;构建现代UI的基本单位 Props&#xff1a;组件之间的数据传递 Props的灵活性&#xff1a;构建可配置的组件 组件间的通信&#xff1a;通过回调函数传递数据 总结&#xff1a; 组件&#xff1a;构建现代UI的基本单位 组件是前端开发中的关键概念之一。…

如何使用Ruby 多线程爬取数据

现在比较主流的爬虫应该是用python&#xff0c;之前也写了很多关于python的文章。今天在这里我们主要说说ruby。我觉得ruby也是ok的&#xff0c;我试试看写了一个爬虫的小程序&#xff0c;并作出相应的解析。 Ruby中实现网页抓取&#xff0c;一般用的是mechanize&#xff0c;使…

手机转接器实现原理,低成本方案讲解

USB-C PD协议里&#xff0c;SRC和SNK双方之间通过CC通信来协商请求确定充电功率及数据传输速率。当个设备需要充电时&#xff0c;它会发送消息去给适配器请求充电&#xff0c;此时充电器会回应设备的请求&#xff0c;并告知其可提供的档位功率&#xff0c;设备端会根据适配器端…

SpringBoot集成-阿里云对象存储OSS

文章目录 阿里云 OSS 介绍准备工作SpringBoot 集成 OSS 阿里云 OSS 介绍 阿里云对象存储 OSS &#xff08;Object Storage Service&#xff09;&#xff0c;是一款海量、安全、低成本、高可靠的云存储服务。使用 OSS&#xff0c;你可以通过网络随时存储和调用包括文本、图片、…

单行自动横向滚动——css实现

效果 封装组件 <template><div ref"container" class"scroll-area"><divref"content":class"[isScroll ? scroll : no-scroll]":style"{ color: fontColor }">{{ content }}</div></div> &…

【2023-10-31】某钩招聘网站加密参数分析

声明:该专栏涉及的所有案例均为学习使用,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!如有侵权,请私信联系本人删帖! 文章目录 一、前言二、网站分析1.X-S-HEADER参数2.请求参数data3.响应机密值data一、前言 网址: aHR0cHM6Ly93d3cubGFnb3UuY29t…

11.Z-Stack协议栈使用

f8wConfig.cfg文件 选择信道、设置PAN ID 选择信道 #define DEFAULT_CHANLIST 0x00000800 DEFAULT_CHANLIST 表明Zigbee模块要工作的网络&#xff0c;当有多个信道参数值进行或操作之后&#xff0c;把结果作为 DEFAULT_CHANLIST值 对于路由器、终端、协调器的意义&#xff1…

【MySQL索引与优化篇】数据库的设计规范

数据库的设计规范 文章目录 数据库的设计规范1. 范式2. 键和相关属性的概念3. 第一范式4. 第二范式5. 第三范式6. 小结7. 反范式化7.1 概述7.2 反范式的新问题7.3 反范式适用场景 8. 巴斯范式9. 第四范式、第五范式和域键范式 1. 范式 在关系型数据库中&#xff0c;关于数据表…

免费获得临时域名/内网穿透

文章目录 Coplar 介绍Coplar 使用场景Coplar 使用 Coplar 介绍 》官网地址《 官网介绍&#xff1a; cpolar极点云: 公开一个本地Web站点至公网 只需一行命令&#xff0c;就可以将内网站点发布至公网&#xff0c;方便给客户演示。高效调试微信公众号、小程序、对接支付宝网关…

Jmeter之JSR223

一、JSR223组件 JSR是Java Specification Requests的缩写,意思是Java规范提案。JSR已成为Java界的一个重要标准. JSR223其实包含了有好几种组件,但是其用法都是一致的,并且都是执行一段代码&#xff0c;主要分类如下&#xff1a; JSR223 PreProcessor JSR223 Timer JSR223 S…

使用Gorm进行CRUD操作指南

使用GORM在Go中创建、读取、更新和删除记录的逐步教程 在数据库管理中&#xff0c;CRUD操作是应用程序的支柱&#xff0c;它们使数据的创建、检索、更新和删除成为可能。强大的Go对象关系映射库GORM通过抽象SQL语句的复杂性&#xff0c;使这些操作变得轻松。本文将作为您全面指…

基于ASP.NET MVC + Bootstrap的仓库管理系统

基于ASP.NET MVC Bootstrap的仓库管理系统。源码亲测可用&#xff0c;含有简单的说明文档。 适合单仓库&#xff0c;基本的仓库入库管理&#xff0c;出库管理&#xff0c;盘点&#xff0c;报损&#xff0c;移库&#xff0c;库位等管理&#xff0c;有着可视化图表。 系统采用Bo…

Linux学习笔记之二(环境变量)

Linux learning note 1、环境变量1.1、修好PATH环境变量 1、环境变量 环境变量(environment variables)即系统运行的一些环境参数。主要的环境变量有以下这些&#xff1a; PATH&#xff1a;决定了系统查找可执行文件的目录范围。HOME&#xff1a;指定当前用户的主目录路径。U…

vue中的rules表单校验规则使用方法 :rules=“rules“

一、el-form里面必写属性值 :ref"dataForm" // 提交表单时进行校验 :rules"rules" // return 下的校验规则 :model"userForm" // 绑定表单的值 <el-formref"dataForm" // 必写属性值:rules"rules"…