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

news2024/11/25 3:08:35

文章目录

  • 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;
    }

结束。

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

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

相关文章

进阶C语言-指针的进阶(三)

模拟实现qsort函数 &#x1f388;1.测试bubble_sort&#xff0c;排序整型数组&#x1f388;2测试bubble_sort&#xff0c;排序结构体数组 &#x1f4dd;关于qsort函数&#xff0c;我们可以先去cpluplus网站上面了解一下&#xff1a; //1.排序整型数组&#xff0c;两个整型可以…

Linux 上的轻量级浏览器

导读大多数 Linux 桌面环境中包含的基本图像查看器可能不足以满足你的需要。如果你想要一些更多的功能&#xff0c;但仍然希望它是轻量级的&#xff0c;那么看看这四个 Linux 桌面中的图像查看器&#xff0c;如果还不能满足你的需要&#xff0c;还有额外的选择。 当你需要的不…

竞赛选题 深度学习实现语义分割算法系统 - 机器视觉

文章目录 1 前言2 概念介绍2.1 什么是图像语义分割 3 条件随机场的深度学习模型3\. 1 多尺度特征融合 4 语义分割开发过程4.1 建立4.2 下载CamVid数据集4.3 加载CamVid图像4.4 加载CamVid像素标签图像 5 PyTorch 实现语义分割5.1 数据集准备5.2 训练基准模型5.3 损失函数5.4 归…

整理的一些Java细节问题

1. 为什么要有无参构造&#xff1f; 在 Java 中&#xff0c;如果一个类没有显式定义构造方法&#xff0c;编译器会自动生成一个默认的无参构造方法&#xff08;也称为默认构造方法&#xff09;。无参构造方法是一个没有任何参数的构造方法。 无参构造方法的存在有几个重要原因…

【vscode输出中文乱码】

vscode输出中文乱码为一个个的问号。 这个链接亲测有用 win11对应的界面在这里&#xff1a;

产品经理入门学习(二):产品经理问题思考维度

参考引用 黑马-产品经理入门基础课程 1. 抓住核心用户 1.1 为什么要抓住核心用户 什么是用户&#xff1f; 所有和产品有关系的群体就是用户&#xff0c;他们是一群既有共性&#xff0c;又有差异的群体组合 做产品为什么要了解用户&#xff1f; 了解用户的付费点、更好的优化产…

文件同步工具推荐:挑选高效实用的工具大揭秘

随着工作的累积&#xff0c;会持续产出大量电子资料和文件。如何妥善管理这些文件资料&#xff0c;成了一个问题。有需求就有市场&#xff0c;当下市场上也有很多文件同步工具。 有什么好用的文件同步工具&#xff1f; Zoho WorkDrive 同步网盘就是一款好用的文件同步工具&am…

Leetcode—199.二叉树的右视图【中等】

2023每日刷题&#xff08;十九&#xff09; Leetcode—199.二叉树的右视图 深度优先遍历实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(…

【数据结构】冒泡排序

冒泡排序 前言冒泡排序运行图例算法实现基本思路算法实现步骤算法码源详解冒泡排序效率分析&#xff08;一&#xff09;时间复杂度——O&#xff08;N^2&#xff09;&#xff08;二&#xff09;空间复杂度——O&#xff08;1&#xff09;&#xff08;三&#xff09;稳定性&…

人工智能基础_机器学习018_手写代码实现_MBGD小批量梯度下降---人工智能工作笔记0058

然后我们继续来看这里的小批量梯度下降,小批量梯度下降,其实就是 用少量的样本数据,进行梯度下降,上面是公式 然后我们来看代码 import numpy as np 导入数学计算包 #X,y创建数据集X=np.random.rand(100,1) x是100行1列 w,b=np.random.randint(1,10,size=2) 然后获取w和截距…

干货分享:10个行业可视化大屏模板(附 Python 源码)

