代码学习记录29----贪心最后一天

随想录日记part29

t i m e : time: time 2024.03.28



主要内容:今天是学习贪心算法最后一天,接下来是针对题目的讲解:1.单调递增的数字;2.监控二叉树; 3. 总结



Topic1单调递增的数字

题目:

当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。
给定一个整数 n ,返回小于或等于 n 的最大数字,且数字呈 单调递增 。

输入: n = 10 n = 10 n=10
输出: 9 9 9

思路:

思路简单直接看答案。

代码如下:

class Solution {
    public int monotoneIncreasingDigits(int n) {
        if (n >= 0 && n <= 9)
            return n;
        int count = wei(n);
        int[] nums = new int[count];
        int tem = n;
        for (int i = count - 1; i >= 0; i--) {
            nums[i] = tem % 10;
            tem = tem / 10;
        }
        int flag = count;
        for (int i = count - 1; i > 0; i--) {
            if (nums[i] < nums[i - 1]) {
                nums[i - 1]--;
                flag = i;
            }
        }
        for (int i = flag; i < count; i++) {
            nums[i] = 9;
        }
        int sum = 0;
        for (int i = 0; i < count; i++) {
            sum = sum * 10 + nums[i];
        }
        return sum;
    }

    private int wei(int n) {
        if (n < 10)
            return 1;
        int tem = n;
        int result = 0;
        while (tem != 0) {
            result++;
            tem = tem / 10;
        }
        return result;
    }
}

时间复杂度 O ( n ) O(n) O(n)
空间复杂度 O ( n ) O(n) O(n)



Topic2监控二叉树

题目:

给定一个二叉树,我们在树的节点上安装摄像头。节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。计算监控树的所有节点所需的最小摄像头数量。
在这里插入图片描述

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

思路:

从下往上看,局部最优:让叶子节点的父节点安摄像头,所用摄像头最少,整体最优:全部摄像头数量所用最少!局部最优推出全局最优,找不出反例,那么就按照贪心来!
大体思路就是从低到上,先给叶子节点父节点放个摄像头,然后隔两个节点放一个摄像头,直至到二叉树头结点。
此时这道题目还有两个难点:

  • 二叉树的遍历
  • 如何隔两个节点放一个摄像头

如何隔两个节点放一个摄像头:
每个节点可能有几种状态:有如下三种:

  • 该节点无覆盖
  • 本节点有摄像头
  • 本节点有覆盖

分别有三个数字来表示:
0:该节点无覆盖
1:本节点有摄像头
2:本节点有覆盖
递归的终止条件: 应该是遇到了空节点,此时应该返回2。
单层逻辑处理:
【情况1】:左右节点都有覆盖
左孩子有覆盖,右孩子有覆盖,那么此时中间节点应该就是无覆盖的状态了。
【情况2】:左右节点至少有一个无覆盖的情况
如果是以下情况,则中间节点(父节点)应该放摄像头:
left == 0 && right == 0 左右节点无覆盖
left == 1 && right == 0 左节点有摄像头,右节点无覆盖
left == 0 && right == 1 左节点有无覆盖,右节点摄像头
left == 0 && right == 2 左节点无覆盖,右节点覆盖
left == 2 && right == 0 左节点覆盖,右节点无覆盖
【情况3】:左右节点至少有一个有摄像头
如果是以下情况,其实就是 左右孩子节点有一个有摄像头了,那么其父节点就应该是2(覆盖的状态)
left == 1 && right == 2 左节点有摄像头,右节点有覆盖
left == 2 && right == 1 左节点有覆盖,右节点有摄像头
left == 1 && right == 1 左右节点都有摄像头
【情况4】:头结点没有覆盖
以上都处理完了,递归结束之后,可能头结点 还有一个无覆盖的情况

整体代码如下:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 * int val;
 * TreeNode left;
 * TreeNode right;
 * TreeNode() {}
 * TreeNode(int val) { this.val = val; }
 * TreeNode(int val, TreeNode left, TreeNode right) {
 * this.val = val;
 * this.left = left;
 * this.right = right;
 * }
 * }
 */
class Solution {
    int result;

    public int minCameraCover(TreeNode root) {
        result = 0;
        int tem = reback(root);
        if (tem == 0)
            result++;
        return result;
    }

    private int reback(TreeNode root) {
        // 递归出口
        if (root == null)
            return 2;
        int left = reback(root.left);
        int right = reback(root.right);
        // 【情况1】:左右节点都有覆盖
        if (left == 2 && right == 2) {
            return 0;
        }
        // 【情况2】:左右节点至少有一个无覆盖的情况
        if (left == 0 || right == 0) {
            result++;
            return 1;
        }
        // 【情况3】:左右节点至少有一个有摄像头
        if (left == 1 || right == 1) {
            return 2;
        }
        return -1;
    }
}

时间复杂度 O ( n ) O(n) O(n)
空间复杂度 O ( n ) O(n) O(n)



  • 38
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
贪心算法是一种优化问题的常用方法,它在每个步骤中选择当前最佳的选项,以期望最终得到全局最优解。下面是几个常见的贪心算法例题及其代码过程。 1. 题目:跳跃游戏 II 给定一个非负整数数组,您最初定位在数组的第一个索引处。 数组中的每个元素表示您在那个位置可以跳跃的最大长度。 您的目标是到达最后一个索引,使得跳跃次数最小。 例如,给定一个长度为 4 的数组 [2,3,1,1,4],最少的跳跃次数为 2。跳到第一个索引处的最小跳跃数为 1,从第一个索引跳跃到最后一个索引的最小跳跃数为 1。 解题思路:对于每个位置,计算能够跳到的最远位置,然后在这些位置中选择最大的跳跃位置。 代码实现: ```python def jump(nums): n = len(nums) max_pos, end, step = 0, 0, 0 for i in range(n - 1): if max_pos >= i: max_pos = max(max_pos, i + nums[i]) if i == end: end = max_pos step += 1 return step ``` 2. 题目:分发饼干 假设你是一位很棒的家长,想要给你的孩子们一些饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i,都有一个胃口值 gi,这是一个整数。如果你有一块饼干,且其大小为 si,则这个饼干可以满足孩子 i 的胃口,当且仅当 si >= gi。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 解题思路:将饼干和孩子的胃口值排序,然后按顺序将饼干分配给孩子,直到饼干用完或者孩子都被满足。 代码实现: ```python def findContentChildren(g, s): g.sort() s.sort() i, j, count = 0, 0, 0 while i < len(g) and j < len(s): if s[j] >= g[i]: count += 1 i += 1 j += 1 return count ``` 3. 题目:买卖股票的最佳时机 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 注意你不能在买入股票前卖出股票。 解题思路:记录最小价格和最大利润,在遍历过程中更新最小价格和最大利润。 代码实现: ```python def maxProfit(prices): min_price, max_profit = float('inf'), 0 for price in prices: min_price = min(min_price, price) max_profit = max(max_profit, price - min_price) return max_profit ``` 以上就是几个常见的贪心算法例题及其代码过程。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值