比较版本号 图解题解
这道题到底在问什么
- version1
- "1.01.3"
- version2
- "1.001"
- 输出
- 1
最优解:一步一步想明白
- 3版本号比较的魂就一句话:分段、转数字、逐段比。下面把两个版本号切成段排成一排,一段一段往右走着比给你看。
- 4v1 = "1.01.3"先把 version1 沿着每个 "." 剪开,得到 3 段修订号:"1"、"01"、"3"。注意这里还是字符串,"01" 带着前导 0。
- 5v2 = "1.001"version2 切出来只有 2 段:"1"、"001"。它比 v1 少一段——这个差异待会儿要靠「缺的段补 0」来处理。
- 6我们用一个指针 i 从 0 走到「两边最长段数」。每一段:v1 这段有就取值、没有按 0 算,v2 同理,然后比这两个数。下面排成一排逐段演示。
- 7缺段补 0,准备逐段比把两边对齐成 3 个比较位,每格左边是 v1 的段、右边是 v2 的段。第 2 位 v2 没有,标「缺」(按 0 算)。马上让指针 i 从第 0 位开始一格一格往右比。
- 8v1段='1' v2段='1'看第 0 位:v1 这段 "1" 转成整数是 1,v2 这段 "1" 也是 1。把两个字符串都先变成数字,再比大小。
- 9平局,看下一位1 == 1,第 0 位打平,染绿表示已比过且相等。还没分出大小,指针 i 往右挪到第 1 位继续。
- 10来到比较位 1指针走到第 1 位。这里 v1 是 "01"、v2 是 "001",字符串明显不同。但别急着判不等——版本号要忽略前导 0,得先转成数字。
- 1101→1, 001→1关键一步:转整数时,"01" 和 "001" 开头的 0 全被丢掉,都变成 1。格子里也同步刷新成 "1 | 1"。这就是「忽略前导 0」。
- 12又平局,继续转成数字后 1 == 1,第 1 位也打平、染绿。可见若按字符串比就会冤判,按数值比才对。指针挪到最后一位第 2 位。
- 13v2 这段缺失走到第 2 位。v1 有 "3",但 v2 总共才 2 段、到这一位已经没有段了。前面说过——缺的段当 0。
- 14v2: 缺 → 0把 v2 缺的这段补成 0,格子刷新成 "3 | 0"。现在两边都有数可比了:v1 是 3,v2 是 0。
- 15v1 更大3 > 0!终于分出胜负:v1 在这一位更大,说明 v1 整体更新,立刻返回 1。前两位都平、第三位 v1 胜出。
- 16返回 1 ✓整道题的节奏:从左到右一段一段比,相等就看下一段,一不等立刻定输赢;比到头都相等才返回 0。这就是版本号比较。
- 17i=0换个相等的例子:"1.0" 和 "1.0.0"。v2 多一段,所以共 3 个比较位,v1 第 2 位要补 0。先从第 0 位开始比。
- 18相等第 0 位 1 == 1,打平,继续看下一位。
- 19相等第 1 位都是 0,0 == 0 平局,再往后。
- 20v1 缺 → 0第 2 位 v1 缺,补 0;v2 是 "0" 也是 0。格子刷新成 "0 | 0",两边相等。
- 21完全相等三个位全打平,没有任何一位分出胜负,补 0 让多出来的 ".0" 不影响结果。所以 "1.0" 和 "1.0.0" 相等,返回 0。
- 22对齐 2 个比较位最后看一个 v1 更小的例子:"0.1" 和 "1.1"。两边都 2 段,排成 2 个比较位,准备从第 0 位开始。
- 23i=0指针落在第 0 位。v1 这段 "0" 是 0,v2 这段 "1" 是 1。先把两段都转成数字。
- 24v1 更小第 0 位就 0 < 1,v1 更小,立刻返回 -1,后面的段根本不用看(灰掉)——高位一旦分出大小,低位再大也翻不了盘。
⚠️ 容易写错的地方
✗ 错:直接按字符串比 version1 < version2
✓ 对:切段后每段转整数再比
字符串比会把 "2" 判成大于 "10"('2'>'1'),也会把 "01" 当成不等于 "1"
✗ 错:Java 用 version1.split(".")
✓ 对:split("\\.") 转义点号
split 参数是正则,"." 匹配任意字符会切出空数组,必须写 "\\."
✗ 错:段数不同时漏处理缺段
✓ 对:缺的段一律按 0 参与比较
"1.0" 与 "1.0.0" 应相等,不补 0 会误判;只比 min(len) 段也会漏掉 "1.0.1">"1.0"
完整代码(Python / C++ / Java)
Python
class Solution:
def compareVersion(self, version1, version2):
a = version1.split(".") # 按 . 切段
b = version2.split(".")
for i in range(max(len(a), len(b))):
x = int(a[i]) if i < len(a) else 0 # 缺段补0,int去前导0
y = int(b[i]) if i < len(b) else 0
if x != y: # 一不等立刻定胜负
return 1 if x > y else -1
return 0 # 比到头全平C++
class Solution {
public:
int compareVersion(string version1, string version2) {
int i = 0, j = 0, n = version1.size(), m = version2.size();
while (i < n || j < m) {
long x = 0, y = 0; // long 防溢出
while (i < n && version1[i] != '.') x = x * 10 + (version1[i++] - '0');
while (j < m && version2[j] != '.') y = y * 10 + (version2[j++] - '0');
if (x != y) return x > y ? 1 : -1;
i++; j++; // 跳过 '.'
}
return 0;
}
};Java
class Solution {
public int compareVersion(String version1, String version2) {
String[] a = version1.split("\\."); // 正则,点要转义
String[] b = version2.split("\\.");
int n = Math.max(a.length, b.length);
for (int i = 0; i < n; i++) {
int x = i < a.length ? Integer.parseInt(a[i]) : 0; // 缺段补0
int y = i < b.length ? Integer.parseInt(b[i]) : 0;
if (x != y) return x > y ? 1 : -1;
}
return 0;
}
}复杂度
时间复杂度
O(n+m)
n、m 为两个版本号长度。切段 + 逐字符转数值各扫一遍,线性
空间复杂度
O(n+m)
split 出来的段数组占用与长度成正比;C++ 边扫边算可做到 O(1)
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 比较版本号 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么不能直接按字符串字典序比?+
字典序逐字符比 ASCII:"2" vs "10" 会因 '2'>'1' 判成 2 更大;"01" vs "1" 会判不等。版本号每段是数值,必须转整数比。
段数不同怎么办?为什么补 0 而不是判更长的大?+
缺的段按 0 算,使 "1.0" 与 "1.0.0" 相等。语义上尾部的 ".0" 不代表更新版本;真有差异(如 "1.0.1")补 0 后也能正确比出。
若修订号极大可能溢出怎么办?+
Java/Python 用 int/大整数通常够;C++ 用 long 累加,或边扫边比避免攒出超大数。本质是比数值,注意类型范围即可。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 比较版本号 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。