一、贪心算法简介
证明贪心策略正确性的常用方法:直接证明、交换论证法、反证法、分类讨论…
二、相关编程题
2.1 柠檬水找零
题目链接
题目描述
算法原理
提示:最优解和贪心解唯一可能不同的就是20块钱的找零方法,贪心解由优先选择10+5,最优解可能是5+5+5。最优解中可能没有用到10块找零,也可能在后面找零时用到了,但都可以和5+5交换也转换成10+5。这样在不破坏最优性质的前提下就可以转化为贪心解。
编写代码
class Solution {
public:
bool lemonadeChange(vector<int>& bills) {
int f = 0, t = 0;
for(auto e : bills)
{
if(e == 5) ++f;
else if(e == 10)
{
if(f>0) ++t, --f;
else return false;
}
else
{
if(t>0 && f>0) --t, --f;
else if(f>2) f-=3;
else return false;
}
}
return true;
}
};
2.2 将数组和减半的最少操作次数
题目链接
2208. 将数组和减半的最少操作次数 - 力扣(LeetCode)
题目描述
算法原理
编写代码
class Solution {
public:
int halveArray(vector<int>& nums) {
priority_queue<double> heap;
double sum = 0;
for(auto e : nums)
{
heap.push(e);
sum+=e;
}
int cnt = 0;
double aim = sum/2;
while(sum > aim)
{
double top = heap.top()/2;
heap.pop();
sum-=top;
heap.push(top);
++cnt;
}
return cnt;
}
};
2.3 最大数
题目链接
题目描述
算法原理
编写代码
class Solution {
public:
string largestNumber(vector<int>& nums) {
vector<string> strs;
for(auto e : nums)
strs.push_back(to_string(e));
sort(strs.begin(), strs.end(), [](const string& a, const string& b)
{
return a+b > b+a;
});
string ret;
for(auto e : strs) ret += e;
if(ret[0] == '0') return "0";
return ret;
}
};
2.4 摆动序列
题目链接
题目描述
算法原理
提示:这里使用的是反证法证明的
编写代码
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
int n = nums.size();
if(n < 2) return n;
int left = 0, right = 0;
int ret = 0;
for(int i = 0; i < n-1; ++i)
{
right = nums[i+1]-nums[i];
if(right == 0) continue; //right跳过中间连续相等的区间
if(left*right <= 0) ++ret; //等于0是为了选第1个位置
left = right;
}
return ret+1; //最后1个位置是一定要选的
}
};
2.5 最长递增子序列
题目链接
题目描述
算法原理
编写代码
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> arr;
arr.push_back(nums[0]);
for(auto e : nums)
{
if(e > arr.back())
arr.push_back(e);
else
{
int left = 0, right = arr.size();
while(left < right)
{
int mid = left+(right-left)/2;
if(arr[mid] < e) left = mid+1;
else if(arr[mid] >= e) right = mid;
}
arr[left] = e;
}
}
return arr.size();
}
};
2.6 递增的三元子序列
题目链接
题目描述
算法原理
编写代码
class Solution {
public:
bool increasingTriplet(vector<int>& nums) {
int a = nums[0], b = INT_MAX;
for(int i = 1; i < nums.size(); ++i)
{
if(nums[i] > b) return true;
else if(nums[i] <= a) a = nums[i];
else b = nums[i];
}
return false;
}
};
2.7 最长连续递增序列
题目链接
题目描述
算法原理
略
编写代码
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
int ret = 0;
int i = 0, j = 1;
for(; j < nums.size(); ++j)
{
if(nums[j] <= nums[j-1])
{
ret = max(ret, j-i);
i = j;
}
}
ret = max(ret, j-i); //记得算上最后一个子数组
return ret;
}
};
2.8 买卖股票的最佳时机
题目链接
题目描述
算法原理
编写代码
class Solution {
public:
int maxProfit(vector<int>& prices) {
int ret = 0, prevmin = prices[0];
for(int i =