算法日记day 32(贪心之划分字母区间|合并区间|单调递增的数字|监控二叉树)

news2024/9/25 21:24:56

一、划分字母区间

题目:

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。

注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。

返回一个表示每个字符串片段的长度的列表。

示例 1:

输入:s = "ababcbacadefegdehijhklij"
输出:[9,7,8]
解释:
划分结果为 "ababcbaca"、"defegde"、"hijhklij" 。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 这样的划分是错误的,因为划分的片段数较少。 

示例 2:

输入:s = "eccbbbbdec"
输出:[10]

思路:

如何确立划分的一个片段有多少是关键,我们需要记录同一个字母的下标,在循环遍历字符串的过程中,每当相同的字母出现一次就更新成最新的位置,在遍历时如果找到最远出现下标的位置,说明找到了分割点,此时就属于一个片段,记录其长度至结果数组中,重复此操作,直到找到遍历完全部字符串

代码:

public List<Integer> partitionLabels(String s) {
    List<Integer> list = new LinkedList<>(); // 创建一个存储结果的链表
    int[] edge = new int[26]; // 创建一个长度为26的数组,用于记录每个字母在字符串中最后出现的位置
    char[] chars = s.toCharArray(); // 将字符串转换为字符数组,方便遍历和操作
    for (int i = 0; i < chars.length; i++) {
        edge[chars[i] - 'a'] = i; // 记录每个字母在字符串中最后出现的位置
        //char[i] - 'a'为对应字母的ascii码形式
    }
    int left = 0; // 初始化左边界
    int right = 0; // 初始化右边界
    for (int i = 0; i < chars.length; i++) {
        right = Math.max(right, edge[chars[i] - 'a']); // 更新当前片段的右边界
        if (i == right) { // 如果当前位置i达到了当前片段的右边界
            list.add(right - left + 1); // 将当前片段的长度添加到结果列表中
            left = right + 1; // 更新下一个片段的左边界
        }
    }
    return list; // 返回结果列表
}

二、合并区间

题目:

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

示例 1:

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:

输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。

思路:

首先对全部区间的左边界从小到大排序,遍历的过程中比较该区间的左边界是否小于上一个区间的右边界 ,如果是,说明这两个区间有重合部分需要合并,合并时需取两区间左边界较小的值,右边界较大的值,然后存入结果数组中,最后输出结果数组

代码:

public int[][] merge(int[][] intervals) {
    LinkedList<int[]> res = new LinkedList<>(); // 创建一个链表用于存储合并后的区间结果
    Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0])); // 根据区间的起始位置排序输入的二维数组

    res.add(intervals[0]); // 将第一个区间添加到结果链表中作为起始

    // 遍历排序后的区间数组
    for (int i = 1; i < intervals.length; i++) {
        // 如果当前区间的起始位置小于等于结果链表中最后一个区间的结束位置
        if (intervals[i][0] <= res.getLast()[1]) {
            int start = res.getLast()[0]; // 获取结果链表中最后一个区间的起始位置
            int end = Math.max(intervals[i][1], res.getLast()[1]); // 计算当前区间与结果链表中最后一个区间合并后的结束位置
            res.removeLast(); // 移除结果链表中最后一个区间
            res.add(new int[] { start, end }); // 将合并后的区间添加到结果链表中
        } else {
            res.add(intervals[i]); // 如果当前区间不能与结果链表中最后一个区间合并,则直接添加当前区间到结果链表中
        }
    }

    return res.toArray(new int[res.size()][]); // 将结果链表转换为二维数组并返回
}
  1. 链表初始化:

    • LinkedList<int[]> res = new LinkedList<>();
      • 创建一个链表 res 用来存储合并后的区间结果。
  2. 排序:

    • Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
      • 根据二维数组 intervals 中每个子数组的第一个元素(区间的起始位置)进行排序。
  3. 添加第一个区间:

    • res.add(intervals[0]);
      • 将排序后的第一个区间添加到链表 res 中作为起始。
  4. 合并区间:

    • 使用 for 循环遍历排序后的区间数组 intervals
      • 如果当前区间的起始位置小于等于链表 res 中最后一个区间的结束位置,则说明这两个区间可以合并。
      • 计算合并后的起始位置为链表中最后一个区间的起始位置,合并后的结束位置为当前区间和链表中最后一个区间结束位置的较大值。
      • 更新链表 res 中最后一个区间为合并后的区间。
      • 如果当前区间不能与链表 res 中最后一个区间合并,则直接将当前区间添加到链表 res 中。
  5. 返回结果:

    • return res.toArray(new int[res.size()][]);
      • 将链表 res 转换为二维数组并返回,这个二维数组包含了所有合并后的区间。

