代码随想录训练营第三十七天打卡|738.单调递增的数字 968.监控二叉树

738.单调递增的数字

1.暴力法:当前元素递减,每次减一都判断一下是否满足单调递增数字条件。不出意外的超时了,只通过了三分之二的测试用例。但考虑到是自己写的,还是贴一下代码。

class Solution {
    bool isIncrease(int n) {
        vector<int> result;
        while (n) {
            result.push_back(n % 10);
            n = n / 10;
        }
        for (int i = 0; i < result.size() - 1; i++) {
            if (result[i] < result[i + 1])
                return false;
        }
        return true;
    }

public:
    int monotoneIncreasingDigits(int n) {
        while (n) {
            if (isIncrease(n))
                break;
            else
                n--;
        }
        return n;
    }
};

2.正经解法:贪心。

例如:98,一旦出现s[i - 1] > s[i]的情况(非单调递增),首先想让st[i - 1]--,然后s[i]给为9,这样这个整数就是89,即小于98的最大的单调递增整数。这一点如果想清楚了,这道题就好办了。此时是从前向后遍历还是从后向前遍历呢?从前向后遍历的话,遇到s[i - 1] > s[i]的情况,让s[i - 1]减一,但此时如果s[i - 1]减一了,可能又小于s[i - 2]。这么说有点抽象,举个例子,数字:332,从前向后遍历的话,那么就把变成了329,此时2又小于了第一位的3了,真正的结果应该是299。那么从后向前遍历,就可以重复利用上次比较得出的结果了,从后向前遍历332的数值变化为:332 -> 329 -> 299。(从后向前遍历,找到最后一个不满足单调递增的位置,用flag标记。将flag前一位元素减一,flag及之后的元素全部变为9)

class Solution {
public:
    int monotoneIncreasingDigits(int n) {
        string s = to_string(n); //整数转字符串
        int flag = s.size();     // flag标记从哪开始赋值9
        for (int i = s.size() - 1; i > 0; i--) {
            if (s[i - 1] > s[i]) {
                s[i - 1]--; //更新元素,防止之后误判
                flag = i;   //更新标记位置
            }
        }
        for (int j = flag; j < s.size(); j++) {
            s[j] = '9'; //标记及以后位置全部赋值为9
        }
        return stoi(s); //字符串转整数
    }
};

968.监控二叉树

1.贪心:随想录版。局部最优:让叶子节点的父节点安摄像头,所用摄像头最少,整体最优:全部摄像头数量所用最少!二叉树中从低向上推导,采用后序遍历。注意三种状态的分析0:该节点无覆盖1:本节点有摄像头2:本节点有覆盖。(笔者也只是勉强看懂题解,暂给不出更犀利的见解,详情还请移步随想录网站)

/**
 * 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) {

        // 空节点,该节点有覆盖
        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;
    }
};

2.官解:动态规划。代码十分简洁,核心是罗列出需要维护的状态并分析状态转移转移方程。这实际上十分困难,是当之无愧的hard题。(注:个人水平有限,详情请看官方网站。)

/**
 * 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) {}
 * };
 */
struct Status {
    int a, b, c;
};

class Solution {
public:
    Status dfs(TreeNode* root) {
        if (!root) {
            return {INT_MAX / 2, 0, 0};
        }
        auto [la, lb, lc] = dfs(root->left);
        auto [ra, rb, rc] = dfs(root->right);
        int a = lc + rc + 1;
        int b = min(a, min(la + rb, ra + lb));
        int c = min(a, lb + rb);
        return {a, b, c};
    }

    int minCameraCover(TreeNode* root) {
        auto [a, b, c] = dfs(root);
        return b;
    }
};

今日总结:贪心+二叉树,闹麻了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值