当前位置: 首页 > article >正文

LeetCode 贪心算法经典题目 (C++实现)

121. 买卖股票的最佳时机

题目描述

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

提示:

1 <= prices.length <= 105
0 <= prices[i] <= 104

解题思路

首先定义两个变量profit和cost,分别用来记录成本以及利润,然后遍历股票的价格,cost用来记录遍历过的最小价格,作为买入价格,profit用来记录如果当天卖出,能取得的最大利润。遍历完之后profit的最大值即为答案。

代码

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int profit = 0;
        int cost = INT_MAX;
        for (int i = 0; i < prices.size(); i++)
        {
            cost = min(cost, prices[i]);
            profit = max(profit, prices[i] - cost);
        }
        return profit;
    }
};

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

题目描述

给你一个整数数组 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。

提示:

1 <= prices.length <= 3 * 104
0 <= prices[i] <= 104

解题思路

这道题目强调的是在每一天,都可以购买或者出售股票。遍历股票的价格,如果当天比前一天贵就可以记录收益,最后记录所有正收益的总和即为答案。

代码

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

55. 跳跃游戏

题目描述

给你一个非负整数数组 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 , 所以永远不可能到达最后一个下标。

提示:

1 <= nums.length <= 104
0 <= nums[i] <= 105

解题思路

首先定义最远位置cover,然后遍历数组,如果当前位置大于能跳的最远位置,则返回false,否则更新最远位置为当前位置+当前能跳最大长度。

代码

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int cover = 0;
        for (int i = 0; i < nums.size(); i++)
        {
            if (i > cover)
            {
                return false;
            }
            cover = max(cover, i + nums[i]);
        }
        return true;
    }
};

45. 跳跃游戏 II

题目描述

给定一个长度为 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

提示:

1 <= nums.length <= 104
0 <= nums[i] <= 1000
题目保证可以到达 nums[n-1]

解题思路

首先定义当前右边界cur_right,和下一个右边界next_right。遍历数组,当前右边界不动,更新下一个右边界的最大值,当走到当前右边界的时候,更新当前右边界的值,同时跳跃次数加一,到达n-2个元素的时候返回跳跃次数。

代码

class Solution {
public:
    int jump(vector<int>& nums) {
        int ans = 0;
        int cur_right = 0;
        int next_right = 0;
        for (int i = 0; i < nums.size() - 1; i++)
        {
            next_right = max(next_right, i + nums[i]);
            if (i == cur_right)
            {
                cur_right = next_right;
                ans++;
            }
        }
        return ans;
    }
};

763. 划分字母区间

题目描述

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。例如,字符串 “ababcc” 能够被分为 [“abab”, “cc”],但类似 [“aba”, “bcc”] 或 [“ab”, “ab”, “cc”] 的划分是非法的。

注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。

返回一个表示每个字符串片段的长度的列表。

示例 1:

输入:s = “ababcbacadefegdehijhklij”
输出:[9,7,8]
解释:
划分结果为 “ababcbaca”、“defegde”、“hijhklij” 。
每个字母最多出现在一个片段中。
像 “ababcbacadefegde”, “hijhklij” 这样的划分是错误的,因为划分的片段数较少。

示例 2:

输入:s = “eccbbbbdec”
输出:[10]

提示:

1 <= s.length <= 500
s 仅由小写英文字母组成

解题思路

首先定义一个数组last用来记录每个字母出现的最后位置,然后遍历s,将具有交集的字母所在区间进行合并,取并集,记录每个区间返回最后的结果。

代码

class Solution {
public:
    vector<int> partitionLabels(string s) {
        int n = s.size();
        vector<int> last(26, 0);
        for (int i = 0; i < n; i++)
        {
            last[s[i] - 'a'] = i;
        }
        vector<int> ans;
        int start = 0, end = 0;
        for (int i = 0; i < n; i++)
        {
            end = max(end, last[s[i] - 'a']);
            if(end == i)
            {
                ans.push_back(end - start + 1);
                start = i + 1;
            }
        }
        return ans;
    }
};

455. 分发饼干

题目描述

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

对每个孩子 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。

提示:

1 <= g.length <= 3 * 104
0 <= s.length <= 3 * 104
1 <= g[i], s[j] <= 231 - 1

解题思路

首先将s和g排序,然后遍历饼干大小数组s,如果当前饼干大小满足当前孩子的胃口,ans加一,否则继续循环。

