问题描述
在某个项目中,每个版本都用版本号标记,由一个或多个修订号组成,修订号之间由点号 . 分隔。每个修订号可能有多位数字,并且可能会包含前导零。你需要根据两个版本号 version1 和 version2,判断哪个版本更新,或者它们是否相同。
例如,2.5.33 和 0.1 都是有效的版本号。
当比较两个版本时,从左到右依次比较它们的修订号。忽略每个修订号的前导零,直接比较修订号对应的整数值。如果其中一个版本没有足够的修订号,缺失部分默认补为 0。
你需要根据以下规则返回比较结果:
- 如果
version1 > version2,返回1。 - 如果
version1 < version2,返回-1。 - 如果两个版本相等,返回
0。
测试样例
样例 1
输入:
version1 = "0.1", version2 = "1.1"
输出:-1
样例 2
输入:
version1 = "1.0.1", version2 = "1"
输出:1
样例 3
输入:
version1 = "7.5.2.4", version2 = "7.5.3"
输出:-1
样例 4
输入:
version1 = "1.0", version2 = "1.0.0"
输出:0
解题思路分析
可以将两个版本号按点号(.)分隔,逐个比较各个修订号。具体步骤如下:
- 先将两个版本号分别用
split('.')方法分割成修订号列表。 - 比较两个列表的长度,确保长度一致。在较短的列表末尾补
0。 - 按照顺序逐个比较修订号,将字符串转换为整数后进行比较。
- 若发现某个位置的修订号不同,直接返回
1或-1。 - 若所有修订号相同,返回
0。
关键问题分析
这道题大概有以下几个关键问题:
1. 修订号长度不一致时如何处理?
比如 1.0 和 1.0.0 实际是等价的,需要在短的列表末尾补零。可以通过计算两个版本号列表的最大长度,使用列表扩展补全较短的那个版本号。
2. 如何比较修订号?
修订号需要按数值进行比较,而不是按字符串的字典序比较。例如,"001" 和 "1" 是相等的,比较时应转化为整数。
3. 优化比较逻辑
一旦某个修订号不相等,结果就可以立即返回,减少不必要的后续比较。
代码实现
def solution(version1, version2):
# 将版本号按点号分割成修订号列表
v1_parts = version1.split('.')
v2_parts = version2.split('.')
# 获取较长的长度
max_len = max(len(v1_parts), len(v2_parts))
# 补齐较短的版本号为相同长度
v1_parts += ['0'] * (max_len - len(v1_parts))
v2_parts += ['0'] * (max_len - len(v2_parts))
# 逐个比较修订号
for i in range(max_len):
# 转换为整数进行比较
v1_num = int(v1_parts[i])
v2_num = int(v2_parts[i])
if v1_num > v2_num:
return 1
elif v1_num < v2_num:
return -1
# 如果所有修订号相等
return 0
知识点总结
这道题大概包含以下几个知识点:
1. 字符串处理
使用 split 方法分割字符串、通过字符串列表扩展补零(+= ['0'])来简化对齐操作。
2. 列表操作
列表的长度不一致时,需要补零操作,涉及到列表扩展。
3. 提前返回
在遍历过程中,只要某个修订号的大小关系明确,就可以立即返回结果,而不需要继续比较。通过提前结束的逻辑提升效率。
思考与优化
1. 时间复杂度分析
这段代码的时间复杂度为 ,其中 是版本号中修订号的个数。因为只遍历了所有修订号一次。该复杂度可以接受。
2. 对边界条件的处理
比如:
- 当版本号有很多前导零时,是否能够正确忽略?
- 当两个版本号的修订号个数相差很多时,是否能正确补零?
- 空字符串或者不符合格式的输入是否需要处理?
这段代码假设输入总是合法的。如果需要考虑非法输入,可以在开头增加输入验证,比如检查是否只有数字和点号。
3. 通用性扩展
更复杂的版本号比较,比如含字母的修订号(如 1.0.0-alpha),那么可以增加对字母部分的特殊规则处理。