代码随想录Day37

70 阅读2分钟

738.单调递增的数字

力扣题目链接

// 暴力解法 
    // 时间复杂度:O(n × m) m为n的数字长度
    // 空间复杂度:O(1)

    bool checkNum(int num) {
        int max = 10;
        while (num) {
            int t = num % 10;
            if (max >= t) {
                max = t;
            }
            else return false;
            num /= 10;
        }
        return true;
    }

    int monotoneIncreasingDigits1(int n) {
        for (int i = n; i > 0; i--) {
            if (checkNum(i)) {
                return i;
            }
        }
        return 0;
    }

    // 贪心算法,找到strNum[i - 1] > strNum[i]的位置,让strNum[i - 1]--,然后将strNum[i]置为零(相当于高位退一,低位拉满,一定符合单调递增),这使得局部达到最优,由后向前遍历操作,使局部最优变为全局最优,举不出反例。
    int monotoneIncreasingDigits(int n) {
        string strNum = to_string(n);
        // flag用来标记赋值9从哪里开始
        // 设置为这个默认值,为了防止第二个for循环在flag没有被赋值的情况下执行
        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.监控二叉树

力扣题目链接

class Solution {
public:
    // 要从下往上看,局部最优:让叶子节点的父节点安摄像头,所用摄像头最少,整体最优:全部摄像头数量所用最少!
    // 状态设置:0——无覆盖、2——有覆盖、1——有摄像头
    // 应该采用后序遍历,来从下往上遍历树
    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;
    }
    int minCameraCover(TreeNode* root) {
        result = 0;
        // 情况4 根节点未覆盖
        if (traversal(root) == 0) {
            result++;
        }
        return result;
    }
};