56m. 合并区间
方法一:排序+贪心
用时:9m16s
思路
先将各个区间按照左边界升序排序,然后遍历区间,当两个区间重叠时,将两个区间合并,没有重叠就保存至结果中。
- 时间复杂度: O ( n log n ) O(n \log n) O(nlogn)。
- 空间复杂度: O ( log n ) O(\log n) O(logn)。
C++代码
class Solution {
private:
static bool cmp(const vector<int>& a, const vector<int>& b) {
return a[0] < b[0]; // 按照左边界升序排序
}
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> res;
sort(intervals.begin(), intervals.end(), cmp);
for (int i = 1; i < intervals.size(); ++i) {
if (intervals[i][0] <= intervals[i - 1][1]) { // 如果两区间重叠,则将两个区间合并
intervals[i][0] = intervals[i - 1][0];
intervals[i][1] = max(intervals[i][1], intervals[i - 1][1]);
} else res.push_back(intervals[i - 1]); // 如果不重叠,则将上一个区间记录至结果中
}
res.push_back(intervals.back());
return res;
}
};
看完讲解的思考
无。
代码实现遇到的问题
无。
738m. 单调递增的数字
方法一:贪心
用时:20m41s
思路
将数字转化成字符串,遍历字符串,找到第一个不满足递增的数字的前一个数字k,如果k前面有连续的与k相同的数字,则找到第一个k,(例如num="12344444298"
,找到num[3]='4'
,)将k减一,并将它后续的数字全变成9,然后将字符串转化回int类型。
- 时间复杂度: O ( d ) O(d) O(d),d为数字的位数。
- 空间复杂度: O ( d ) O(d) O(d)。
C++代码
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string num = to_string(n);
for (int i = 0, maxIdx = 0; i < num.size(); ++i) {
if (num[i] > num[maxIdx]) maxIdx = i;
else if (num[i] < num[maxIdx]) {
num[maxIdx] -= 1;
for (int j = maxIdx + 1; j < num.size(); ++j) num[j] = '9';
break;
}
}
return stoi(num);
}
};
看完讲解的思考
无。
代码实现遇到的问题
无。
968h. 监控二叉树
方法一:后序遍历+贪心
用时:21m22s
思路
递归三部曲:
- 确定参数和返回值:参数是节点。返回值是int,用int来表示当前节点的状态:0-无覆盖;1-有摄像头;2-有覆盖但没摄像头。
- 递归结束的条件:空节点则结束递归,返回2。空节点返回的值不能影响父节点的状态选择,如果空节点返回0,则父节点就会因为这个0导致需要放置摄像头,如果空节点返回1,则父节点就会因为子节点有摄像头而状态变成已被覆盖,所以空节点只能返回2。
- 单层递归逻辑:1)若左右节点中有节点未被覆盖,则当前节点必须装摄像头。2)若左右节点中有摄像头,则当前节点会被覆盖。3)若左右节点都被覆盖但没有摄像头,则当前节点未被覆盖。
需要注意的点,如果遍历完所有节点,根节点的状态是0,则需要在根节点再装一个摄像头。
- 时间复杂度: O ( n ) O(n) O(n)。
- 空间复杂度: O ( n ) O(n) O(n)。
C++代码
class Solution {
private:
int res;
int dfs(TreeNode* node) { // 后序遍历,返回值:0-无覆盖;1-有摄像头;2-有覆盖但没摄像头
if (node == nullptr) return 2; // 空结点相当于被覆盖但没有摄像头的节点
int left = dfs(node->left); // 左节点覆盖情况
int right = dfs(node->right); // 右节点覆盖情况
if (left == 0 || right == 0) { // 若左右节点中有节点未被覆盖,则当前节点必须装摄像头
++res;
return 1;
} else if (left == 1 || right == 1) return 2; // 若左右节点中有摄像头,则当前节点会被覆盖
else return 0; // 若左右节点都被覆盖但没有摄像头,则当前节点未被覆盖
}
public:
int minCameraCover(TreeNode* root) {
res = 0;
return dfs(root) == 0 ? res + 1 : res; // 如果根节点未被覆盖,则需要在根节点放置一个摄像头
}
};
看完讲解的思考
思路理解起来不难,但是很难想到这种方法。
代码实现遇到的问题
最后根节点可能未被覆盖,需要判断是否需要加装一个摄像头。
最后的碎碎念
芜湖~贪心章节完结撒花!!!
接下来要进入题量最多的动态规划章节了😰。