三、单调递增的数字

题目:

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

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

示例 1:

输入: n = 10
输出: 9

示例 2:

输入: n = 1234
输出: 1234

示例 3:

输入: n = 332
输出: 299

思路:

如果n中的前一位数大于后一位数,则让前一位值减一,为了使其数得到的为最大,后面位的数字全部变为9

代码:

public int monotoneIncreasingDigits(int n) {
    // 将整数 n 转换为字符串
    String str = String.valueOf(n);
    // 将字符串转换为字符数组,方便后续操作
    char[] chars = str.toCharArray();
    // 记录递减位置的标志位,初始为字符串长度
    int flag = str.length();
    
    // 从字符串的倒数第二位开始向前遍历
    for (int i = str.length() - 1; i > 0; i--) {
        // 如果前一位比当前位大,说明需要进行调整
        if (chars[i - 1] > chars[i]) {
            // 将前一位减1
            chars[i - 1]--;
            // 更新递减位置的标志位
            flag = i;
        }
    }
    
    // 将从 flag 位置开始的所有字符设置为 '9',以确保最大化单调递增
    for (int i = flag; i < str.length(); i++) {
        chars[i] = '9';
    }
    
    // 将字符数组重新转换为整数并返回
    return Integer.parseInt(String.valueOf(chars));
}
  1. 字符串处理:

    • String str = String.valueOf(n);
      • 将输入的整数 n 转换为字符串 str,方便后续操作。
  2. 字符数组准备:

    • char[] chars = str.toCharArray();
      • 将字符串 str 转换为字符数组 chars,以便可以直接修改其中的字符内容。
  3. 递减位置标志初始化:

    • int flag = str.length();
      • flag 用于记录发生递减的位置,默认初始化为字符串的长度。如果发生递减,将更新为当前递减的位置。
      • 这里flag初始化为字符串长度还有个好处,若是初始化为0,如果本身的数就为单调递增(例如n=1234),此时在运行至 for (int i = flag; i < str.length(); i++) { chars[i] = '9'; } 时,就会把原有数字全部覆盖为9999,得到错误的结果,因此初始化为字符串长度避免了这种情况
  4. 递减位置处理:

    • 使用从字符串末尾开始的循环,比较每一位和它前一位的大小关系:
      • if (chars[i - 1] > chars[i]):如果前一位比当前位大,表示发生了递减。
      • chars[i - 1]--:将前一位减去1,以确保满足单调递增的要求。
      • flag = i;:更新 flag,记录最后一次发生递减的位置。
  5. 最大化单调递增:

    • 从 flag 位置开始,将所有字符设为 '9',因为从这个位置开始的所有位都已经被调整为符合单调递增的最大值。
  6. 返回结果:

    • return Integer.parseInt(String.valueOf(chars));
      • 将字符数组 chars 转换为字符串,然后再转换为整数,并将其作为结果返回。

四、监控二叉树

题目:

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

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

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

示例 1:

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

示例 2:

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

思路:

首先定义状态

0为未被摄像头覆盖区域

1为安装了摄像头区域

2为被摄像头覆盖的区域

总共可分为四种情况

1、根节点的左右子节点都有覆盖(都为状态2)

此时根节点为未被覆盖状态0,返回0

2、左右子节点至少有一个没有被覆盖(至少一个为状态0)

此时根节点必须安装摄像头,才能保证子节点均被覆盖,返回1

3、左右子节点至少有一个装有摄像头(至少一个为状态1)

此时根节点为被覆盖状态,返回1

4、再遍历完所有子节点后,返回至第一层时的根节点无覆盖

此时需要在根节点加入一个摄像头,返回1

代码:

class Solution {
    int result = 0; // 全局变量,记录摄像头数量

    public int minCameraCover(TreeNode root) {
        if (traversal(root) == 0) { // 如果根节点需要安装摄像头
            result++; // 增加摄像头数量
        }
        return result;
    }

    // 后序遍历递归方法,返回当前节点的状态
    // 0:当前节点需要安装摄像头
    // 1:当前节点已经安装了摄像头
    // 2:当前节点被覆盖但不需要额外摄像头
    private int traversal(TreeNode root) {
        if (root == null) {
            return 2; // 空节点被覆盖
        }

        int left = traversal(root.left); // 遍历左子树
        int right = traversal(root.right); // 遍历右子树

        // 如果左右子树有任意一个需要安装摄像头
        if (left == 0 || right == 0) {
            result++; // 在当前节点安装摄像头
            return 1; // 返回1表示当前节点已经安装了摄像头
        }

        // 如果左右子树都被覆盖且无需额外摄像头
        if (left == 2 && right == 2) {
            return 0; // 返回0表示当前节点需要安装摄像头
        }

        return 2; // 其他情况,返回2表示当前节点被覆盖但不需要额外摄像头
    }
}
  1. result 是全局变量,用来记录整棵树需要安装的摄像头数量。
    • minCameraCover 方法是公共方法,用于计算整棵二叉树最少需要安装的摄像头数量。
      • 如果根节点需要安装摄像头,则增加 result 的计数。
      • 返回最终的 result 数量。
    • 后序遍历的递归方法,用于确定每个节点的状态。
    • 参数 root 是当前要处理的节点。
    • 返回值说明:
      • 0:当前节点需要安装摄像头。
      • 1:当前节点已经安装了摄像头。
      • 2:当前节点被覆盖但不需要额外摄像头。

