代码随想录Day31-贪心:力扣第56m、738m、968h题

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

思路

递归三部曲:

  1. 确定参数和返回值:参数是节点。返回值是int,用int来表示当前节点的状态:0-无覆盖;1-有摄像头;2-有覆盖但没摄像头。
  2. 递归结束的条件:空节点则结束递归,返回2。空节点返回的值不能影响父节点的状态选择,如果空节点返回0,则父节点就会因为这个0导致需要放置摄像头,如果空节点返回1,则父节点就会因为子节点有摄像头而状态变成已被覆盖,所以空节点只能返回2。
  3. 单层递归逻辑: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;  // 如果根节点未被覆盖,则需要在根节点放置一个摄像头
    }
};

看完讲解的思考

思路理解起来不难,但是很难想到这种方法。

代码实现遇到的问题

最后根节点可能未被覆盖,需要判断是否需要加装一个摄像头。


最后的碎碎念

芜湖~贪心章节完结撒花!!!
接下来要进入题量最多的动态规划章节了😰。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值