此系列分三章来记录leetcode的有关贪心算法题解,题目我都会给出具体实现代码,如果看不懂的可以后台私信我。
本章目录
- 1.柠檬水找零
- 2.将数组和减半的最少操作次数
- 3.最大数
- 4.摆动序列
- 5.最长递增子序列
- 6.递增的三元子序列
- 7.最长连续递增序列
- 8.买卖股票的最佳时机
- 9.买卖股票的最佳时机II
- 10.K次取反后最大化的数组和
- 11.按身高排序
- 12.优势洗牌
1.柠檬水找零
cpp
class Solution {
public:
bool lemonadeChange(vector<int>& bills) {
int five = 0,ten = 0;
for(auto x:bills)
{
if(x==5) five++;
else if(x==10)
{
if(five == 0) return false;
five--;ten++;
}
else
{
if(ten&&five) //贪心
{
ten--;five--;
}
else if(five>=3)
{
five -= 3;
}
else return false;
}
}
return true;
}
};
2.将数组和减半的最少操作次数
cpp
class Solution {
public:
int halveArray(vector<int>& nums) {
//贪心+大根堆
priority_queue<double> heap;
double sum = 0.0;
for(auto x:nums)
{
sum += x;
heap.push(x);
}
sum /= 2.0;
int count =0;
while(sum>0)
{
auto t = heap.top()/2.0;
heap.pop();
sum -= t;
count++;
heap.push(t);
}
return count;
}
};
3.最大数
cpp
class Solution {
public:
string largestNumber(vector<int>& nums) {
//优化:将整型都转成字符串,通过比较字符串的字典序来比大小
vector<string> strs;
for(auto x:nums) strs.push_back(to_string(x));
sort(strs.begin(),strs.end(),[&](const string& s1,const string& s2)
{
return s1+s2>s2+s1;
});
string ret;
for(auto& s: strs) ret+=s;
//处理前导零
if(ret[0]=='0') return "0";
return ret;
}
};
4.摆动序列
cpp
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
//贪心:找极值点,建议大家将nums画成折线图进行观察
int n = nums.size();
if(n<2) return n;
int ret =0,left = 0;
for(int i=0;i<n-1;i++)
{
int right = nums[i+1]-nums[i];
if(right == 0) continue;
if(left*right<=0) ret++; //两边异号
left = right;
}
return ret+1;//最后一个点必要
}
};
5.最长递增子序列
cpp
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
//自己设计一个数组,此数组的每个元素表示存储长度为x的子序列的最后一个元素的最小值
int n = nums.size();
vector<int> ret;
ret.push_back(nums[0]);
for(int i=1;i<n;i++)
{
if(nums[i]>ret.back())
{
ret.push_back(nums[i]);
}
else
{
int left = 0,right = ret.size()-1;
while(left<right)
{
int mid = (left+right)>>1;
if(ret[mid]<nums[i]) left = mid+1;
else right = mid;
}
ret[left] = nums[i];
}
}
return ret.size();
}
};
6.递增的三元子序列
cpp
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;
if(nums[i]>a) b = nums[i];
else a = nums[i];
}
return false;
}
};
7.最长连续递增序列
cpp
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
//贪心+双指针
int ret = 0,n = nums.size();
for(int i=0;i<n;)
{
int j = i+1;
while(j<n&& nums[j]>nums[j-1]) j++;
ret = max(ret,j-i);
i = j;//直接在循环中更新下一个起点的位置,体现了贪心
}
return ret;
}
};
8.买卖股票的最佳时机
cpp
class Solution {
public:
int maxProfit(vector<int>& prices) {
int ret = 0,minElem = INT_MAX;
int n = prices.size();
for(int i=0;i<n;i++)
{
ret = max(ret,prices[i]-minElem);//先更新结果
minElem = min(minElem,prices[i]);//再更新最小值
}
return ret;
}
};
9.买卖股票的最佳时机II
cpp
class Solution {
public:
int maxProfit(vector<int>& prices) {
//法一:双指针
int ret = 0,n = prices.size();
for(int i=0;i<n;i++)
{
int j = i;
while(j+1<n && prices[j+1]>prices[j]) j++;
ret += prices[j]-prices[i];
i = j;
}
return ret;
}
};
class Solution {
public:
int maxProfit(vector<int>& prices) {
//法二:一天一天进行计算
int ret = 0,n = prices.size();
for(int i=1;i<n;i++)
{
if(prices[i]-prices[i-1]>0) ret += (prices[i]-prices[i-1]);
}
return ret;
}
};
10.K次取反后最大化的数组和
cpp
class Solution {
public:
int largestSumAfterKNegations(vector<int>& nums, int k) {
int m = 0,minElem = INT_MAX,n = nums.size();
for(auto x:nums)
{
if(x<0) m++;
minElem = min(minElem,abs(x));
}
int ret = 0;
if(m>k)
{
sort(nums.begin(),nums.end());
for(int i=0;i<k;i++)
{
ret += -nums[i];
}
for(int i=k;i<n;i++)
{
ret += nums[i];
}
}
else
{
for(auto x:nums)
{
ret += abs(x);
}
if((k-m)%2!=0)
{
ret -= minElem*2;
}
}
return ret;
}
};
11.按身高排序
cpp
class Solution {
public:
vector<string> sortPeople(vector<string>& names, vector<int>& heights) {
//1.创建一个下标数组
int n = names.size();
vector<int> index(n);
for(int i=0;i<n;i++) index[i] = i;
//2.对下标数组进行排序
sort(index.begin(),index.end(),[&](int i,int j)
{
return heights[i]>heights[j];
});
//3.输出结果
vector<string> ret;
for(auto x:index)
{
ret.push_back(names[x]);
}
return ret;
}
};
12.优势洗牌
cpp
class Solution {
public:
vector<int> advantageCount(vector<int>& nums1, vector<int>& nums2) {
//此题可以学习对应的策略,积累经验
int n = nums1.size();
//1.排序
sort(nums1.begin(),nums1.end());
vector<int> index2(n);
for(int i=0;i<n;i++) index2[i] = i;
sort(index2.begin(),index2.end(),[&](int i,int j)
{
return nums2[i]<nums2[j];
});
//2.田忌赛马
int left = 0,right = n-1;
vector<int> ret(n);
for(int i=0;i<n;i++)
{
if(nums1[i]>nums2[index2[left]]) ret[index2[left++]] = nums1[i];
else ret[index2[right--]] = nums1[i];
}
return ret;
}
};