LeetCode-165:比较版本号,按段拆分 + 补零对齐就够了

本题在线练习LeetCode 165. 比较版本号 — 在线练习(免费 · 无需登录 · AI 辅助)

配套刷题网站 Zero2Leetcode —— 内置本地 OJ + AI 教练,零门槛开刷 Hot 100。

题目概述

给你两个版本号字符串 version1version2,按照 . 分隔,每一段叫做一个"修订号"。

比较规则:

  • 每一段按数值比较(忽略前导零),比如 "01""1" 是相等的
  • 如果某个版本号段数较少,缺失的段视为 0,比如 "1.0""1.0.0" 是相等的
  • 返回 -101

例如:

  • "1.01" vs "1.001"0(两个版本号相等)
  • "1.0" vs "1.0.0"0(缺失的段视为 0)
  • "0.1" vs "1.1"-1(version1 < version2)

核心思路:拆分后逐段比较整数

这道题没有复杂算法,关键是把细节处理对:

  1. "." 分割版本号字符串,得到两个段列表
  2. 把每一段转成 int(自动去除前导零)
  3. 逐段比较,短的那个用 0 补齐
  4. 第一个不相等的段决定结果

两种实现方式:

  • split + zip_longest:先拆分成列表,用 zip_longest 对齐后逐段比
  • 双指针:不用 split,直接在字符串上解析每一段数字,省去额外空间

代码

解法一:split + zip_longest(推荐,简洁易懂)

from itertools import zip_longest


class Solution:
    def compareVersion(self, version1: str, version2: str) -> int:
        v1 = version1.split(".")
        v2 = version2.split(".")

        for s1, s2 in zip_longest(v1, v2, fillvalue="0"):
            n1, n2 = int(s1), int(s2)
            if n1 < n2:
                return -1
            if n1 > n2:
                return 1

        return 0

解法二:双指针(不用 split,O(1) 额外空间)

class Solution:
    def compareVersion(self, version1: str, version2: str) -> int:
        i, j = 0, 0
        n1, n2 = len(version1), len(version2)

        while i < n1 or j < n2:
            # 解析 version1 当前段
            num1 = 0
            while i < n1 and version1[i] != ".":
                num1 = num1 * 10 + int(version1[i])
                i += 1
            i += 1  # 跳过 '.'

            # 解析 version2 当前段
            num2 = 0
            while j < n2 and version2[j] != ".":
                num2 = num2 * 10 + int(version2[j])
                j += 1
            j += 1  # 跳过 '.'

            if num1 < num2:
                return -1
            if num1 > num2:
                return 1

        return 0

逐行拆解

解法一:split + zip_longest

  • v1 = version1.split(".")
    • "." 分割。例如 "1.01.0" 变成 ["1", "01", "0"]
  • for s1, s2 in zip_longest(v1, v2, fillvalue="0")
    • zip_longest 的作用:当两个列表长度不同时,短的那个用 "0" 补齐
    • 比如 v1 = ["1", "0"], v2 = ["1", "0", "0"],zip_longest 会生成 ("1","1"), ("0","0"), ("0","0")
  • n1, n2 = int(s1), int(s2)
    • 转成整数,int("01") 就是 1,自动忽略前导零
  • if n1 < n2: return -1 / if n1 > n2: return 1
    • 第一个不相等的段直接决定结果
  • return 0
    • 所有段都相等,两个版本号一样

解法二:双指针

  • i, j 分别是两个字符串的当前扫描位置
  • 内层 while 循环逐字符读取数字:num1 = num1 * 10 + int(version1[i])
    • 这就是手动把字符串转整数的标准写法,天然处理前导零
  • i += 1 跳过 "."
    • 如果 i 已经越界也没关系,下一轮外层 while 检查时会用 num1 = 0
  • 当一个版本号已经扫描完(i >= n1),对应的 num 保持为初始值 0,等价于用 0 补齐

手动模拟

示例 1:"1.01" vs "1.001"

split 后:v1 = ["1", "01"], v2 = ["1", "001"]

s1 s2 int(s1) int(s2) 比较结果
0 "1" "1" 1 1 相等,继续
1 "01" "001" 1 1 相等,继续

所有段相等,返回 0

示例 2:"1.0" vs "1.0.0"

split 后:v1 = ["1", "0"], v2 = ["1", "0", "0"]

zip_longest 补齐后:

s1 s2 int(s1) int(s2) 比较结果
0 "1" "1" 1 1 相等,继续
1 "0" "0" 0 0 相等,继续
2 "0"(补) "0" 0 0 相等,继续

返回 0

示例 3:"0.1" vs "1.1"

split 后:v1 = ["0", "1"], v2 = ["1", "1"]

s1 s2 int(s1) int(s2) 比较结果
0 "0" "1" 0 1 0 < 1,返回 -1

第一段就分出胜负,返回 -1

边界情况:"1.0.0.0.0" vs "1"

split 后:v1 = ["1", "0", "0", "0", "0"], v2 = ["1"]

zip_longest 补齐后,第 0 段相等(1 vs 1),后面所有段都是 0 vs 0,返回 0


复杂度分析

version1 长度为 mversion2 长度为 n

解法一(split + zip_longest):

  • 时间复杂度:O(m + n) -- split 和遍历各一次
  • 空间复杂度:O(m + n) -- 存储分割后的列表

解法二(双指针):

  • 时间复杂度:O(m + n) -- 每个字符只扫描一次
  • 空间复杂度:O(1) -- 只用了几个指针和临时变量

总结

这道题考的不是算法,而是字符串处理的细节功夫

. 拆分,转整数去前导零,短的补零对齐,逐段比较。

三个容易踩的坑:

  1. 前导零"01""1" 要相等 -- 转 int 自动解决
  2. 长度不同"1.0""1.0.0" 要相等 -- zip_longest"0" 或双指针默认 0
  3. 尾部零"1.0.0.0""1" 要相等 -- 同上

面试中推荐解法一,代码短、思路清晰、不容易写错。如果面试官要求 O(1) 空间,再切换到解法二的双指针写法。

posted @ 2026-04-20 00:21  孤飞  阅读(63)  评论(0)    收藏  举报