LeetCode|贪心算法| 455. 分发饼干 、53. 最大子数组和 、122. 买卖股票的最佳时机 II 、55. 跳跃游戏、45. 跳跃游戏 II

目录

一、455. 分发饼干

1.题目描述

2.解题思路

3.代码实现

二、53. 最大子数组和

1.题目描述

2.解题思路

3.代码实现

三、122. 买卖股票的最佳时机 II

1.题目描述

2.解题思路

3.代码实现

四、55. 跳跃游戏

1.题目描述

2.解题思路

3.代码实现

五、45. 跳跃游戏 II

1.题目描述

2.解题思路

3.代码实现


 

一、455. 分发饼干

1.题目描述

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

 

示例 1:

输入: g = [1,2,3], s = [1,1]
输出: 1
解释: 
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。

示例 2:

输入: g = [1,2], s = [1,2,3]
输出: 2
解释: 
你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出2.

2.解题思路

        局部最优:让最大的饼干去喂胃口最大的小孩。

  • 先对两个数组排序,result记录喂了几个小孩
  • for循环  i  遍历胃口(从后往前--也就是从胃口最大的开始遍历),index指向目前最大的饼干
  • 如果index指向的饼干 符合  i  所指向的胃口,就result++,并且index--。

3.代码实现

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(),g.end());
        sort(s.begin(),s.end());
        //局部最优:用大饼干喂胃口最大的人
        int result = 0;//记录满足了多少个小孩
        int index = s.size() - 1;//表示目前最大饼干的下标
        for(int i = g.size() - 1;i >= 0;i--){
            if(index >= 0 && s[index] >= g[i]){
                result++;
                index--;
            }
        }
        return result;
    }
};

二、53. 最大子数组和

1.题目描述

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

2.解题思路

本题关键:如果连续子数组的和sum  < 0 了,如果再往后面加,不如不加,直接sum清零重新计算。

  • 例如:2,-3,4,3
  • 计算到前两个元素的连续和:2 - 3 = -1;
  • 连续和sum 成了负数。此时直接将sum = 0;然后从4开始计算(因为4 肯定比 4 - 1大)

3.代码实现

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int sum = 0;//记录最大和
        int result = INT_MIN;//记录结果
        for(int i = 0;i < nums.size();i++){
            //如果连续和sum变成负数,就不要再带他了,直接保存结果,然后sum等于 0 
            sum += nums[i];
            if(sum > result){
                result = sum;
            }
            if(sum <= 0){
                sum = 0;
            }
        }
        return result;
    }
};

三、122. 买卖股票的最佳时机 II

1.题目描述

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。

示例 1:

输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
     随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
     总利润为 4 + 3 = 7 。

示例 2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
     总利润为 4 。

示例 3:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。

2.解题思路

关键点:对于prices = [1,2,3,4,5]这个条件,假设 每次都是,当天买入,第二天就卖出,那么这个条件下的利润和为:( price[4] - price[3] ) + ( price[3] - price[2] ) + ( price[2] - price[1] ) + ( price[1] - price[0] ) 。当然每天的利润,可能是正,可能是负,我们只需要将 利润是正数的收集起来(局部最优),就可以达到利润最大化(全局最优)。

3.代码实现

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int result = 0;
        for(int i =1 ;i < prices.size();i++){
            if(prices[i] - prices[i - 1] > 0){
                result += prices[i] - prices[i - 1];
            }
        }
        return result;
    }
};

四、55. 跳跃游戏

1.题目描述

给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。

示例 1:

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

示例 2:

输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。

2.解题思路

  • 如果当前元素是2,不用纠结跳一步、还是跳两步,只需要判断我们跳跃的覆盖范围包含了数组末尾元素每,如果包含了,就return true
  • 注意这里for循环中,i的取值范围,i只能去能覆盖的范围的地方
  • 局部最优:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点

3.代码实现

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int cover = 0;//覆盖范围
        for(int i = 0;i <= cover;i++){
            cover = (cover,i + nums[i]);
            if(cover >= nums.size() - 1)//覆盖范围包含了数组末尾元素,说明可以调到那个地方
                return true;
        }
        return false;
    }
};

五、45. 跳跃游戏 II

1.题目描述

给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]

每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:

  • 0 <= j <= nums[i] 
  • i + j < n

返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]

示例 1:

输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
     从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。

示例 2:

输入: nums = [2,3,0,1,4]
输出: 2

2.解题思路

见代码注释。

3.代码实现

class Solution {
public:
    int jump(vector<int>& nums) {
        if(nums.size() == 1)    return 0;
        int cur = 0;//记录当前最大覆盖范围的下标
        int next = 0;//记录下一步最大覆盖范围的下标
        int result = 0;//记录走的步数
        for(int i = 0;i < nums.size();i++){
            next = max(next,nums[i] + i);
            if(i == cur){//已经走到了目前最大的覆盖范围
                result++;
                cur = next;//更新最大范围
            }
            //如果最大范围包括了末尾元素,说明可以走到
            if(cur >= nums.size() - 1)   break;
        }
        return result;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值