贪心算法day.6

738.单调递增的数字

链接:. - 力扣(LeetCode)

题目描述:


当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。

给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增

示例 1:

输入: n = 10
输出: 9

示例 2:

输入: n = 1234
输出: 1234

示例 3:

输入: n = 332
输出: 299

提示:

  • 0 <= n <= 109.

贪心思路:

当我们遍历数字的不同位数时,遇到当前位数小于后面的位数,则当前位-1,后面位取最大值,例如32,3小于2,因此-1得到2,后一位找的最大值9,因此就得出结果29,我们在遍历的时候应该由后往前遍历,因为由前往后遍历,可能后面得到的数值会比前面的小,例如332,由前向后遍历结果为329,这不符合我们的题目要求,因此我们就需要从后往前遍历,这样332遍历即先比较3和2,之后就变为了329,最后就得到的就是299

代码实现:


int monotoneIncreasingDigits(int n) {
    char num[12]; // 数组大小增加到12,以便容纳最大的整数9999999999及结尾的'\0'
    sprintf(num, "%d", n);
    int mark = strlen(num); // 初始化 mark 为 num 的长度,用于记录需要修改的位置

    // 从倒数第二位开始向前遍历,找到第一个不满足递增条件的位置
    for(int i = mark - 1; i > 0; i--) {
        if(num[i - 1] > num[i]) {
            num[i - 1]--; // 将前一位数字减1
            mark = i; // 记录需要修改的位置
        }
    }

    // 将 mark 位置及其后面的所有数字都修改为9
    for(int j = mark; j < strlen(num); j++) {
        num[j] = '9';
    }

    return atoi(num);
}

968.监控二叉树

链接:. - 力扣(LeetCode)

题目描述:

给定一个二叉树,我们在树的节点上安装摄像头。

节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。

计算监控树的所有节点所需的最小摄像头数量。

示例 1:

输入:[0,0,null,0,0]
输出:1
解释:如图所示,一台摄像头足以监控所有节点。

示例 2:

输入:[0,0,null,0,null,0,null,null,0]
输出:2
解释:需要至少两个摄像头来监视树的所有节点。 上图显示了摄像头放置的有效位置之一。

提示:

  1. 给定树的节点数的范围是 [1, 1000]
  2. 每个节点的值都是 0。

思路:

根据题目可知,一个摄像头可以覆盖上中下,即可以监控4个节点,因此我们最好在叶子节点的父节点上安装摄像头,这样最大程度的利用了摄像头的覆盖范围,之后往上回退,每隔两个节点放置一个摄像头,直到遇到根节点(局部最优),因为我们要在从下往上去遍历我们的二叉树,因此我们需要后序遍历二叉树,即左右中,依靠回溯的过程去放置摄像头,对于我们的节点,都有几个状态,即0没有被覆盖,2被覆盖,1有摄像头3个状态,我们就可以根据节点的状态来确定哪些节点需要放置摄像头,对于我们叶子节点下的空节点,我们要将其设置为被覆盖的状态,否则会导致叶子节点要放置摄像头,而我们要在叶子节点的父节点放置

节点状态转移的过程:

如果左右孩子都是有覆盖的情况下,则父节点应该是无覆盖状态,要转换为有摄像头状态

如果左右孩子至少有一个覆盖,则父节点一定要有摄像头

如果左右孩子至少有一个有摄像头,其父节点一定是有覆盖状态

如果我们遍历完了,而根节点还是无覆盖状态,我们需要加上摄像头

代码实现:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

// 递归函数,用于遍历树的节点并确定相机的放置情况
// 返回值的意义:
// 0: 当前节点的子节点均被覆盖
// 1: 当前节点放置了相机
// 2: 当前节点未被覆盖
int ph(struct TreeNode *node, int *ans)
{
    // 如果节点为空,返回2,表示未被覆盖
    if(node == NULL)
        return 2;
    
    // 递归遍历左子树和右子树
    int left = ph(node->left, ans);
    int right = ph(node->right, ans);

    // 如果左右子树均未被覆盖,则当前节点需要放置相机
    if(left == 2 && right == 2)
        return 0;
    
    // 如果左右子树中有至少一个节点放置了相机,当前节点被覆盖
    if(left == 0 || right == 0)
    {
        (*ans)++;
        return 1;
    }
    
    // 如果左右子树中有至少一个节点未被覆盖,当前节点未被覆盖
    if(left == 1 || right == 1)
    {
        return 2;
    }
    
    return -1; // 其他情况,返回-1
}

// 主函数,计算最少需要多少个相机才能覆盖整棵树
int minCameraCover(struct TreeNode* root) {
    int ans = 0;
    // 调用递归函数,计算需要的相机数量
    if(ph(root, &ans) == 0)
        ans++; // 如果根节点需要放置相机,则相机数量加1
    return ans; // 返回相机数量
}

  • 24
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值