大家好&#xff0c;数据大屏是一种用于展示和分析数据的可视化工具&#xff0c;通常用于监控、分析和报告数据。大屏可以帮助组织更好地理解和管理其数据&#xff0c;支持数据驱动决策&#xff0c;提高业务效率和决策的质量。 本文的所有大屏都是基于Python开发&#xff0c;因…

根据一个类型 获取该类型的 特殊判断 优雅写法

需求&#xff1a;一个统计接口&#xff0c;时间类型参数有以下&#xff1a;今日、近七天、近三十日等 如果我要查询的话&#xff0c;SQL 里的条件必定是一个时间范围&#xff0c;所以就需要根据类型来算好这个时间范围&#xff0c;所以可以写成下面这样。 到时候直接就是 获取…

前端vue,后端springboot。如何防止未登录的用户直接浏览器输入地址访问

前端&#xff0c;使用Vue框架来实现前端路由拦截&#xff1a; 设置需要登录校验的页面&#xff1a; 登录成功后&#xff0c;去设置LocalStorage里面的IsLogin为true:

[LeetCode]-链表中倒数第k个结点-CM11 链表分割-LCR 027. 回文链表

目录 链表中倒数第k个结点 题目 思路 代码 CM11 链表分割 题目 思路 代码 LCR 027.回文链表 题目 思路 代码 链表中倒数第k个结点 链表中倒数第k个结点_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId…

Web3游戏的十字路口:沿用传统IP还是另起炉灶?

人们经常问我对 Web3 游戏有什么看法。因此&#xff0c;我想以书面形式概述一下我目前的想法。 让我先澄清一下&#xff1a;我不是专家。这不是一篇深入探讨游戏世界精细指标如 MAU 或 D14 等的全面分析。请把这看作是我根据个人交流和研究&#xff0c;这反映我在游戏领域关注…

学习Opencv(蝴蝶书/C++)相关——1. 前言 和 第1章.概述

文章目录 1. 整体架构1.1 OpenCV3.01.2 Opencv4.xX. Opencv cheatsheet(小抄)1. 整体架构 1.1 OpenCV3.0 对于Opencv3.x版本,网上最常见的图,图自OpenCV Tutorial-Itseez 现在已经不是500+的算法了,而是2500+,详见:About

喜报|英码科技荣登“广州首届百家新锐企业名单”、“2022年度中国好技术项目库名单”榜单

近日&#xff0c;英码科技喜报连连&#xff0c;在刚刚公布的2022年度“中国好技术”项目库入选名单和广州首届百家新锐企业名单中&#xff0c;英码科技凭借出色的技术创新能力和优秀的企业竞争力荣登榜单。 2022年度“中国好技术” 近期&#xff0c;2022年度“中国好技术”征集…

如何从站长的角度选择高防CDN以节省成本

在当今的数字化世界中&#xff0c;网站站长需要面对越来越复杂的网络安全威胁&#xff0c;如DDoS攻击、恶意爬虫和恶意请求等。为了保护网站的可用性和数据安全&#xff0c;站长通常会寻求使用高防CDN&#xff08;内容分发网络&#xff09;。然而&#xff0c;如何在选择高防CDN…

隐私保护多领域推荐的紧密度共聚类联邦概率偏好分布模型

论文链接 Federated Probabilistic Preference Distribution Modelling with Compactness Co-Clustering for Privacy-Preserving Multi-Domain Recommendation 引言 这篇论文提出的概率偏好分布是通过使用高斯分布来表示用户和项目的偏好。在论文中&#xff0c;作者提出了一…

11.1 Linux 设备树

一、什么是设备树&#xff1f; 设备树(Device Tree)&#xff0c;描述设备树的文件叫做 DTS(DeviceTree Source)&#xff0c;这个 DTS 文件采用树形结构描述板级设备&#xff0c;也就是开发板上的设备信息&#xff1a; 树的主干就是系统总线&#xff0c; IIC 控制器、 GPIO 控制…