贪心算法 (greedy algorithm
), 是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是最好或最优的算法。
简单点说就是 保证每次操作都是局部最优的,从而使最后得到的结果是全局最优的。
做题是测试是否掌握的最好方式
455.分发饼干
贪心策略:给剩余孩子里最小饥饿度的孩子分配最小的能饱腹的饼干。
int findContentChildren(vector<int>& children, vector<int>& cookies) {
sort(children.begin(), children.end());
sort(cookies.begin(), cookies.end());
int child = 0, cookie = 0;
while (child < children.size() && cookie < cookies.size()) {
if (children[child] <= cookies[cookie]) ++child;
++cookie;
}
return child;
}
135.分发糖果
贪心策略:至少每人一个,一次循环仅考虑一侧大小关系
- 先从左往右遍历一遍,如果右边孩子的评分比左边的高,则右边孩子的糖果数更新为左边孩子的 糖果数加 1;
- 再从右往左遍历一遍,如果左边孩子的评分比右边的高,且左边孩子当前的糖果数不大于右边孩子的糖果数,则左边孩子的糖果数更新为右边孩子的糖果数加 1
int candy(vector<int>& ratings) {
int size = ratings.size();
if (size < 2) return size;
vector<int> num(size, 1);
for (int i = 1; i < size; ++i) {
if (ratings[i] > ratings[i-1])
num[i] = num[i-1] + 1;
}
for (int i = size - 1; i > 0; --i) {
if (ratings[i] < ratings[i-1])
num[i-1] = max(num[i-1], num[i] + 1);
}
return accumulate(num.begin(), num.end(), 0);
}
435.无重叠区间
贪心策略:优先保留结尾小且不相交的区间。
先把区间按照结尾的大小进行增序排序,每次选择结尾最小且和前一个选择的区间不重叠的区间。
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if (intervals.empty()) {
return 0;
}
int n = intervals.size();
sort(intervals.begin(), intervals.end(), [](vector<int> a, vector<int> b) {
return a[1] < b[1];
});
int total = 0, prev = intervals[0][1];
for (int i = 1; i < n; ++i) {
if (intervals[i][0] < prev) {
++total;
} else {
prev = intervals[i][1];
}
}
return total;
}
605.种花问题
贪心策略:在不打破种植规则的情况下种入尽可能多的花,然后判断可以种入的花的最多数量是否大于或等于 n。
bool canPlaceFlowers(vector<int>& flowerbed, int n) {
int length = flowerbed.size();
int count = 0;
for (int i=0;i<length;i++) {
if (flowerbed[i] == 0
&& (i == length - 1 || flowerbed[i + 1] == 0)
&& (i == 0 || flowerbed[i - 1] == 0)) {
flowerbed[i] = 1;
count++;
}
}
return count >= n;
}
452.用最少数量的箭引爆气球
贪心策略:最优保证所有气球中右边界位置最靠左的那一个被引爆
int findMinArrowShots(vector<vector<int>>& points) {
if (points.empty()) {
return 0;
}
sort(points.begin(), points.end(), [](const vector<int>& u, const vector<int>& v) {
return u[1] < v[1];
});
int pos = points[0][1];
int ans = 1;
for (const vector<int>& balloon: points) {
if (balloon[0] > pos) {
pos = balloon[1];
++ans;
}
}
return ans;
}
763.划分字母区间
贪心策略:在得到每个字母最后一次出现的下标位置之后,可以使用贪心的方法将字符串划分为尽可能多的片段
vector<int> partitionLabels(string s) {
int last[26];
int length = s.size();
for (int i = 0; i < length; i++) {
last[s[i] - 'a'] = i;
}
vector<int> partition;
int start = 0, end = 0;
for (int i = 0; i < length; i++) {
end = max(end, last[s[i] - 'a']);
if (i == end) {
partition.push_back(end - start + 1);
start = end + 1;
}
}
return partition;
}
122.买卖股票的最佳时间 II
贪心策略:只要今天比昨天的价格高,就卖,计算利润
int maxProfit(vector<int>& prices) {
int len = prices.size();
if (len < 2) {
return 0;
}
int res = 0;
for (int i = 1; i < len; i++) {
int diff = prices[i] - prices[i - 1];
if (diff > 0) {
res += diff;
}
}
return res;
}
406.根据身高重建队列
贪心策略:身高从高到底排序,在配合身高大于等于人身高的个数插入到合适的位置
vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
sort(people.begin(), people.end(), [](const vector<int>& u, const vector<int>& v) {
return u[0] > v[0] || (u[0] == v[0] && u[1] < v[1]);
});
vector<vector<int>> ans;
for (const vector<int>& person: people) {
ans.insert(ans.begin() + person[1], person);
}
return ans;
}
665.非递减数列
贪心策略:在改变前后值大小的时候让数组 仍然维持非递减数列
简单点说,当 nums[i] > nums[i + 1]
,要么
nums[i] = nums[i + 1]
前面的元素变小nums[i + 1] = nums[i]
后面的元素变大
bool checkPossibility(vector<int> &nums) {
int n = nums.size();
for (int i = 0; i < n - 1; ++i) {
int x = nums[i], y = nums[i + 1];
if (x > y) {
// 尝试前面元素变小
nums[i] = y;
// 通过排序判断是否是递增
if (is_sorted(nums.begin(), nums.end())) {
return true;
}
// 如果前面元素变小不行,尝试换成后面元素变大
nums[i] = x;
nums[i + 1] = x;
return is_sorted(nums.begin(), nums.end());
}
}
return true;
}