AC代码:
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end(),
[](vector<int> a, vector<int> b) { return a[0] < b[0]; });
int left = intervals[0][0];
int right = intervals[0][1];
vector<vector<int>> ans;
for (int i = 1; i < intervals.size(); ++i) {
if (right < intervals[i][0]) {
ans.push_back(vector<int>{left, right});
left = intervals[i][0];
right = intervals[i][1];
} else {
// 注意[[1,4],[2,3]]的情况
// 只有在right小于当前查看区间的右边界时才更新right
if (right < intervals[i][1]) {
right = intervals[i][1];
}
}
}
// 记得把最后一个区间补上
// 对于最后一个合并区间,不会有某个小区间的左边界的值大于right了
ans.push_back(vector<int>{left, right});
return ans;
}
};
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> result;
if (intervals.size() == 0) return result; // 区间集合为空直接返回
// 排序的参数使用了lambda表达式
sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b){return a[0] < b[0];});
// 第一个区间就可以放进结果集里,后面如果重叠,在result上直接合并
result.push_back(intervals[0]);
for (int i = 1; i < intervals.size(); i++) {
if (result.back()[1] >= intervals[i][0]) { // 发现重叠区间
// 合并区间,只更新右边界就好,因为result.back()的左边界一定是最小值,因为我们按照左边界排序的
result.back()[1] = max(result.back()[1], intervals[i][1]);
} else {
result.push_back(intervals[i]); // 区间不重叠
}
}
return result;
}
};
重点在于找到从左往右第一个递减的位置,要求尽可能大且要小于当前数,所以,例如3321,3到2是递减的,此时最接近32的就是29,又因为要递增,所以后面的所有数也应该是变为9,;另外,此时3变成2后,前面又不满足递增的要求了,所以我们要继续往前遍历,因此我们从后往前遍历,记录最后的递减位置,将这个位置之后的所有数都改为9
AC代码:
class Solution {
public:
int monotoneIncreasingDigits(int n) {
string s = to_string(n);
int pos = s.size();
for (int i = s.size() - 1; i > 0; --i) {
if (s[i - 1] > s[i]) {
pos = i;
s[i - 1]--;
}
}
for (int i = pos; i < s.size(); ++i) {
s[i] = '9';
}
return stoi(s);
}
};
代码如下:
class Solution {
// 四种状态,只有子节点返回CameraFatherFather和CameraChild时才将当前节点设置为相机
// 换句话说,就是希望一个相近尽可能的监视更多的节点
enum State { CameraFatherFather, CameraFather, Camera, CameraChild };
public:
int minCameraCover(TreeNode* root) {
int ans = 0;
State state = GetMinCameraCover(root, ans);
if (state == State::CameraChild || state == State::CameraFatherFather) {
ans++;
}
return ans;
}
State GetMinCameraCover(TreeNode* root, int& ans) {
// 空节点视为被监视
if (root == nullptr)
return State::CameraFather;
// 叶子节点必须要有一个节点去监视
if (root->left == nullptr && root->right == nullptr)
return State::CameraChild;
State leftState = GetMinCameraCover(root->left, ans);
State rightState = GetMinCameraCover(root->right, ans);
// 如果左右节点有一个是叶子节点,那么父节点必须是相机
if (leftState == State::CameraChild ||
rightState == State::CameraChild) {
ans++;
return State::Camera;
}
// 如果子节点是相机的父节点,那么代表子节点是没有被监视的
// 为了用更少的相机监视更多的节点,我们不用子节点作相机,而是当前这个父节点
if (leftState == State::CameraFatherFather ||
rightState == State::CameraFatherFather) {
ans++;
return State::Camera;
}
// 子节点有一个是相机,代表当前节点是被监视的
if (leftState == State::Camera || rightState == State::Camera) {
return State::CameraFather;
}
return State::CameraFatherFather;
}
};
// 版本一
class Solution {
private:
int result;
int traversal(TreeNode* cur) {
// 空节点,该节点有覆盖
if (cur == NULL) return 2;
int left = traversal(cur->left); // 左
int right = traversal(cur->right); // 右
// 情况1
// 左右节点都有覆盖
if (left == 2 && right == 2) return 0;
// 情况2
// left == 0 && right == 0 左右节点无覆盖
// left == 1 && right == 0 左节点有摄像头,右节点无覆盖
// left == 0 && right == 1 左节点有无覆盖,右节点摄像头
// left == 0 && right == 2 左节点无覆盖,右节点覆盖
// left == 2 && right == 0 左节点覆盖,右节点无覆盖
if (left == 0 || right == 0) {
result++;
return 1;
}
// 情况3
// left == 1 && right == 2 左节点有摄像头,右节点有覆盖
// left == 2 && right == 1 左节点有覆盖,右节点有摄像头
// left == 1 && right == 1 左右节点都有摄像头
// 其他情况前段代码均已覆盖
if (left == 1 || right == 1) return 2;
// 以上代码我没有使用else,主要是为了把各个分支条件展现出来,这样代码有助于读者理解
// 这个 return -1 逻辑不会走到这里。
return -1;
}
public:
int minCameraCover(TreeNode* root) {
result = 0;
// 情况4
if (traversal(root) == 0) { // root 无覆盖
result++;
}
return result;
}
};