LeetCode-165:比较版本号,按段拆分 + 补零对齐就够了
本题在线练习:LeetCode 165. 比较版本号 — 在线练习(免费 · 无需登录 · AI 辅助)
配套刷题网站 Zero2Leetcode —— 内置本地 OJ + AI 教练,零门槛开刷 Hot 100。
题目概述
给你两个版本号字符串 version1 和 version2,按照 . 分隔,每一段叫做一个"修订号"。
比较规则:
- 每一段按数值比较(忽略前导零),比如
"01"和"1"是相等的 - 如果某个版本号段数较少,缺失的段视为
0,比如"1.0"和"1.0.0"是相等的 - 返回
-1、0或1
例如:
"1.01"vs"1.001"→0(两个版本号相等)"1.0"vs"1.0.0"→0(缺失的段视为 0)"0.1"vs"1.1"→-1(version1 < version2)
核心思路:拆分后逐段比较整数
这道题没有复杂算法,关键是把细节处理对:
- 用
"."分割版本号字符串,得到两个段列表 - 把每一段转成
int(自动去除前导零) - 逐段比较,短的那个用
0补齐 - 第一个不相等的段决定结果
两种实现方式:
- 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 长度为 m,version2 长度为 n。
解法一(split + zip_longest):
- 时间复杂度:
O(m + n)-- split 和遍历各一次 - 空间复杂度:
O(m + n)-- 存储分割后的列表
解法二(双指针):
- 时间复杂度:
O(m + n)-- 每个字符只扫描一次 - 空间复杂度:
O(1)-- 只用了几个指针和临时变量
总结
这道题考的不是算法,而是字符串处理的细节功夫:
按
.拆分,转整数去前导零,短的补零对齐,逐段比较。
三个容易踩的坑:
- 前导零:
"01"和"1"要相等 -- 转int自动解决 - 长度不同:
"1.0"和"1.0.0"要相等 --zip_longest补"0"或双指针默认 0 - 尾部零:
"1.0.0.0"和"1"要相等 -- 同上
面试中推荐解法一,代码短、思路清晰、不容易写错。如果面试官要求 O(1) 空间,再切换到解法二的双指针写法。

浙公网安备 33010602011771号