基础贪心算法集合2(10题)

目录

1.单调递增的数字

2.坏了的计算器

 3.合并区间

4.无重叠区间

5. 用最少数量的箭引爆气球

 6.整数替换

解法1:模拟+记忆化搜索

解法2位运算+贪心

7.俄罗斯套娃信封问题

补充.堆箱子

8.可被3整除的最大和

 9.距离相等的条形码

 10.重构字符串


1.单调递增的数字

 738. 单调递增的数字 - 力扣(LeetCode)

但是如果只这么处理会出现bug 

例如如下这种情况,我们需要找到最前面的5.

因此

class Solution {
public:int monotoneIncreasingDigits(int n) {string num = to_string(n);int sz = num.size();int i = 0;while(i+1 < sz && num[i] <= num[i+1])i++;if(i+1 == sz)return n;//如果全递增直接返回,或者处理nums[i]的时候判断一下while(i - 1 >= 0 && num[i-1] == num[i])i--;num[i]--;for(int k = i + 1; k < sz; k++){num[k] = '9';}return stoi(num);//std::stoi 会忽略前导零,只返回字符串表示的整数值}
};

2.坏了的计算器

 991. 坏了的计算器 - 力扣(LeetCode)

看到这题我们首先就想到正向推导。

我们贪心地想到,如果想让初始数字以尽可能少的次数变成目标数字,可以多用*2操作。

但是我们发现这种贪心是不对的,对于*2和-1的操作,判断标准不是很明确。 用正向的方法比较难解决这个问题

        于是我们想到正难则反,而*2 和-1的操作正好有相反的/2和+1操作。 

        这一题有个非常重要的点就是它里面的数据是没有小数的,从起始数据到目标数据,不断*2,-1操作下是不能产生小数的。

          所以我们在面对奇数的时候,就不能进行/2操作了,只能进行+1操作。

整理思路,我们得出以下结论:

1.当end <= begin

当 end <= begin时,end要想达到begin,肯定不可能进行/2操作,只能进行+1操作,这时候无论奇数偶数,都只有+1的选择。我们需要进行begin-end次操作

 2.当end > begin 的时

当end > begin 的时候

 我们如果想要先+1再/2,那么我们必须要加偶数个1,我们才能/2.最后,我们通过k+1次操作得到了(x+k)/2.

而如果我们先/2,那么我们只需要1+k/2 次就能得到(x+k)/2。

我们很容易得到先进行除法是更优的。

因此在end > begin的时候 ,我们奇数仍然是只能+1,偶数则是只进行/2操作

class Solution {
public:int brokenCalc(int startValue, int target) {int ret = 0;while(target > startValue){if(target % 2 == 0){target /= 2;ret++;}else{target++;ret++;}}ret += startValue - target;return ret;}
};

 3.合并区间

56. 合并区间 - 力扣(LeetCode)

区间问题解法

我们为了思路统一,统一采用左端点排序

 假设我们有一个区间,从left 到right

那么我们下一个区间有以下这些情况。

整体分为有重叠部分和没有重叠部分。

当有重叠部分时,我们保存左端点,取较大的右端点。(因为进行排序后,左端点是升序排序的)

当没有重叠部分时,我们把{left,right}加入ret数组,然后更新left和right。

class Solution {
public:static bool cmp(vector<int> a, vector<int> b){return a[0] < b[0];}vector<vector<int>> merge(vector<vector<int>>& intervals) {//排序sort(intervals.begin(), intervals.end(), cmp);//合并区间vector<vector<int>> ret;int left = intervals[0][0];int right = intervals[0][1];for(int i = 1; i < intervals.size(); i++){if(intervals[i][0] <= right)//有重叠部分{right = max(right,intervals[i][1]);//合并}else//无重叠{ret.push_back({left, right});//加入到结果中left = intervals[i][0];right = intervals[i][1];}}ret.push_back({left, right});return ret;}
};

4.无重叠区间

