LeetCode 165. 比较版本号 - 优雅Java解决方案

文章目录

  • LeetCode 165. 比较版本号 - 优雅Java解决方案
    • 题目描述
    • 示例分析
      • 示例 1
      • 示例 2
      • 示例 3
    • 算法思路
    • Java实现方案
      • 方案一:双指针法(推荐)
      • 方案二:优化的单次遍历法
    • 可视化执行过程
      • 示例:compareVersion("1.2", "1.10")
      • 示例:compareVersion("1.01", "1.001")
      • 示例:compareVersion("1.0", "1.0.0.0")
    • 算法复杂度分析
      • 时间复杂度:O(max(m, n))
      • 空间复杂度:
    • 测试用例
    • 关键要点总结

LeetCode 165. 比较版本号 - 优雅Java解决方案

题目描述

给你两个 版本号字符串 version1version2 ,请你比较它们。版本号由被点 ‘.’ 分开的修订号组成。修订号的值是它转换为整数并忽略前导零。

比较版本号时,请按从左到右的顺序依次比较它们的修订号。如果其中一个版本字符串的修订号较少,则将缺失的修订号视为 0。

返回规则:

  • 如果 version1 < version2 返回 -1
  • 如果 version1 > version2 返回 1
  • 除此之外返回 0

示例分析

示例 1

输入:version1 = "1.2", version2 = "1.10"
输出:-1
解释:version1 的第二个修订号为 "2",version2 的第二个修订号为 "10":2 < 10,所以 version1 < version2

示例 2

输入:version1 = "1.01", version2 = "1.001"
输出:0
解释:忽略前导零,"01" 和 "001" 都代表相同的整数 "1"

示例 3

输入:version1 = "1.0", version2 = "1.0.0.0"
输出:0
解释:version1 有更少的修订号,每个缺失的修订号按 "0" 处理

算法思路

  1. 分割版本号:使用点号分割版本号字符串
  2. 双指针遍历:使用两个指针分别遍历两个版本号的修订号数组
  3. 逐个比较:从左到右比较对应位置的修订号
  4. 处理边界:当某个版本号的修订号用完时,将其视为0
  5. 返回结果:根据比较结果返回相应值

Java实现方案

方案一:双指针法(推荐)

public class Solution {public int compareVersion(String version1, String version2) {String[] v1 = version1.split("\\.");String[] v2 = version2.split("\\.");int maxLength = Math.max(v1.length, v2.length);for (int i = 0; i < maxLength; i++) {int num1 = i < v1.length ? Integer.parseInt(v1[i]) : 0;int num2 = i < v2.length ? Integer.parseInt(v2[i]) : 0;if (num1 < num2) {return -1;} else if (num1 > num2) {return 1;}}return 0;}
}

方案二:优化的单次遍历法

public class Solution {public int compareVersion(String version1, String version2) {int i = 0, j = 0;int n1 = version1.length(), n2 = version2.length();while (i < n1 || j < n2) {int num1 = 0, num2 = 0;// 解析version1的当前修订号while (i < n1 && version1.charAt(i) != '.') {num1 = num1 * 10 + (version1.charAt(i) - '0');i++;}i++; // 跳过点号// 解析version2的当前修订号while (j < n2 && version2.charAt(j) != '.') {num2 = num2 * 10 + (version2.charAt(j) - '0');j++;}j++; // 跳过点号if (num1 < num2) {return -1;} else if (num1 > num2) {return 1;}}return 0;}
}

可视化执行过程

让我们通过示例来可视化算法的执行过程:

示例:compareVersion(“1.2”, “1.10”)

初始状态:
version1 = "1.2"    →  ["1", "2"]
version2 = "1.10"   →  ["1", "10"]第1轮比较:
位置 i=0: num1=1, num2=1
1 == 1  →  继续第2轮比较:
位置 i=1: num1=2, num2=10  
2 < 10  →  返回 -1结果: -1 (version1 < version2)

示例:compareVersion(“1.01”, “1.001”)

初始状态:
version1 = "1.01"   →  ["1", "01"]   →  [1, 1]
version2 = "1.001"  →  ["1", "001"]  →  [1, 1]第1轮比较:
位置 i=0: num1=1, num2=1
1 == 1  →  继续第2轮比较:
位置 i=1: num1=1, num2=1 (忽略前导零)
1 == 1  →  继续所有修订号都相等
结果: 0 (version1 == version2)

示例:compareVersion(“1.0”, “1.0.0.0”)

初始状态:
version1 = "1.0"      →  ["1", "0"]
version2 = "1.0.0.0"  →  ["1", "0", "0", "0"]第1轮比较:
位置 i=0: num1=1, num2=1
1 == 1  →  继续第2轮比较:
位置 i=1: num1=0, num2=0
0 == 0  →  继续第3轮比较:
位置 i=2: num1=0(缺失视为0), num2=0
0 == 0  →  继续第4轮比较:
位置 i=3: num1=0(缺失视为0), num2=0
0 == 0  →  继续所有修订号都相等
结果: 0 (version1 == version2)

算法复杂度分析

时间复杂度:O(max(m, n))

