一、贪心算法
保证每次操作都是局部最优的,从而使最后得到的结果是全局最优的。
1 分配问题
1.1 Assign Cookies(Easy) 455.分发饼干
https://leetcode-cn.com/problems/assign-cookies/
题解:
饥饿度最小的孩子最容易吃饱,所以先考虑这个孩子,把大于等于这个孩子饥饿度的、且大小最小的饼干给这个孩子。所以先对孩子和饼干按照从小到大排序然后循环筛选。
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
sort(g.begin(), g.end());
sort(s.begin(), s.end());
int child = 0, cookie = 0;
while (child < g.size() && cookie < s.size()){
if (g[child] <= s[cookie]) child++;
cookie++;
}
return child;
}
};
1.2 Candy(hard) 135.分发糖果
https://leetcode-cn.com/problems/candy/
题解:
两次遍历,先从左到右,然后从右到左,判断两边的数值是否比中间的大。
class Solution {
public:
int candy(vector<int>& ratings) {
// sort(ratings.begin(), ratings.end());
int length = ratings.size();
if (length < 2) return length;
vector<int> nums(length, 1);
for (int i = 1; i < ratings.size(); i++){
if (ratings[i] > ratings[i-1]){
nums[i] = nums[i-1] + 1;
}
}
for (int i = length - 1; i > 0; i--){
if (ratings[i-1] > ratings[i]){
nums[i-1] = max(nums[i-1], nums[i]+ 1);
}
}
return accumulate(nums.begin(), nums.end(), 0);
}
};
2 区间问题
2.1 Non-overlapping intervals(Medium) 435.无重叠区间
题解:
先按照区间的第二个元素大小排序,然后比较前一个区间的第二个元素和当前区间的第一个元素的大小。边遍历边寻找满足要求的区间。
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if (intervals.empty()) return 0;
int size = intervals.size();
// 按照每个元素的第二个元素的大小排列,因为每个元素右边的元素决定的这个区间的结束。
sort(intervals.begin(), intervals.end(), [](vector<int>a, vector<int>b){
return a[1] < b[1];
});
int res = 0, prev = intervals[0][1];
for (int i = 1; i < size; i++){
if (intervals[i][0] < prev){
res++;
} else{
prev = intervals[i][1];
}
}
return res;
}
};
3 练习
3.1 Can Place Flowers(Easy) 605.种花问题
题解:
其实就是利用贪心的思想,只有一个点的值为0才能种花,就是要判断这个为0的点左面和右边的点是否都为0,同时考虑两个特殊点,左边界和右边界,因为这两个点只有一个邻居。
class Solution {
public:
bool canPlaceFlowers(vector<int>& flowerbed, int n) {
//int temp = flowerbed
if (flowerbed.size() == 1 && flowerbed[0] == 0) return --n <= 0;
for (int i = 0; i < flowerbed.size(); i++){
if (flowerbed[i] == 0){
if (i == 0){
if (flowerbed[i+1] == 0){
flowerbed[i] = 1;
n--;
}
}else if(i == flowerbed.size() - 1){
if (flowerbed[i-1] == 0){
flowerbed[i] = 1;
n--;
}
}else{
if(flowerbed[i-1] == 0 && flowerbed[i+1] ==0){
flowerbed[i] = 1;
n--;
}
}
}
}
return n<=0;
}
};
3.2 Minimum Number of Arrows to Burst Balloons (Medium) 452.用最少数量的箭引爆气球
题解:
和435类似,先进行排序(按照每一个元素的第二个位置的值排序)然后进行循环遍历,判断当前的这个气球的最小值是不是比上一个记录下来的值(这个值用来记录箭射中的第一个气球的最大值,同时这个箭还可能射中后面的气球)大,如果大就不和他公用一个箭,就自己用一个,如果不大就和上一个气球公用一个箭。
public:
int findMinArrowShots(vector<vector<int>>& points) {
if (points.empty()) return 0;
sort(points.begin(), points.end(), [](vector<int> a, vector<int> b){
return a[1] < b[1];
});
int res = 1, prev = points[0][1];
for (int i = 1; i < points.size(); i++){
if (points[i][0] > prev){
res++;
prev = points[i][1];
}
}
return res;
}
};
3.3 Partition Labels(Medium) 763.划分字母区间
这道题思路就是参考的官方思路,首先遍历存储所有字母的最大索引值,然后建立两个指针,从前向后开始遍历,用end指针和每一个字母的最大的索引比较,让end等于每一次循环end和当前字母索引的最大值如果end和当前的循环索引相等,那么就存储为一个子序列,然后一次循环。
class Solution {
public:
vector<int> partitionLabels(string S) {
// 用哈希表的思想
int hash_map[26] = {0};
vector<int> res;
int start = 0, end = 0;
// 现存一边每个字母最后出现的索引
for (int i = 0; i < S.size(); i++){
hash_map[S[i] - 'a'] = i;
}
for (int i = 0; i < S.size(); i++){
end = max(end, hash_map[S[i] - 'a']);
if (end == i){
res.push_back(end - start + 1);
start = end + 1;
}
}
return res;
}
};
3.4 Best Time to Buy and Sell stock 2(Easy)122.买卖股票的最佳时机
遍历求和就好,每次计算出差值 当为负数就不做计算,当为正就求和,相当于求max(0, res)
class Solution {
public:
int maxProfit(vector<int>& prices) {
int res = 0;
for (int i = 1; i < prices.size(); i++){
res += max(0, prices[i] - prices[i-1]);
}
return res;
}
};
3.5 406. 根据身高重建队列(中等)
class Solution {
public:
vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
sort(people.begin(), people.end(), [](vector<int> a, vector<int> b){
if (a[0] == b[0]) return a[1] < b[1];
else return a[0] > b[0];
});
vector<vector<int>> que;
for (int i = 0; i < people.size(); i++){
int ki = people[i][1];
que.insert(que.begin() + ki, people[i]);
}
return que;
}
};
3.6 665.非递减数列(简单)
两次循环,第一次找到一个,第二次如果还有就是false,否则为true。
class Solution {
public:
bool checkPossibility(vector<int>& nums) {
if (nums.size() <= 2) return true;
for (int i = 0; i <= nums.size() - 2; i++){
if (nums[i] > nums[i+1]){
if (i == 0){
nums[i] = nums[i+1];
break;
}else if (i == nums.size() - 2){
// nums[i+1] = nums[i];
return true;
}
if (nums[i] < nums[i+2] && nums[i-1] <= nums[i]){
nums[i+1] = nums[i];
}else if (nums[i-1] <= nums[i+1] && nums[i+1] <= nums[i+2]){
nums[i] = nums[i+1];
}else return false;
break;
}
}
cout << nums.size() << endl;
for (int i = 0; i <= nums.size() - 2; i++){
// cout << nums[i] << endl;
if (nums[i] > nums[i+1]){
// cout << 1;
return false;
}
}
return true;
}
};