【贪心算法题目练习】

1. 分发饼干

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

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

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

直接上代码:

cpp 复制代码
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++;
            else
                j++;   
        }
        return ret;
    }
};

2. 最优除法

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

cpp 复制代码
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位置的最小跳跃步数

直接上代码:

cpp 复制代码
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. 跳跃游戏

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

cpp 复制代码
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,代表无论怎样,你都不可能绕环路行驶一周,否则可以。
cpp 复制代码
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。

cpp 复制代码
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;
	}
};
相关推荐
数据分析螺丝钉37 分钟前
力扣第240题“搜索二维矩阵 II”
经验分享·python·算法·leetcode·面试
no_play_no_games37 分钟前
「3.3」虫洞 Wormholes
数据结构·c++·算法·图论
￴ㅤ￴￴ㅤ9527超级帅37 分钟前
LeetCode hot100---数组及矩阵专题(C++语言)
c++·leetcode·矩阵
五味香37 分钟前
C++学习,信号处理
android·c语言·开发语言·c++·学习·算法·信号处理
PYSpring1 小时前
数据结构-LRU缓存(C语言实现)
c语言·数据结构·缓存
毕小宝1 小时前
逻辑回归(下): Sigmoid 函数的发展历史
算法·机器学习·逻辑回归
小叮当爱咖啡1 小时前
DenseNet算法:口腔癌识别
算法
希望有朝一日能如愿以偿1 小时前
算法(食物链)
算法
鱼跃鹰飞1 小时前
Leecode热题100-295.数据流中的中位数
java·服务器·开发语言·前端·算法·leetcode·面试
Mr Aokey1 小时前
双向无头非循环链表的简单实现及介绍
数据结构