今天的学习就到这里 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1989019.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nginx 405错误是什么意思

405错误&#xff1a;方法不被允许 当Web服务器收到一个它不支持的HTTP请求方法时&#xff0c;就会返回405错误。 原因 405错误通常是由于客户端发出了不兼容或不支持的HTTP请求方法。例如&#xff0c;客户端可能请求一个只能通过GET方法访问的资源&#xff0c;但使用了POST方…

C代码做底层及Matlab_SimuLink做应用层设计单片机程序

前言:SimuLink工具极其强大,但是能直接支持单片机自主开发的很少,造成这个问题的原因主要是我们使用的芯片底层多是C代码工程,芯片厂家也只提供C代码库,很少能提供SimuLink的支持库,即使提供也不是很不完善,如NXP的一些芯片提供的SimuLink库不含盖高级应用,再比如意法半…

视创云展:轻松构建出独一无二的元宇宙空间

视创云展作为一款前沿的元宇宙数字营销平台&#xff0c;集成了多项核心技术&#xff0c;旨在为用户提供低门槛、高效能的元宇宙体验与创作工具。其核心技术主要包括&#xff1a; 1、低门槛、模块化&#xff0c;3D场景创作工具 视创云展集成了海量的元宇宙场景模板&#xff0c;…

SpringBoot中如何自定义自己的过滤器Filter(简易版)

本文不再说SpringMVC中的写法&#xff0c;毕竟现在项目都是SpringBoot&#xff0c;我们还是尽量使用SpringBoot的写法&#xff0c;首先了解一下Filter。 说白了&#xff0c;就是在请求到达服务器之前进行拦截&#xff0c;一般使用场景是拦截登录进行权限校验&#xff0c;当然一…

跟李沐学AI:GoogLeNet含并行连结的网络

Inception块 GoogleNet中的基本卷积块&#xff0c;从4个路径从不同层面抽取信息&#xff0c;然后再输出通道维合并。 数据输入后共有四条路径&#xff1a;第一个路径为1x1的卷积层&#xff1b;第二个路径先用1x1的卷积层修改通道数&#xff0c;在输入到3x3的卷积层&#xff0c…

腾讯云AI代码助手助力软件开发体验分享

引言 现在&#xff0c;AI工具在软件开发中变得越来越重要&#xff0c;它们能显著提升效率和代码质量。本文就来分享一下我用腾讯云AI代码助手的经历&#xff0c;看看它是怎么在开发中帮了大忙的。 开发环境介绍 这次的项目用的是JavaScript&#xff0c;开发环境是Windows 10…

用于胰腺癌自动化综述报告和可切除性分类的大型语言模型| 文献速递-基于深度学习的乳房、前列腺疾病诊断系统

Title 题目 Large Language Models for Automated Synoptic Reports and Resectability Categorization in Pancreatic Cancer 用于胰腺癌自动化综述报告和可切除性分类的大型语言模型 Background 背景 Structured radiology reports for pancreatic ductal adenocarcinom…

condition字符串匹配问题

概述 freeswitch是一款简单好用的VOIP开源软交换平台。 fs使用dialplan配置文件执行业务流程&#xff0c;condition条件变量的配置是必然会使用的&#xff0c;这里记录一次配置过程中的错误示范。 环境 CentOS 7.9 freeswitch 1.10.7 问题描述 dialplan配置如下&#xf…

如何做到项目真实性优化?保姆级写简历指南第五弹!

大家好&#xff0c;我是程序员鱼皮。做知识分享这些年来&#xff0c;我看过太多简历、也帮忙修改过很多的简历&#xff0c;发现很多同学是完全不会写简历的、会犯很多常见的问题&#xff0c;不能把自己的优势充分展示出来&#xff0c;导致措施了很多面试机会&#xff0c;实在是…

pdf拆分需要怎么做?6个软件帮助你快速拆分pdf文件

