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

文章目录

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实现方案

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

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;
    }
}

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

java 复制代码
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) - 只使用常数额外空间

测试用例

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

关键要点总结

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

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

相关推荐
GUIQU.32 分钟前
【QT】嵌入式开发:从零开始,让硬件“活”起来的魔法之旅
java·数据库·c++·qt
自信的小螺丝钉3 小时前
Leetcode 146. LRU 缓存 哈希表 + 双向链表
leetcode·缓存·散列表
机器学习之心4 小时前
多目标鲸鱼优化算法(NSWOA),含46种测试函数和9个评价指标,MATLAB实现
算法·matlab·多目标鲸鱼优化算法·46种测试函数·9个评价指标
max5006004 小时前
基于Meta Llama的二语习得学习者行为预测计算模型
人工智能·算法·机器学习·分类·数据挖掘·llama
callJJ5 小时前
从 0 开始理解 Spring 的核心思想 —— IoC 和 DI(2)
java·开发语言·后端·spring·ioc·di
wangjialelele5 小时前
Linux中的线程
java·linux·jvm·c++
谷咕咕5 小时前
windows下python3,LLaMA-Factory部署以及微调大模型,ollama运行对话,开放api,java,springboot项目调用
java·windows·语言模型·llama
没有bug.的程序员5 小时前
MVCC(多版本并发控制):InnoDB 高并发的核心技术
java·大数据·数据库·mysql·mvcc
在下村刘湘6 小时前
maven pom文件中<dependencyManagement><dependencies><dependency> 三者的区别
java·maven
王哥儿聊AI6 小时前
Lynx:新一代个性化视频生成模型,单图即可生成视频,重新定义身份一致性与视觉质量
人工智能·算法·安全·机器学习·音视频·软件工程