代码

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(s.begin(), s.end());
        sort(g.begin(), g.end());
        int ans = 0;
        for (int i = 0; i < s.size(); i++)
        {
            if (ans < g.size() && s[i] >= g[ans])
            {
                ans++;
            }
        }
        return ans;
    }
};

135. 分发糖果

题目描述

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。

你需要按照以下要求,给这些孩子分发糖果:

每个孩子至少分配到 1 个糖果。
相邻两个孩子评分更高的孩子会获得更多的糖果。
请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。

示例 1:

输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。

示例 2:

输入:ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。
第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。

提示:

n == ratings.length
1 <= n <= 2 * 104
0 <= ratings[i] <= 2 * 104

解题思路

定义数组left和right,从左边第1个开始遍历,如果当前孩子的评分大于前一个则left[i]加一。再从倒数第二个开始遍历,如果当前孩子的评分大于后一个则right[i]加一,最后遍历一遍每个孩子的评分,取每个孩子的left和right数组值大的那个相加。

代码

class Solution {
public:
    int candy(vector<int>& ratings) {
        int ans = 0;
        int n = ratings.size();
        vector<int> left(n, 1);
        vector<int> right(n, 1);
        for (int i = 1; i < n; i++)
        {
            if (ratings[i] > ratings[i - 1])
            {
                left[i] = left[i - 1] + 1;
            }
        }
        for (int i = n - 2; i >= 0; i--)
        {
            if (ratings[i] > ratings[i + 1])
            {
                right[i] = right[i + 1] + 1;
            }
        }
        for (int i = 0; i < n; i++)
        {
            ans += max(left[i], right[i]);
        }
        return ans;
    }
};

435. 无重叠区间

题目描述

给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。

注意 只在一点上接触的区间是 不重叠的。例如 [1, 2] 和 [2, 3] 是不重叠的。

示例 1:

输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
解释: 移除 [1,3] 后,剩下的区间没有重叠。

示例 2:

输入: intervals = [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。

示例 3:

输入: intervals = [ [1,2], [2,3] ]
输出: 0
解释: 你不需要移除任何区间,因为它们已经是无重叠的了。

提示:

1 <= intervals.length <= 105
intervals[i].length == 2
-5 * 104 <= starti < endi <= 5 * 104

解题思路

首先按照右端点大小将区间从小到大排序。定义end为第一个区间的右端点,从第一个区间开始遍历,如果当前区间的左端点大于等于end则无重复区间数量加一,更新end为当前区间右端点,最后移除区间的数量为n-无重复区间数量。

代码

class Solution {
public:
    static bool cmp(vector<int>& a, vector<int>& b)
    {
        return a[1] < b[1];
    }
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        int n = intervals.size();
        int ans = 1;
        sort(intervals.begin(), intervals.end(), cmp);
        int end = intervals[0][1];
        for (int i = 1; i < n; i++)
        {
            if (end <= intervals[i][0])
            {
                end = intervals[i][1];
                ans++;
            }
        }
        return n - ans;
    }
};

605. 种花问题

题目描述

假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。

给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false 。

示例 1:

输入:flowerbed = [1,0,0,0,1], n = 1
输出:true

示例 2:

输入:flowerbed = [1,0,0,0,1], n = 2
输出:false

提示:

1 <= flowerbed.length <= 2 * 104
flowerbed[i] 为 0 或 1
flowerbed 中不存在相邻的两朵花
0 <= n <= flowerbed.length

解题思路

首先将flowerbed前后各插入一个0,然后从第一个位置还是遍历,如果前中后位置都为0则当前位置能种花,n–,最后如果n的数量小于等于0则视为能种下n朵花

代码

class Solution {
public:
    bool canPlaceFlowers(vector<int>& flowerbed, int n) {
        flowerbed.insert(flowerbed.begin(), 0);
        flowerbed.push_back(0);
        for (int i = 1; i < flowerbed.size() - 1; i++)
        {
            if (flowerbed[i - 1] == 0 && flowerbed[i] == 0 && flowerbed[i + 1] == 0)
            {
                flowerbed[i] = 1;
                n--;
            }
        }
        return n <= 0;
    }
};

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

题目描述