  • m 和 n 分别是两个版本号的修订号个数
  • 需要遍历较长版本号的所有修订号

空间复杂度:

  • 方案一:O(m + n) - 需要存储分割后的数组
  • 方案二:O(1) - 只使用常数额外空间

测试用例

public class TestCompareVersion {public static void main(String[] args) {Solution solution = new Solution();// 测试用例1System.out.println(solution.compareVersion("1.2", "1.10"));      // -1// 测试用例2  System.out.println(solution.compareVersion("1.01", "1.001"));    // 0// 测试用例3System.out.println(solution.compareVersion("1.0", "1.0.0.0"));   // 0// 边界测试System.out.println(solution.compareVersion("0.1", "1.1"));       // -1System.out.println(solution.compareVersion("1.0.1", "1"));       // 1System.out.println(solution.compareVersion("7.5.2.4", "7.5.3")); // -1}
}

关键要点总结

  1. 忽略前导零:使用 Integer.parseInt() 自动处理
  2. 处理不同长度:缺失的修订号视为0
  3. 效率优化:方案二避免了字符串分割的开销
  4. 边界处理:正确处理版本号末尾的点号和空修订号

这个解决方案具有良好的可读性和效率,能够正确处理所有边界情况。

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

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

相关文章

基于Kubernetes StatefulSet的有状态微服务部署与持久化存储实践经验分享

基于Kubernetes StatefulSet的有状态微服务部署与持久化存储实践经验分享 在传统微服务架构中&#xff0c;大多数服务都是无状态的&#xff08;Stateless&#xff09;&#xff0c;可以通过 Deployment、ReplicaSet 等控制器实现水平自动扩缩容。但在生产环境中&#xff0c;仍有…

MySQL编程开发

变量系统变量&#xff1a;MySQL内置变量#查看所有系统变量show variables \G;#通过模糊查询筛选变量show variables like “%path%”;全局变量&#xff1a;在所有终端中都生效&#xff1b;会话变量&#xff1a;在当前会话&#xff08;本次登录&#xff09;&#xff1b;#可以通过…

20250830_Oracle 19c CDB+PDB(QMS)默认表空间、临时表空间、归档日志、闪回恢复区巡检手册

PDB 关业务,CDB 管底层;每天紧盯 PDB,必要时看 CDB。 一、CDB 与 PDB 的关系 Oracle 12c 以后引入 多租户架构(Multitenant),分成两类容器: 层级 名称 作用 存储内容 典型操作 CDB CDB$ROOT(容器数据库) 数据库实例的根容器 Oracle 元数据、系统表字典、公共用户、PDB…

什么是MIPS架构?RISC-V架构?有什么区别?【超详细初学者教程】

什么是MIPS架构&#xff1f;RISC-V架构&#xff1f;有什么区别&#xff1f;【超详细初学者教程】 关键词&#xff1a;MIPS架构&#xff0c;RISC-V架构&#xff0c;精简指令集RISC&#xff0c;嵌入式系统&#xff0c;CPU架构对比&#xff0c;指令集架构&#xff0c;开源处理器&…

IDEA Spring属性注解依赖注入的警告 Field injection is not recommended 异常解决方案

一、异常错误 在使用 IntelliJ IDEA 进行 Spring 开发时&#xff0c;当使用 Autowired 注解直接在字段上进行依赖注入时&#xff0c;IDE 会显示黄色警告&#xff1a; Field injection is not recommended这个警告出现在以下代码模式中&#xff1a; Service public class UserSe…

智能核心:机器人芯片的科技革新与未来挑战

在人工智能与机器人技术深度融合的今天&#xff0c;机器人芯片作为驱动智能机器的“大脑”&#xff0c;正成为科技竞争的战略制高点。这一微小却至关重要的硬件&#xff0c;决定了机器人的计算能力、响应速度与智能水平&#xff0c;是机器人从“自动化”迈向“自主化”的关键所…

经典扫雷游戏实现:从零构建HTML5扫雷游戏

一、引言 扫雷是一款经典的单人益智游戏&#xff0c;起源于20世纪60年代&#xff0c;并在90年代随着Windows操作系统的普及而风靡全球。本文将详细介绍如何使用现代网页技术&#xff08;HTML、CSS和JavaScript&#xff09;从零开始构建一个功能完整的扫雷游戏。我们将涵盖游戏逻…

ccache编译加速配置

ccache 介绍 ccache(“compiler cache”的缩写)是一个编译器缓存,该工具会高速缓存编译生成的信息,并在编译的特定部分使用高速缓存的信息, 比如头文件,这样就节省了通常使用 cpp 解析这些信息所需要的时间。 github :https://github.com/ccache/ccache home:https://c…

数据库主键选择策略分析

为什么不推荐使用数据库自增主键&#xff1f;分库分表问题&#xff1a;自增ID在分库分表场景下会导致ID冲突需要额外机制(如步长设置)来保证全局唯一&#xff0c;增加系统复杂度安全性问题&#xff1a;自增ID容易暴露业务量(如订单号连续)可能被恶意爬取数据分布式系统限制&…

线性代数理论——状态空间的相关概念以及由系统的输入输出导出状态空间描述

线性代数理论——状态空间 状态&#xff1a;动态系统的状态就是指系统的过去、现在、将来的运动状况&#xff0c;精确的说就是状态需要一组必要而充分的数据来表明。 状态变量&#xff1a;可以表达系统运动状态的变量都是状态变量。 状态变量组&#xff1a;可以完全表征系统在时…

【GaussDB】排查应用高可用切换出现数据库整体卡顿及报错自治事务无法创建的问题

【GaussDB】排查应用高可用切换出现数据库整体卡顿及报错自治事务无法创建的问题 背景 某客户在做应用程序的高可用切换测试&#xff0c;在应用程序中&#xff0c;收到了来自数据库的报错&#xff0c;不能创建自治事务 ERROR: autonomous transaction failed to create auton…

shell脚本第五阶段---shell函数与正则表达式

学习目标掌握case语句的基本语法结构掌握函数的定义以及调用掌握常用的正则表达式元字符含义一、case语句case语句为多选择语句。可以用case语句匹配一个值与一个模式&#xff0c;如果匹配成功&#xff0c;执行相匹配的命令。case var in 定义变量&#xff1b;var代表变量名…

164.在 Vue3 中使用 OpenLayers 加载 Esri 地图(多种形式)

适配&#xff1a;Vue 3 Vite TypeScript&#xff08;也兼容 JS&#xff09; 地图引擎&#xff1a;OpenLayers v10 目标&#xff1a;一次性学会 多种 Esri 底图加载方式、注记叠加、动态切换、令牌&#xff08;Token&#xff09;鉴权、常见坑位排查。一、效果预览二、为什么选…

深入了解Flink核心:Slot资源管理机制

TaskExecutor、Task 和 Slot 简单来说&#xff0c;它们的关系可以比作&#xff1a;TaskExecutor&#xff1a;一个工厂&#xff0c;拥有固定的生产资源。TaskSlot&#xff1a;工厂里的一个工位。每个工位都预先分配了一份独立的资源&#xff08;主要是内存&#xff09;。Task&am…

java web 练习demo。生成简单验证码前端是jsp

目录结构 demo\ ├── WEB-INF\ │ └── weblogic.xml # WebLogic服务器配置文件 ├── demo.iml # IntelliJ IDEA项目配置文件 ├── lib\ # Java EE核心依赖库 │ ├── javax.annotation.jar │ ├── javax.ejb.jar │ ├── javax.…

拥抱智能高效翻译 ——8 款视频翻译工具深度测评

前阵子帮知识博主做跨境视频翻译&#xff0c;踩了不少坑&#xff1a;把 “内卷” 直译成 “involution” 让海外观众困惑&#xff0c;多语种版本赶工 3 天只出 2 种&#xff0c;还得手动核对 “碳中和”“非遗” 这类特色词的译法&#xff1b;用传统工具译完&#xff0c;视频要…

[知识点记录]SQLite 数据库和MySQL 数据库有什么区别?

核心区别&#xff1a;一个“内嵌”&#xff0c;一个“独立”SQLite (你的个人笔记本)本质&#xff1a; 它是“无服务器”的&#xff0c;或者叫“内嵌式”数据库。它不需要一个独立的程序一直在后台运行。你的应用程序&#xff08;比如Strapi&#xff09;直接就能读写它的数据库…

【Spark Core】(二)RDD编程入门

目录1 程序入口&#xff1a;SparkContext对象2 RDD的创建2.1 本地创建2.2 读取文件创建3 RDD算子4 常用Transform算子4.1 map算子4.2 flatMap算子4.3 reduceBykey算子4.4 mapValues算子<实例> WordCount4.5 groupBy算子4.6 filter算子4.7 distinct算子4.8 union算子4.9 j…

java IDEA run/Debug异常:“jdk1.8injava.exe“ CreateProcess error=206, 文件名或扩展名太长

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#,Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开发…

Java 函数编程之【过滤器filter()合并】【predicate(断言)】与【谓词逻辑】

Java函数式编程之【过滤器filter合并】【predicate&#xff08;断言&#xff09;】与【谓词逻辑】一、合并多个过滤器filter &#xff08;Lambda版本&#xff09;二、合并多个过滤器filter &#xff08;谓词逻辑&#xff08;Predicate&#xff09;版本&#xff09;&#xff08;…