一个本硕双非的小菜鸡,备战24年秋招,计划刷完卡子哥的刷题计划,加油!
推荐一手卡子哥的刷题网站,感谢卡子哥。代码随想录
贪心:通过局部最优,推出整体最优。
860. 柠檬水找零
Note:这真的是贪心嘛?
class Solution {
public:
bool lemonadeChange(vector<int>& bills) {
int fiveSize = 0, tenSize = 0, twentySize = 0;
for (auto bill : bills) {
if (bill == 5)
fiveSize++;
else if (bill == 10) {
if (fiveSize < 0)
return false;
else {
tenSize++;
fiveSize--;
}
}
else {
if (tenSize > 0 && fiveSize > 0) {
tenSize--;
fiveSize--;
twentySize++;
} else if (fiveSize >= 3) {
fiveSize -= 3;
twentySize++;
} else return false;
}
}
return true;
}
};
406. 根据身高重建队列
Note:按照身高排序之后,再按身高高的people的k来插入
class Solution {
public:
static bool cmp(const vector<int>& a, const vector<int>& b) {
if (a[0] == b[0])
return a[1] < b[1];
return a[0] > b[0];
}
vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
sort(people.begin(), people.end(), cmp);
vector<vector<int>> que;
for (int i = 0; i < people.size(); i++) {
int position = people[i][1];
que.insert(que.begin() + position, people[i]);
}
return que;
}
};
452. 用最少数量的箭引爆气球
Note:思路很好想,排序+找最小重复区间
class Solution {
private:
static bool cmp(vector<int>& a, vector<int>& b) {
return a[0] < b[0];
}
public:
int findMinArrowShots(vector<vector<int>>& points) {
if (points.size() == 0) return 0;
sort(points.begin(), points.end(), cmp);
int res = 1;
for (int i = 1; i < points.size(); i++) {
if (points[i - 1][1] < points[i][0])
res++;
else
points[i][1] = min(points[i - 1][1], points[i][1]);
}
return res;
}
};
435. 无重叠区间
Note:左右均可,但是右排序明显比左排序简单,因为核心还是考虑的是右区间的范围。
按区间右边界排序写法
class Solution {
private:
static bool cmp(const vector<int>& a, const vector<int>& b) {
return a[1] < b[1];
}
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if (intervals.size() == 0) return 0;
sort(intervals.begin(), intervals.end(), cmp);
int res = 1;
int end = intervals[0][1];
for (int i = 1; i < intervals.size(); i++) {
if (end <= intervals[i][0]) {
end = intervals[i][1];
res++;
}
}
return intervals.size() - res;
}
};
按区间左边界排序写法
class Solution {
private:
static bool cmp(const vector<int>& a, const vector<int>& b) {
return a[0] < b[0];
}
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if (intervals.size() == 0) return 0;
sort(intervals.begin(), intervals.end(), cmp);
int res = 0;
int end = intervals[0][1];
for (int i = 1; i < intervals.size(); i++) {
if (end > intervals[i][0]) {
end = min(end, intervals[i][1]);
res++;
} else
end = max(end, intervals[i][1]);
}
return res;
}
};
763. 划分字母区间
Note:这真的是贪心嘛?
class Solution {
public:
vector<int> partitionLabels(string s) {
int hash[27] = {0};
for (int i = 0; i < s.size(); i++) {
hash[s[i] - 'a'] = i;
}
vector<int> res;
int left = 0;
int right = 0;
for (int i = 0; i < s.size(); i++) {
right = max(right, hash[s[i] - 'a']);
if (i == right) {
res.push_back(right - left + 1);
left = i + 1;
}
}
return res;
}
};
56. 合并区间
Note:排序+判断重复+合并区间
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> result;
if (intervals.size() == 0) return result;
sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b){return a[0] < b[0];});
result.push_back(intervals[0]);
for (int i = 1; i < intervals.size(); i++) {
if (result.back()[1] >= intervals[i][0]) {
result.back()[1] = max(result.back()[1], intervals[i][1]);
} else {
result.push_back(intervals[i]);
}
}
return result;
}
};
738. 单调递增的数字
Note:从后往前遍历,前一个小于后一个-1,并记录换9
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string strNum = to_string(n);
int flag = strNum.size();
for (int i = strNum.size() - 1; i > 0; i--) {
if (strNum[i - 1] > strNum[i]) {
flag = i;
strNum[i - 1]--;
}
}
for (int i = flag; i < strNum.size(); i++)
strNum[i] = '9';
return stoi(strNum);
}
};
968. 监控二叉树
Note:分好情况讨论,理清思路
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
int result;
int traversal(TreeNode* cur) {
//无覆盖0,有摄像头1,有覆盖2
//空节点认为是有覆盖
if (cur == NULL) return 2;
int left = traversal(cur->left);
int right = traversal(cur->right);
//情况1(返回0):左右节点均有覆盖
if (left == 2 && right == 2) return 0;
//情况2(返回1):左右节点至少有一个为无覆盖
if (left == 0 || right == 0) {
result++;
return 1;
}
//情况3(返回2):左右节点至少有一个有摄像头
if (left == 1 || right == 1) return 2;
return -1;
}
public:
int minCameraCover(TreeNode* root) {
result = 0;
//情况4:根节点无覆盖
if (traversal(root) == 0) result++;
return result;
}
};
因为贪心题比较多,就分上下两篇记录了。
贪心没有固定的套路,只要能通过局部最优推导出全局最优就可以尝试贪心了。
贪心更多的是思想与解题技巧。
贪心结束了,下面就是天下无敌的动态规划了(吐血)。