第八章 贪心算法 part02
文章目录
122. 买卖股票的最佳时机 II
没想到自己居然一下子就想到了,感动哭了,要是所有题目都这么简单就好了。最初我还加了个判断语句,判断下数组大小为1的情况,后来发现没必要判断,因为为1的话,根本进不去循环。只要今天的价格比昨天高,就卖出获取利润,贪心地最大化收益。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int result=0;
int gap=0;
for(int i=1;i<prices.size();i++){
gap=prices[i]-prices[i-1];
if(gap>0)
result+=gap;
}
return result;
}
};
本题解法很巧妙,大家可以先自己思考一下然后再看题解,会有惊喜!
55. 跳跃游戏
本题如果没接触过,很难想到,所以不要自己憋太久,读题思考一会儿,没思路立刻看题解。
class Solution {
public:
bool canJump(vector<int>& nums) {
int maxLength=0;
for(int i=0;i<=maxLength;i++){
maxLength=(i+nums[i]>maxLength)?i+nums[i]:maxLength;
if(maxLength>=nums.size()-1)
{
return true;
}
}
return false;
}
};
不用拘泥于每次究竟跳几步,而是看覆盖范围,覆盖范围内一定是可以跳过来的,不用管是怎么跳的。
题解链接
45. 跳跃游戏 II
本题同样不容易想出来。贪心算法有时候会感觉简单到离谱,有时候又难得不行,主要是不容易想到。
class Solution {
public:
int jump(vector<int>& nums) {
if (nums.size() == 1) return 0; // 如果只有一个元素,不需要跳跃
int step=0;
int maxLength1=0;//当前跳最远距离
int maxLength2=0;//下一跳最远距离
int i=0;
while(maxLength1<nums.size()-1)
{
step++;//每跳一次,步数加一
while(i<=maxLength1)
{
maxLength2=(maxLength2>nums[i]+i)?maxLength2:nums[i]+i;
i++;
}
maxLength1=maxLength2;
}
return step;
}
};
每次我们都尝试跳跃到当前范围内能够到达的最远位置。每次跳跃都寻找当前能跳到的范围内下一跳的最远点,保证每次跳跃尽可能最大化前进距离,从而最小化跳跃次数。maxLength1:当前这一步能跳到的最远距离。也就是我们在这次跳跃范围内可以到达的最远点。
maxLength2:下一步跳跃时能到达的最远距离。我们会遍历当前跳跃范围(即从当前位置 i 到 maxLength1 ),计算从这些位置能跳到的最远位置,并更新 maxLength2。
题解链接
1005. K 次取反后最大化的数组和
本题比较简单,估计大家不用过多思考贪心,用自己的直觉也会有思路。
这题思考还是能按照贪心的想法思考,让绝对值大的负数变为正数,当前数值达到最大。但是每次的排序好像也很耗时间
第一步:将数组按照绝对值大小从大到小排序,注意要按照绝对值的大小
第二步:从前向后遍历,遇到负数将其变为正数,同时K–
第三步:如果K还大于0,那么反复转变数值最小的元素,将K用完
第四步:求和
最重要的是绝对值,确实很巧妙,对的,绝对值。
玛德,思路清晰后,题目易如反掌,好简单。
这段代码定义了一个函数 sortByAbsoluteValue
,该函数用于将传入的整数数组 nums
按照绝对值的大小进行排序。
class Solution {
public:
void sortByAbsoluteValue(vector<int>& nums) {
// 使用自定义的比较函数,将数组按照绝对值大小排序
sort(nums.begin(), nums.end(), [](int a, int b) {
return abs(a) > abs(b);
});
}
int largestSumAfterKNegations(vector<int>& nums, int k) {
sortByAbsoluteValue(nums);//求绝对值从大到小排序
for (int i = 0; i < A.size(); i++) { // 第二步
if (A[i] < 0 && K > 0) {
A[i] *= -1;
K--;
}
}
if (K % 2 == 1) A[A.size() - 1] *= -1; // 第三步
int result = 0;
for (int a : A) result += a; // 第四步
return result;
}
};
关键点解释:
- Lambda 表达式:
[](int a, int b) { return abs(a) >abs(b); }
- 这是一个匿名函数(lambda 表达式),用于比较两个整数
a
和b
的绝对值。 abs(a)
和abs(b)
分别计算a
和b
的绝对值,return abs(a) > abs(b);
返回一个布尔值,表示a
是否应该排在b
前面。- 通过这个自定义比较函数,
std::sort
将会按照元素的绝对值进行升序排序。
- 这是一个匿名函数(lambda 表达式),用于比较两个整数
- [] 在 C++ 中,[] 是用于定义 lambda 表达式 的语法的一部分。它通常被称为 捕获列表(capture list),定义了 lambda 表达式可以访问的外部变量。
- Lambda 表达式 是 C++11 引入的一种匿名函数,主要用于定义简洁的函数对象。它的核心功能是允许在函数内部或局部位置内快速创建函数对象,尤其适合像
std::sort
等需要临时函数对象的场景。
Lambda 表达式的基本语法
Lambda 表达式的结构如下:
[capture-list](parameter-list) -> return-type {
// function body
};
[capture-list]
:捕获列表,用来指定哪些外部变量可以在 lambda 表达式中使用,以及捕获方式(按值或按引用)。(parameter-list)
:参数列表,类似普通函数的参数。-> return-type
(可选):返回类型,如果省略,编译器会自动推导。{}
:函数体,包含具体的逻辑。
Lambda 表达式的各部分详解
-
捕获列表
[capture-list]
:
捕获列表定义了 lambda 表达式可以访问哪些外部作用域中的变量,有以下几种捕获方式:- 按值捕获
[x]
:捕获变量x
的值,lambda 内部对x
的操作不会影响外部变量。 - 按引用捕获
[&x]
:捕获变量x
的引用,lambda 内部对x
的操作会直接影响外部变量。 - 捕获所有变量
[=]
:按值捕获所有外部变量。 - 捕获所有变量
[&]
:按引用捕获所有外部变量。 - 混合捕获
[&, x]
:按引用捕获所有外部变量,x
除外,x
按值捕获。
示例:
int x = 10, y = 20; auto lambda1 = [=]() { return x + y; }; // 按值捕获 x 和 y auto lambda2 = [&]() { x += y; }; // 按引用捕获 x 和 y
- 按值捕获
总结:
题解链接
一点点学起来呢!