165. 比较版本号(Compare Version Numbers)

难度:中等 | 主题:字符串——逐段比较

题目

比较两个版本号 version1version2。版本号由点 . 分隔的修订号组成。从左到右逐个比较修订号,忽略前导零。

  • 如果 version1 > version2,返回 1

  • 如果 version1 < version2,返回 -1

  • 如果相等,返回 0

示例:

 
version1 = "1.01", version2 = "1.001" → 0(忽略前导零)
 
version1 = "1.0", version2 = "1.0.0" → 0(短版本补 0)
 
version1 = "1.0.1", version2 = "1" → 1
 

思路

先讲个故事:软件版本号的江湖规矩

你是个运维工程师,要比较两个软件版本号哪个更新。版本号像 1.2.3 这样用点分隔。

你发现两个坑:

  1. 前导零1.011.001 其实是一样的——int("01") == int("001") == 1

  2. 长度不等1.01.0.0 也是一样的——短的后面补 0

所以不能直接字符串比较,要逐段转成数字比较


引导式推导:从 split 到双指针

方法一:split 后逐段比较(推荐)

  1. split('.') 分割两个版本号

  2. 遍历到较长的版本号长度,逐段比较

  3. 短版本越界的段补 0

  4. int() 自动忽略前导零

方法二:双指针扫描(O(1) 空间)

不用 split,用两个指针逐个字符扫描,遇到 . 就取一段转整数比较。


graph LR

    subgraph 双指针逐段比较

        A["i 扫 version1<br/>j 扫 version2"] --> B["提取当前段<br/>转整数"]

        B --> C{"seg1 vs seg2?"}

        C -->|不等| D["返回 1 或 -1"]

        C -->|相等| E["继续下一段"]

    end


代码

 
def compareVersion(self, version1: str, version2: str) -> int:
 
    v1 = version1.split('.')
 
    v2 = version2.split('.')
 
    n1, n2 = len(v1), len(v2)
 
    for i in range(max(n1, n2)):
 
        seg1 = int(v1[i]) if i < n1 else 0
 
        seg2 = int(v2[i]) if i < n2 else 0
 
        if seg1 != seg2:
 
            return 1 if seg1 > seg2 else -1
 
    return 0
 

复杂度

指标解释
时间O(max(m,n))m、n 是两个版本号的段数
空间O(m+n)split 创建数组。双指针版可 O(1)

实战考量

频率分析

字符串处理中等题,约 15% 考察,重点是 int() 忽略前导零和短版本补 0。

延伸思考

Q:为什么用 int 而不是直接比较字符串?

A:int() 忽略前导零:int("001") = 1,而字符串比较 "001" < "01" 会出错。

Q:如果不用 split 怎么做?

A:双指针法,空间 O(1),是更优解。

Q:int 对大数会不会溢出?

A:Python 中 int 无上限,不会溢出。C++/Java 需要用 long 或手动处理。

Q:如果版本号包含字母(如 “1.0a”)?

A:需要扩展比较逻辑,数字部分和字母部分分别比较。实际场景如 semver 的 pre-release 标签。

易错点

  • 短版本不补 0 导致比较错误

  • 返回类型是 int 不是 bool

  • 双指针法中 i += 1 跳过 . 很关键,忘记会死循环


生活类比

版本号比较 → 逐段对齐

就像比较两本书的目录:第一章、第二章、第三章……

如果一本书只有两章,第三章视为”空”(= 0)。

如果章节编号有前导零(第 01 章 vs 第 001 章),转成数字再比。

对齐 + 类型转换,就是版本号比较的全部。


相关题目

题目关系
93复原IP地址字符串分割为多段
415字符串相加字符串处理基本功
58最后一个单词的长度简单字符串遍历

→ 返回题单:LeetCode学习路线图 > 二、字符串

速记卡(面试闪卡)

Q1:一句话讲清「165. 比较版本号(Compare Version Numbers)」到底是什么?

A:版本号按点分段、逐段转整数比较,忽略前导零、短版补零,O(max) 完成。

Q2:一、题目:点分版本谁更新 —— 怎么理解?

A:像比较两个软件版本号哪个新:1.01 和 1.001 一样(前导零忽略),1.0 和 1.0.0 一样(短补零)。返回 1/-1/0(Compare Version Numbers)。

Q3:二、思路:逐段对齐转数字 —— 怎么理解?

A:像比两本书目录:第一章比第一章,短的书第三章视为空(=0)。不能直接字符串比,要 split 后 int() 逐段比较(Segment comparison),int 自动吃前导零。

Q4:三、双指针:O(1) 空间版 —— 怎么理解?

A:像不撕书页、用两根手指同时指:i 扫 v1、j 扫 v2,遇点取一段转整数比,不用 split 省空间(Two-pointer)。忘记 i 跳过 ’.’ 会死循环。

Q5:四、复杂度与实战:中等题 —— 怎么理解?

A:时间 O(max(m,n))、空间 O(m+n)(双指针可 O(1))。字符串中等题约 15% 考察,重点是 int() 忽略前导零与短版补 0(Leading-zero handling)。

Q6:核心速记主线有哪些?

  • 思路:split(’.’) 逐段 int 比较,短段补 0

  • 关键:int() 忽略前导零,不能直接字符串比

  • 双指针:O(1) 空间,遇 ’.’ 取段

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

  • 易错:短版不补 0、返回 int 非 bool、忘记跳 ’.’

口诀

A:版本拆点逐段挑,

前导零先往外抛;

短版补零对齐扫,

双指针走稳又牢。

相关链接