有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] = [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。

一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。

给你一个数组 points ,返回引爆所有气球所必须射出的 最小 弓箭数 。

示例 1:

输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:气球可以用2支箭来爆破:
-在x = 6处射出箭,击破气球[2,8]和[1,6]。
-在x = 11处发射箭,击破气球[10,16]和[7,12]。

示例 2:

输入:points = [[1,2],[3,4],[5,6],[7,8]]
输出:4
解释:每个气球需要射出一支箭,总共需要4支箭。

示例 3:

输入:points = [[1,2],[2,3],[3,4],[4,5]]
输出:2
解释:气球可以用2支箭来爆破:

  • 在x = 2处发射箭,击破气球[1,2]和[2,3]。
  • 在x = 4处射出箭,击破气球[3,4]和[4,5]。

提示:

1 <= points.length <= 105
points[i].length == 2
-231 <= xstart < xend <= 231 - 1

解题思路

首先按照右端点大小将区间从小到大排序。定义pos为第一个区间的右端点,从第一个区间开始遍历,如果当前区间的左端点大于pos则需要加一只箭,pos更新为当前区间右端点

代码

class Solution {
public:
    static bool cmp(vector<int>& a, vector<int>& b)
    {
        return a[1] < b[1];
    }
    int findMinArrowShots(vector<vector<int>>& points) {
        if (points.empty())
        {
            return 0;
        }
        sort(points.begin(), points.end(), cmp);
        int ans = 1;
        int pos = points[0][1];
        for (int i = 1; i < points.size(); i++)
        {
            if (points[i][0] > pos)
            {
                pos = points[i][1];
                ans++;
            }
        }
        return ans;
        
    }
};

376. 摆动序列

题目描述

如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。

例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。

相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。

示例 1:

输入:nums = [1,7,4,9,2,5]
输出:6
解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3) 。

示例 2:

输入:nums = [1,17,5,10,13,15,10,5,16,8]
输出:7
解释:这个序列包含几个长度为 7 摆动序列。
其中一个是 [1, 17, 10, 13, 10, 16, 8] ,各元素之间的差值为 (16, -7, 3, -3, 6, -8) 。

示例 3:

输入:nums = [1,2,3,4,5,6,7,8,9]
输出:2

提示:

1 <= nums.length <= 1000
0 <= nums[i] <= 1000

解题思路

首先定义curdiff和prediff用来记录当前差异和前一个差异,遍历数组,curdiff等于后项减当前项,如果prediff和curdiff符号不同则长度加一,prediff更新为curdiff。

代码

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

    }
};

53. 最大子数组和

题目描述

给你一个整数数组 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

提示:

1 <= nums.length <= 105
-104 <= nums[i] <= 104

解题思路

定义两个变量result和count,遍历数组,count不断加当前数组中的值,如果count小于0的话将当前位置元素跳过,count置为0,否则更新result值。

代码

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int result = INT32_MIN;
        int count = 0;
        for(int i = 0;i<nums.size();i++)
        {
            count += nums[i];
            if(count>result)
            {
                result = count;
            }
            if(count<=0) count = 0;

        }
        return result;

    }
};

http://www.kler.cn/a/561197.html

相关文章:

  • 网络空间安全(2)应用程序安全
  • 机器人“战场”:创新、落地与未来
  • PyCharm Professional 2025 安装配置全流程指南(Windows平台)
  • Vue使用Three.js加载glb (gltf) 文件模型及实现简单的选中高亮、测距、测面积
  • 使用Kafka进行实时数据流处理的场景
  • Sky Hackathon 清水湾的水 AI美食助手
  • 数据结构:Map set - 习题(三)
  • 智能物联赋能城市照明升级——塔能科技的创新实践与城市转型
  • Reactor和Paroactor模型
  • [特殊字符]清华大学:DeepSeek从入门到精通.pdf(清华领航,驾驭DeepSeek,开启AI新境界)
  • 【Python爬虫(69)】解锁游戏数据宝藏:Python爬虫实战攻略
  • 基于TensorFlow.js与Web Worker的智能证件照生成方案
  • 阿里云 ACS:高效、弹性、低成本的容器计算解决方案
  • docker 中安装postgres
  • 基于YOLO11深度学习的半导体芯片缺陷检测系统【python源码+Pyqt5界面+数据集+训练代码】
  • 加油小程序实战教程01需求分析
  • Minio分布式多节点多驱动器集群部署
  • [AI]从零开始的树莓派运行DeepSeek模型教程
  • MySQL数据库的基本命令
  • Linux系统:服务器常见服务默认IP端口合集