pdf拆分需要怎么做&#xff1f;6个软件帮助你快速拆分pdf文件 拆分PDF文件可以让你更方便地处理和管理文档内容&#xff0c;无论是提取特定页面还是将文件分成更小的部分。以下是六款帮助你快速拆分PDF文件的软件&#xff0c;每款软件都有其独特的功能和优势&#xff0c;供你选…

4章4节:临床数据科学中如何用R来进行缺失值的处理

在临床科研中,由于失访、无应答或记录不清等各种原因,经常会遇到数据缺失的问题。本文将深入探讨医学科研中数据缺失的成因、分类、影响以及应对方法,结合R语言的实际应用,为医学研究人员提供全面的解决方案。 一、认识缺失数据 其实,很多医学的纵向研究因获取数据资料时…

铜山金杏·打响区域公用品牌,助力乡村振兴新征程

为进一步提升徐州市铜山区农业产业发展的重要战略布局&#xff0c;从而更好地助力乡村振兴&#xff0c;徐州市铜山区农业农村局借助“铜山金杏地理标志农产品保护工程项目”联合山东百仕达地标产业有限公司打造铜山农特产品区域公用品牌——“铜山金杏”&#xff0c;充分挖掘铜…

大搜罗2024年数据恢复软件TOP3,互联网人士的年度推荐!

不管是咱们普通人&#xff0c;还是大大小小的公司&#xff0c;都怕数据一去不复返。好在科技给力&#xff0c;现在数据恢复软件越来越牛&#xff0c;帮我们解决了这块心病。今儿个&#xff0c;就给大家聊聊几款2024年超火的数据恢复软件&#xff0c;如转转大师数据恢复软件等&a…

防盗、防泄露、防篡改,我们把 ZooKeeper 的这种认证模式玩明白了

作者&#xff1a;子葵 你的 ZooKeeper 安全吗&#xff1f; 在当下网络安全事件频发的背景下&#xff0c;安全防护的构建成为日常开发与运维工作中的重中之重。ZooKeeper 存储着系统敏感实例信息与配置数据&#xff0c;但传统的使用方式并未为 ZooKeeper 配备强制身份验证机制…

Ubuntu查看IP地址

Ubuntu查看IP地址 文章目录 Ubuntu查看IP地址查看IP地址的命令遇到的问题解决方案 查看IP地址的命令 1.使用ifconfig 2.使用hostname -I&#xff08;-之前一个空格&#xff09; 3.使用ip addr show 遇到的问题 1.使用ifconfig只显示一个127.0.0.1地址 2.使用hostname -I …

成功解决LabVIEW中加载 lvanlys.dll动态链接库(DLL)初始化例程失败

‍‍&#x1f3e1;博客主页&#xff1a; virobotics(仪酷智能)&#xff1a;LabVIEW深度学习、人工智能博主 &#x1f384;所属专栏&#xff1a;『奇怪问题及Bug解决』 &#x1f4d1;精选文章&#xff1a;LabVIEW人工智能深度学习指南 &#x1f37b;本文由virobotics(仪酷智能)原…

事务和索引(面试常问)

面试常问&#xff1a; 一、数据库隔离级别&#xff1f;事务隔离级别解决的问题&#xff1f; 答&#xff1a;1.数据库隔离级别&#xff1a; READ_UNCOMMITTED 读未提交 READ_COMMITTED 读提交&#xff08;不可重复读&#xff09; REPEATABLE_READ 可重复读 SERIALIZABLE 串行化…

Spring学习(三)-Bean的作用域和生命周期

Spring学习&#xff08;三&#xff09;-Bean的作用域和生命周期 –2020年06月25日 一、bean的作用域 概念&#xff1a; Spring 2.5之前的Bean 的作用域只有两种 Springleton&#xff1a;单例Bean Prototype &#xff1a; 原型Bean Spring 2.5 之后Bean的作用域有一下五种 …

C语言 Unix 时间戳 和 时间日期相互转换

Unix 时间戳&#xff08;也称为 POSIX 时间戳&#xff09;是一个表示从 1970 年 1 月 1 日 UTC 时刻开始所经过的秒数的数值。这个时间戳是与时间区域无关的&#xff0c;也就是说它在全球任何地方都表示同一个时刻。 如果你要将 Unix 时间戳转换为某个特定时区的时间&#xff…

封闭式蓝牙耳机推荐?4款更实用的开放式耳机推荐

封闭式耳机我想应该是头戴式耳机中的一种耳机类型吧&#xff0c;而开放式耳机则是一种范围比较大的耳机类型&#xff0c;这两种耳机类型确实有比较大的区别&#xff1a; 声音泄漏与隔音效果&#xff1a; 开放式耳机&#xff1a;由于其设计允许空气流通&#xff0c;因此声音会…