当前位置: 首页> 科技> 名企 > 【贪心算法题目练习】

【贪心算法题目练习】

时间:2025/7/19 16:11:45来源:https://blog.csdn.net/qq_64446981/article/details/139322596 浏览次数:2次

1. 分发饼干

这道题目和我们之前讲到的田忌赛马的问题很相似,只不过这这里不需要劣等马去抵消掉优等马,直接上贪心策略:

先将两个数组排序。针对胃口较小的孩子,从小到大挑选饼干:

  • i. 如果当前饼干能满足,直接喂(最小的饼干都能满足,不要浪费大饼干) ;
  • ii. 如果当前饼干不能满足,放弃这个饼干,去检测下一个饼干(这个饼干连最小胃口的孩子都无法满足,更别提那些胃口大的孩子了)。

直接上代码:

class Solution {
public:int findContentChildren(vector<int>& g, vector<int>& s) {// 排序sort(g.begin(), g.end());sort(s.begin(), s.end());int i = 0;int j = 0;int ret = 0;while(j < s.size() && i < g.size()){if(s[j] >= g[i])ret++,j++,i++;elsej++;   }return ret;}
};

2. 最优除法

我们可以看到这个题目的要求,它要求表达式的结果最大,那么在除数中我们可以尽量让分子大一点,让分母小一点即可,这就是我们的贪心策略:在最终的结果中,前两个数的位置是无法改变的,前两个数必定一个在分子,一个在分母,题目中说明每⼀个数的都是大于等于 2 的,所以此时可以用我们的贪心策略,为了让结果更大,我们应该尽可能的把剩下的数全都放在 「分子」上,直接上代码:

class Solution {
public:string optimalDivision(vector<int>& nums) {int n = nums.size();// 先处理两个边界情况if(n == 1) return to_string(nums[0]);if(n == 2) return to_string(nums[0]) + "/" + to_string(nums[1]);string ret = to_string(nums[0]) + "/(" + to_string(nums[1]);for(int i = 2; i < n; i++){ret += "/" + to_string(nums[i]);}ret += ")";return ret;}
};

3. 跳跃游戏Ⅱ

动态规划解法:

  • a.状态表示:dp[i] 表示从0位置开始,到达i位置时候的最小跳跃次数
  • b.状态转移方程:对于dp[i],我们遍历0~i-1区间(用指针j表示),只要能够从j位置跳到i位置(nums[j]+j>=i) ,我们就用 dp[j]+ 1更新dp[i]里面的值,找到所有情况下的最小值即可。

类似层序遍历的过程:

  • 用类似层序遍历的过程,将第i次跳跃的「起始位置」和「结束位置」找出来,用这次跳跃的情况,更新出下一次跳跃的「起始位置」和「终止位置」这样「循环往复」,就能更新出到达n一1位置的最小跳跃步数

直接上代码:

class Solution {
public:int jump(vector<int>& nums) {int left = 0;int right = 0;int ret = 0;int maxpos = 0;while(true){// 判断是否已经跳到最后一个位置if(nums.size() - 1 <= maxpos)return ret;// 遍历当层节点的最大步数for(int i = left; i <= right; i++){maxpos = max(maxpos, nums[i] + i);}// 更新下一层的区间left = right + 1;right = maxpos;ret++;}}
};

4. 跳跃游戏

这个题目和上面的题目思路基本上差不多,但是上一个题目的明显说了一定会到达最后一个下标位置,而我们这道题目是判断能否到达最后一个下标位置,基于上一个题目我们仅需修改⼀下返回值即可,直接上代码啦!!!

class Solution {
public:bool canJump(vector<int>& nums) {int left = 0;int right = 0;int maxpos = 0;int n = nums.size();while(left <= right)// 以防跳不到 n - 1 的位置{// 判断是否已经能跳到最后⼀个位置if(maxpos >= n - 1)return true; for(int i = left; i <= right; i++){maxpos = max(maxpos, nums[i] + i);}left = right + 1;right = maxpos;}return false;}
};

5. 加油站

暴力解法:

  • a. 依次枚举所有的起点;
  • b. 从起点开始,模拟⼀遍加油的流程
  • c. 如果油的剩余量小于0,代表无论怎样,你都不可能绕环路行驶一周,否则可以。
class Solution
{
public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost){int n = gas.size();for (int i = 0; i < n; i++) // 依次枚举所有的起点{int rest = 0; // 标记⼀下净收益for (int step = 0; step < n; step++) // 枚举向后⾛的步数{int index = (i + step) % n; // 求出⾛step步之后的下标rest = rest + gas[index] - cost[index];if (rest < 0) break;}if (rest >= 0) return i;}return -1;}
};

但是此时会超出时间限制,复杂度太高,我们可以优化一下哈,我们发现,当从 i 位置出发,走了 step 步之后,如果失败了。那么 [i, i + step] 这个区间内任意⼀个位置作为起点,都不可能环绕⼀圈。

因此我们枚举的下⼀个起点,应该是 i + step + 1。

class Solution
{
public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost){int n = gas.size();for (int i = 0; i < n; i++) // 依次枚举所有的起点{int rest = 0; // 标记⼀下净收益int step = 0;for (; step < n; step++) // 枚举向后⾛的步数{int index = (i + step) % n; // 求出⾛step步之后的下标rest = rest + gas[index] - cost[index];if (rest < 0) break;}if (rest >= 0) return i;i = i + step; // 优化}return -1;}
};
关键字:【贪心算法题目练习】

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: