一、题目要求
给你两个版本号字符串:
version1
version2
例如:
version1 = "1.2"
version2 = "1.10"
版本号由 . 分隔成多个"修订号"。
例如:
"1.2"
→ [1, 2]
"1.10"
→ [1, 10]
比较时,要从左到右逐段比较。
如果某一段更大,就能直接判断哪个版本更大。
二、为什么不能直接比较字符串?
比如:
"1.2" > "1.10"
不能用这种方式直接判断版本号大小。
因为字符串比较是按字符比较,不是按数值比较。
我们真正想比较的是:
1 和 1
2 和 10
所以应该先拆分:
"1.2".split(".")
得到:
["1", "2"]
而:
"1.10".split(".")
得到:
["1", "10"]
然后逐段转成数字比较。
三、完整 JavaScript 代码
javascript
var compareVersion = function(version1, version2) {
const v1 = version1.split(".")
const v2 = version2.split(".")
const len = Math.max(v1.length, v2.length)
for (let i = 0; i < len; i++) {
const n1 = Number(v1[i] || 0)
const n2 = Number(v2[i] || 0)
if (n1 > n2) return 1
if (n1 < n2) return -1
}
return 0
}
四、第一步:split 拆版本号
代码:
const v1 = version1.split(".")
const v2 = version2.split(".")
例如:
version1 = "1.2.3"
执行:
version1.split(".")
得到:
["1", "2", "3"]
所以 split(".") 的作用就是:
按照
.把字符串拆成数组。
五、为什么要取最大长度?
代码:
const len = Math.max(v1.length, v2.length)
因为两个版本号的段数可能不同。
比如:
version1 = "1.0"
version2 = "1.0.0.0"
拆开后:
v1 = ["1", "0"]
v2 = ["1", "0", "0", "0"]
如果只遍历较短数组,就比较不完整。
所以要取:
Math.max(v1.length, v2.length)
也就是:
两个数组中更长的那个长度。
六、缺失的版本号为什么当 0?
题目规定:
如果某个版本号缺少某一段,就把它看成 0。
比如:
1.0
1.0.0
实际上应该看成:
1.0.0
1.0.0
所以这两个版本相等。
代码里用了:
v1[i] || 0
意思是:
如果:
v1[i]
不存在,就使用:
0
例如:
const v1 = ["1", "0"]
当:
i = 2
时:
v1[2]
// undefined
于是:
v1[2] || 0
结果就是:
0
七、为什么要用 Number()?
代码:
const n1 = Number(v1[i] || 0)
const n2 = Number(v2[i] || 0)
因为 split() 得到的还是字符串。
例如:
"1.10".split(".")
得到:
["1", "10"]
其中:
"10"
还是字符串。
所以我们要:
Number("10")
得到:
10
这样才能进行真正的数值比较。
八、前导 0 怎么处理?
例如:
version1 = "1.01"
version2 = "1.001"
题目要求忽略前导 0。
所以:
01
001
都应该看成:
1
这也是为什么用:
Number()
很方便。
例如:
Number("01")
// 1
Number("001")
// 1
所以前导 0 会自动被去掉。
九、逐段比较
核心代码:
if (n1 > n2) return 1
if (n1 < n2) return -1
意思是:
如果当前这一段已经能分出大小,就直接返回。
比如:
version1 = "1.2"
version2 = "1.10"
第一轮:
1 和 1
相等,继续。
第二轮:
2 和 10
因为:
2 < 10
所以:
return -1
后面不需要再比较了。
十、为什么最后 return 0?
如果整个循环都没有返回:
1
或者:
-1
说明所有对应版本号都相等。
例如:
version1 = "1.0"
version2 = "1.0.0"
比较过程:
1 == 1
0 == 0
0 == 0
所以最终:
return 0
表示:
两个版本号相同。
十一、完整执行示例
例如:
version1 = "1.2"
version2 = "1.10"
拆分:
v1 = ["1", "2"]
v2 = ["1", "10"]
最大长度:
len = 2
第一轮:
n1 = 1
n2 = 1
相等,继续。
第二轮:
n1 = 2
n2 = 10
因为:
2 < 10
所以:
return -1
十二、再看长度不同的情况
version1 = "1.0"
version2 = "1.0.0"
拆分:
v1 = ["1", "0"]
v2 = ["1", "0", "0"]
第三轮时:
v1[2]
// undefined
所以:
Number(v1[2] || 0)
// 0
而:
Number(v2[2] || 0)
// 0
两边还是一样。
最终:
return 0
十三、这道题的核心思路
这道题其实可以压缩成四步:
1. 用 split(".") 拆版本号
2. 遍历两个数组的最大长度
3. 每一段用 Number() 转成数字
4. 从左到右逐段比较
只要某一段出现:
n1 > n2
就返回:
1
如果:
n1 < n2
就返回:
-1
全部一样:
0
十四、这道题主要考什么?
主要考三个点。
1. 字符串处理
split(".")
把版本号拆开。
2. 边界处理
版本长度不一样时:
v1[i] || 0
缺失部分按 0 处理。
3. 类型转换
Number()
把字符串版本号转换成数字,并自动处理前导 0。
总结
最终代码:
var compareVersion = function(version1, version2) {
const v1 = version1.split(".")
const v2 = version2.split(".")
const len = Math.max(v1.length, v2.length)
for (let i = 0; i < len; i++) {
const n1 = Number(v1[i] || 0)
const n2 = Number(v2[i] || 0)
if (n1 > n2) return 1
if (n1 < n2) return -1
}
return 0
}
总结:
先 split 拆版本号,再从左到右逐段转成数字比较;缺失部分补 0,前导 0 用 Number 自动处理。