 435. 无重叠区间 - 力扣(LeetCode)

 

仍然是先按照左端点排序。

我们要移除最少的区间,那也就是说要保留更多的区间。

因此我们可以采用以下策略来保留更多区间。

当存在区间重叠时,我们保留较小的右端点,这样它和后面的 区间有重叠的可能性就会变小。

当区间无重叠,我们更新left right并把count++即可。

遍历数组结束后要记得加上最后存在left right里面的那段区间。

最后,因为我们求的是移除的区间,因此把数组的长度减去count就是我们的返回值

class Solution {
public:int eraseOverlapIntervals(vector<vector<int>>& intervals) {int count = 0;sort(intervals.begin(), intervals.end());int left = intervals[0][0];int right = intervals[0][1];for(int i = 1; i < intervals.size(); i++){if(intervals[i][0] < right){right = min(right,intervals[i][1]);}else{count++;left = intervals[i][0];right = intervals[i][1];}}count ++;return intervals.size() - count;}
};

5. 用最少数量的箭引爆气球

452. 用最少数量的箭引爆气球 - 力扣(LeetCode)

理解题意,我们发现这也是一个区间问题。

我们发现这题找的实际上是交集。

  

class Solution {
public:int findMinArrowShots(vector<vector<int>>& points) {sort(points.begin(), points.end());int cover = 0;int right = points[0][1];for(int i = 1; i < points.size(); i++){if(points[i][0] <= right)//和上一个区间有交集{cover++;//重叠部分++right = min(right, points[i][1]);//右端点较小的同时也是是重叠区间的右端点}else{right = points[i][1];//无交集,以新的区间为基准再求重叠部分}}return points.size() - cover;}
};

 6.整数替换

解法1:模拟+记忆化搜索

就是暴力枚举每种情况,对于偶数直接除以2,对于奇数则是取 min(hash[n-1], hash[n+1])

需要注意的地方是,为了防止INT_MAX + 1 溢出,我们dfs函数的类型使用long long,哈希表也是一样。

class Solution {
public:unordered_map<long long, int> hash;int integerReplacement(int n) {return dfs(n);}int dfs(long long n){if(n == 1)return 0;if(n % 2 == 0){if(!hash.count(n/2)){hash[n/2] = dfs(n/2);}return 1 + hash[n/2];}else{if(!hash.count(n+1) ){hash[n+1] = dfs( n+1 );}if(!hash.count( n-1 ) ){hash[ n-1 ] = dfs( n-1 );}return 1  + min(hash[n-1], hash[n+1]);}}
};

解法2位运算+贪心

对于偶数我们进行/2操作即可。

对于奇数操作, 当其为01结尾的时候,我们采用-1操作操作数会更少。

                                当其为11结尾的时候,-1操作会使得一位1变为0,而+1操作可能会使得多于一位的1变为0,因此采用+1的操作会更快捷地得到最终值。

最后有一个例外,即3,我们应该采用-1操作。

要判断最后两位是01还是11,我们只需要把这些数对4取余即可,看余数是1还是3即可判断。

这道题的贪心就贪在不同的奇数是+1还是-1,已经在过程中证明好了

 同样需要加一个longlong

class Solution {
public:int integerReplacement(int num) {int ret = 0;long long n = num;while(n > 3){if(n % 2 == 0){ret++;n  = n >> 1;}else{if(n % 4 == 3){n = n + 1;ret++;}else if(n % 4 == 1){n = n - 1;ret++;}}}if(n == 3)return ret + 2;else if(n == 2)return ret + 1;else return ret;}
};

7.俄罗斯套娃信封问题

 解法1:区间排序+动态规划(超时)

解法2:区间排序 + 贪心 + 二分

我们严格按照左端点排序后,实际上已经不用看左端点了,因为总是递增的。 

那么这道题经过这样处理,就变成了一个最长递增子序列问题。

 

        但是当左端点有重复的时候需要注意,这时候如果我们的右端点按照升序排,我们就会把一些不该加的元素加入。

         这时候就需要我们在左端点相同的时候把右端点降序排序

 

        这样的好处是,我们就不会有可能把这些数字全部接到原数组后面了。因为如果有更小的数,那么我们会将其与原来的数替换。例如上一个数是3,按照升序排序的话,4679都会排到它后面。

        可是如果我们降序,则我们在将9加入数组后,后面的764都只是更新数组末尾的9而已,让9不断被替换为764.

class Solution {
public:static bool cmp(const vector<int> & a, const vector<int> & b){if(a[0] != b[0])return a[0] < b[0];else return a[1] > b[1];}int maxEnvelopes(vector<vector<int>>& env) {sort(env.begin(), env.end(), cmp);vector<int> ret;ret.push_back(env[0][1]);for(int i = 1; i < env.size(); i++){if(env[i][1] > ret.back()){ret.push_back(env[i][1]);}else{int left = 0; int right = ret.size() - 1;while(left < right){int mid = left + (right-left) / 2;if( env[i][1] <= ret[mid]){right = mid;}else{left = mid + 1;}}ret[left] = env[i][1];}}return ret.size();}
};

补充.堆箱子

 虽然俄罗斯套娃信封中的解法1会超时,但是在堆箱子这题中是可以通过的

面试题 08.13. 堆箱子 - 力扣(LeetCode)

 排序后的思路和最长递增子序列相同

有两个需要注意的问题

class Solution {
public:static bool cmp(vector<int> a, vector<int> b){return a[0] < b[0];}int pileBox(vector<vector<int>>& box) {sort(box.begin(), box.end(),cmp);//1.需要自己手动写一个排序函数,按照某一维度来排。 //默认排序会出问题int n = box.size();if(n == 0)return 0;vector<int> dp(n , 0);for(int i = 0; i < n; i++)//2.初始化dp表的时候,每个箱子最小的堆叠高度是自己的高度{dp[i] = box[i][2];}int ret = dp[0];for(int i = 1; i < n; i++){for(int j = i - 1; j >= 0; j--){if(box[j][0] < box[i][0] && box[j][1] < box[i][1] && box[j][2] < box[i][2]){dp[i] = max(dp[i], dp[j] + box[i][2]);}}ret = max(ret, dp[i]);}return ret;}
};

8.可被3整除的最大和

 1262. 可被三整除的最大和 - 力扣(LeetCode)

 

我们正难则反,根据累加和的不同情况,删去一些数即可,而我们只需要贪心地删除最小值即可。  

        分类情况中, 我们把第二种情况拿来举例子,可能我们有1个或者4个或者7个除以3余1的数,但是我们只需要取出最小的那个。整体来看是把这一组数分成两块,一块是一个除以3余1的数,另一块是可以被3整除的。

        下面的另外三种也是一样的分组方式。

        但是我们要注意,这些情况有可能不会全都有,因此我们可以先将x1 x2 y1 y2等赋值为

10010(题目中数组元素最大为10000),这样我们在最后取max的时候就必然不会取到无效情况。

 

更新最小值以及次小值只需要分类讨论即可 

 

class Solution {
public:int maxSumDivThree(vector<int>& nums) {int sum = 0;int n = nums.size();for(int i = 0; i < n; i++){sum += nums[i];}if(sum % 3 == 0){return sum;}else if(sum % 3 == 1){int x1,y1,y2;x1 = y1 = y2 = 1e4 + 10;for(int i = 0; i < n; i++){int tmp = nums[i];if(tmp % 3 == 1){x1 = min(x1, tmp);}else if(tmp % 3 == 2){if(tmp <= y1){y2 = y1;y1 = tmp;}else if(tmp > y1 && tmp <= y2){y2 = tmp;}}}return max(sum - x1, sum - y1 - y2);}else//取余等于2{int x1,x2,y1;x1 = x2 = y1 = 1e4 + 10;for(int i = 0; i < n; i++){int tmp = nums[i];if(tmp % 3 == 2){y1 = min(y1, tmp);}else if(tmp % 3 == 1){if(tmp <= x1){x2 = x1;x1 = tmp;}else if(tmp > x1 && tmp <= x2){x2 = tmp;}}}return max(sum - x1 - x2, sum - y1);}}
};

 

class Solution {
public:int maxSumDivThree(vector<int>& nums) {int sum = 0;int n = nums.size();for(int i = 0; i < n; i++){sum += nums[i];}if(sum % 3 == 0){return sum;}else if(sum % 3 == 1){int x1,y1,y2;x1 = y1 = y2 = 1e4 + 10;for(int i = 0; i < n; i++){int tmp = nums[i];if(tmp % 3 == 1){x1 = min(x1, tmp);}else if(tmp % 3 == 2){if(tmp <= y1){y2 = y1;y1 = tmp;}else if(tmp > y1 && tmp <= y2){y2 = tmp;}}}return max(sum - x1, sum - y1 - y2);}else//取余等于2{int x1,x2,y1;x1 = x2 = y1 = 1e4 + 10;for(int i = 0; i < n; i++){int tmp = nums[i];if(tmp % 3 == 2){y1 = min(y1, tmp);}else if(tmp % 3 == 1){if(tmp <= x1){x2 = x1;x1 = tmp;}else if(tmp > x1 && tmp <= x2){x2 = tmp;}}}return max(sum - x1 - x2, sum - y1);}}
};

 9.距离相等的条形码

 1054. 距离相等的条形码 - 力扣(LeetCode)

 

如果出现最多的数超过(n+1)/2,那么必定有两个相同元素会相邻 

 

我们只需要把最大的那个元素先排好,然后去排其它的即可,我们的i如果越界,那么将其置为1即可 

class Solution {
public:vector<int> rearrangeBarcodes(vector<int>& barcodes) {int maxval = -1; int maxcount = 0;unordered_map<int, int> hash;for(auto ch : barcodes ){if( maxcount < ++hash[ch] ){maxval = ch;maxcount = hash[ch];}}int n = barcodes.size();int i;vector<int> ret(n);for(i = 0; i < n && maxcount > 0; i += 2){ret[i] = maxval;maxcount --;}hash.erase(maxval);for(auto& [x, y] : hash){for(int j = 0; j < y; j++){if(i >= n)i = 1;ret[i] = x;i += 2;}}return ret;}
};

 10.重构字符串

767. 重构字符串 - 力扣(LeetCode) 

        这道题和上一道题是一模一样的的,唯一的不同就是这道题可能无解,因此我们需要判断一些maxcount 会不会大于(s.size() + 1)/2. 

class Solution {
public:string reorganizeString(string s) {int n = s.size();char maxval;int maxcount = 0;string ret = s;unordered_map<char, int> hash;for(auto ch: s){if(maxcount < ++hash[ch]){maxval = ch;maxcount = hash[ch];}}if(maxcount > (n + 1) / 2)return "";int i;for(i = 0; i < n && maxcount > 0; i += 2){ret[i] = maxval;maxcount--;}hash.erase(maxval);for(auto &[x, y] : hash){for(int j = 0; j < y; j++){if(i >= n)i = 1;ret[i] = x;i += 2;}}return ret;}
};

 

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

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

相关文章

RaabitMQ 快速入门

&#x1f389;欢迎大家观看AUGENSTERN_dc的文章(o゜▽゜)o☆✨✨ &#x1f389;感谢各位读者在百忙之中抽出时间来垂阅我的文章&#xff0c;我会尽我所能向的大家分享我的知识和经验&#x1f4d6; &#x1f389;希望我们在一篇篇的文章中能够共同进步&#xff01;&#xff01;&…

语音识别——根据声波能量、VAD 和 频谱分析实时输出文字

SenseVoiceSmall网络结构图 ASR(语音识别)是将音频信息转化为文字的技术。在实时语音识别中,一个关键问题是:如何决定将采集的音频数据输入大模型的最佳时机?固定时间间隔显然不够灵活,太短可能导致频繁调用模型,太长则会延迟文字输出。有没有更智能的方式?答案是肯定…

AI大模型如何重塑科研范式:从“假说驱动”到“数据涌现”

📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:科研进入“模型共研”时代 传统科研范式通常以“假设→实验→验证→理论”的方式推进,这一经典路径建立在人类的认知能力与逻辑推理基础上。然而,随着数据规模的爆炸式增长与知识系统的高度复杂…

使用Python写入JSON、XML和YAML数据到Excel文件

在当今数据驱动的技术生态中&#xff0c;JSON、XML和YAML作为主流结构化数据格式&#xff0c;因其层次化表达能力和跨平台兼容性&#xff0c;已成为系统间数据交换的通用载体。然而&#xff0c;当需要将这类半结构化数据转化为具备直观可视化、动态计算和协作共享特性的载体时&…

面试题:Eureka和Nocas的区别

Eureka 与 Nacos 核心区别对比 一、功能定位与核心能力 ‌维度‌‌Eureka‌‌Nacos‌‌核心功能‌专注服务注册与发现&#xff0c;无配置管理功能‌:ml-citation{ref“1,3” data“citationList”}集成服务注册、发现、配置管理、动态DNS等‌:ml-citation{ref“1,3” data“c…

2025年4月15日 百度一面 面经

目录 1. 代理相关 从静态代理到动态代理 2. cglib可以代理被final修饰的类吗,为什么 3. JVM 体系结构 4. 垃圾回收算法 5. 什么是注解 如何使用 底层原理 6. synchronized和reentrantlock 7. 讲一下你项目中 redis的分布式锁 与java自带的锁有啥区别 8. post 请求和 ge…

AI改变生活

AI改变生活 人工智能&#xff08;AI&#xff09;在我们生活中的应用越来越广泛&#xff0c;深刻地改变了我们的工作和生活方式。以下是一些AI实际应用的实例&#xff0c;以及它们如何影响我们的日常生活。 1. 智能助手 智能助手如Siri、Alexa和Google Assistant等&#xff0…

信奥赛之c++基础(取模运算与数位分离)

🎮 数字拆解大冒险——取模运算与数位分离魔法课 🍬 第一章:糖果分装术——取模运算 🍭 分糖果游戏 7颗糖每人分3颗: 每人得到:7 / 3 = 2颗剩余糖果:7 % 3 = 1颗(%就是取模符号) 就像把糖果装袋后剩下的零散糖粒!🔧 取模运算说明书 算式比喻结果10 % 310颗糖分…

揭秘大数据 | 21、软件定义计算

老夫先将这个小系列的前两篇内容链接奉上&#xff0c;方便感兴趣的朋友一气读之。 揭秘大数据 | 19、软件定义的世界-CSDN博客 揭秘大数据 | 20、软件定义数据中心-CSDN博客 今天&#xff0c;书接上文&#xff0c;开聊软件定义计算的那些事儿&#xff01; 虚拟化是软件定义…

FPGA-DDS技术的波形发生器

1.实验目的 1.1掌握直接数字频率合成&#xff08;DDS&#xff09;的基本原理及其实现方法。 1.2在DE2-115 FPGA开发板上设计一个可调频率的正弦波和方波发生器&#xff0c;频率范围10Hz~5MHz&#xff0c;最小分辨率小于1kHz。 1.3使用Quartus II进行仿真&#xff0c;并通过S…

LeetCode[541]反转字符串Ⅱ

思路&#xff1a; 题目给我们加了几个规则&#xff0c;剩余长度小于2k&#xff0c;大于等于k就反转k个&#xff0c;小于k就全部反转&#xff0c;我们按照这个逻辑来就行。 第一就是大于等于k就反转k个&#xff0c;我们for循环肯定是i2k了&#xff0c;接下来就是判断是否大于等于…

实现定长的内存池

池化技术 所谓的池化技术&#xff0c;就是程序预先向系统申请过量的资源&#xff0c;然后自己管理起来&#xff0c;以备不时之需。这个操作的价值就是&#xff0c;如果申请与释放资源的开销较大&#xff0c;提前申请资源并在使用后并不释放而是重复利用&#xff0c;能够提高程序…

路由器原理与配置技术详解

一、路由基础原理 1.1 路由器的核心功能 网络层设备&#xff1a;工作在OSI参考模型第三层&#xff0c;实现不同网络间的互联互通智能路径选择&#xff1a;基于路由表为数据包选择最优传输路径协议转换&#xff1a;处理不同网络接口间的协议差异&#xff08;如以太网与PPP&…

Leetcode 3518. Smallest Palindromic Rearrangement II

Leetcode 3518. Smallest Palindromic Rearrangement II 1. 解题思路2. 代码实现 题目链接&#xff1a;Leetcode 3518. Smallest Palindromic Rearrangement II 1. 解题思路 这一题是题目Leetcode 3517. Smallest Palindromic Rearrangement I的升级版本&#xff0c;其主要的…

大模型——Crawl4AI 中的数据提取策略

大模型——Crawl4AI 中的数据提取策略 在本章中,将详细介绍在 Crawl4AI 中可用的数据提取策略。这些策略包括: LLMExtractionStrategy:用于详细内容提取。JsonCssExtractionStrategy:使用 CSS 选择器进行结构化数据检索。CosineStrategy:基于余弦相似性进行有效的语义分段…

职坐标解码互联网行业转型发展新动能

当前&#xff0c;互联网行业正以前所未有的速度重塑全球产业格局。工信部最新数据显示&#xff0c;我国互联网企业营收连续三年保持双位数增长&#xff0c;其中百强企业在人工智能、物联网等领域的投入强度同比提升40%&#xff0c;展现出强劲的技术引领力。与此同时&#xff0c…

linux多线(进)程编程——(4)进程间的传音术(命名管道)

前言&#xff08;前情回顾&#xff09; 进程君&#xff08;父进程&#xff09;在开发出匿名管道这门传音术后&#xff0c;解决了和自己孩子&#xff08;子进程&#xff09;间的沟通问题&#xff0c;父子关系趋于融洽。和孩子沟通后&#xff0c;进程君发现&#xff0c;自己脱离…

在IDEA里面建立maven项目(便于java web使用)

具体步骤&#xff1a; 第一次有的电脑你再创建项目的时候右下角会提醒你弹窗&#xff1a;让你下载没有的东西 一定要下载&#xff01;&#xff01;可能会很慢 运行结果&#xff1a; 因为他是默认的8080端口所以在运行的时候输入的url如下图&#xff1a; 新建了一个controller代…

【13】数据结构之树结构篇章

目录标题 树Tree树的定义树的基本概念树的存储结构双亲表示法孩子表示法孩子兄弟表示法 二叉树二叉树与度不超过&#xff12;的普通树的不同之处二叉树的基本形态二叉树的分类二叉树的性质 二叉树的顺序存储二叉树的链式存储二叉树的链式存储的结点结构树的遍历先序遍历中序遍历…

雷达生命探测仪,地震救援的生命探测先锋|鼎跃安全

在地震、山体滑坡、坍塌建筑等突发灾害中&#xff0c;会严重摧毁建筑物&#xff0c;造成倒塌和人员被困&#xff1b;在瓦砾堆、混凝土板层中&#xff0c;受困人员的生命安全常常面临严峻威胁。传统救援手段通常存在响应时间长、监测精度有限等不足。 救援现场往往环境复杂&…