文章目录
- [LeetCode 165. 比较版本号 - 优雅Java解决方案](#LeetCode 165. 比较版本号 - 优雅Java解决方案)
-
- 题目描述
- 示例分析
-
- [示例 1](#示例 1)
- [示例 2](#示例 2)
- [示例 3](#示例 3)
- 算法思路
- Java实现方案
- 可视化执行过程
-
- [示例:compareVersion("1.2", "1.10")](#示例:compareVersion("1.2", "1.10"))
- [示例:compareVersion("1.01", "1.001")](#示例:compareVersion("1.01", "1.001"))
- [示例:compareVersion("1.0", "1.0.0.0")](#示例:compareVersion("1.0", "1.0.0.0"))
- 算法复杂度分析
-
- [时间复杂度:O(max(m, n))](#时间复杂度:O(max(m, n)))
- 空间复杂度:
- 测试用例
- 关键要点总结
LeetCode 165. 比较版本号 - 优雅Java解决方案
题目描述
给你两个 版本号字符串 version1
和 version2
,请你比较它们。版本号由被点 '.' 分开的修订号组成。修订号的值是它转换为整数并忽略前导零。
比较版本号时,请按从左到右的顺序依次比较它们的修订号。如果其中一个版本字符串的修订号较少,则将缺失的修订号视为 0。
返回规则:
- 如果
version1 < version2
返回 -1 - 如果
version1 > version2
返回 1 - 除此之外返回 0
示例分析
示例 1
输入:version1 = "1.2", version2 = "1.10"
输出:-1
解释:version1 的第二个修订号为 "2",version2 的第二个修订号为 "10":2 < 10,所以 version1 < version2
示例 2
输入:version1 = "1.01", version2 = "1.001"
输出:0
解释:忽略前导零,"01" 和 "001" 都代表相同的整数 "1"
示例 3
输入:version1 = "1.0", version2 = "1.0.0.0"
输出:0
解释:version1 有更少的修订号,每个缺失的修订号按 "0" 处理
算法思路
- 分割版本号:使用点号分割版本号字符串
- 双指针遍历:使用两个指针分别遍历两个版本号的修订号数组
- 逐个比较:从左到右比较对应位置的修订号
- 处理边界:当某个版本号的修订号用完时,将其视为0
- 返回结果:根据比较结果返回相应值
Java实现方案
方案一:双指针法(推荐)
java
public class Solution {
public int compareVersion(String version1, String version2) {
String[] v1 = version1.split("\\.");
String[] v2 = version2.split("\\.");
int maxLength = Math.max(v1.length, v2.length);
for (int i = 0; i < maxLength; i++) {
int num1 = i < v1.length ? Integer.parseInt(v1[i]) : 0;
int num2 = i < v2.length ? Integer.parseInt(v2[i]) : 0;
if (num1 < num2) {
return -1;
} else if (num1 > num2) {
return 1;
}
}
return 0;
}
}
方案二:优化的单次遍历法
java
public class Solution {
public int compareVersion(String version1, String version2) {
int i = 0, j = 0;
int n1 = version1.length(), n2 = version2.length();
while (i < n1 || j < n2) {
int num1 = 0, num2 = 0;
// 解析version1的当前修订号
while (i < n1 && version1.charAt(i) != '.') {
num1 = num1 * 10 + (version1.charAt(i) - '0');
i++;
}
i++; // 跳过点号
// 解析version2的当前修订号
while (j < n2 && version2.charAt(j) != '.') {
num2 = num2 * 10 + (version2.charAt(j) - '0');
j++;
}
j++; // 跳过点号
if (num1 < num2) {
return -1;
} else if (num1 > num2) {
return 1;
}
}
return 0;
}
}
可视化执行过程
让我们通过示例来可视化算法的执行过程:
示例:compareVersion("1.2", "1.10")
初始状态:
version1 = "1.2" → ["1", "2"]
version2 = "1.10" → ["1", "10"]
第1轮比较:
位置 i=0: num1=1, num2=1
1 == 1 → 继续
第2轮比较:
位置 i=1: num1=2, num2=10
2 < 10 → 返回 -1
结果: -1 (version1 < version2)
示例:compareVersion("1.01", "1.001")
初始状态:
version1 = "1.01" → ["1", "01"] → [1, 1]
version2 = "1.001" → ["1", "001"] → [1, 1]
第1轮比较:
位置 i=0: num1=1, num2=1
1 == 1 → 继续
第2轮比较:
位置 i=1: num1=1, num2=1 (忽略前导零)
1 == 1 → 继续
所有修订号都相等
结果: 0 (version1 == version2)
示例:compareVersion("1.0", "1.0.0.0")
初始状态:
version1 = "1.0" → ["1", "0"]
version2 = "1.0.0.0" → ["1", "0", "0", "0"]
第1轮比较:
位置 i=0: num1=1, num2=1
1 == 1 → 继续
第2轮比较:
位置 i=1: num1=0, num2=0
0 == 0 → 继续
第3轮比较:
位置 i=2: num1=0(缺失视为0), num2=0
0 == 0 → 继续
第4轮比较:
位置 i=3: num1=0(缺失视为0), num2=0
0 == 0 → 继续
所有修订号都相等
结果: 0 (version1 == version2)
算法复杂度分析
时间复杂度:O(max(m, n))
- m 和 n 分别是两个版本号的修订号个数
- 需要遍历较长版本号的所有修订号
空间复杂度:
- 方案一:O(m + n) - 需要存储分割后的数组
- 方案二:O(1) - 只使用常数额外空间
测试用例
java
public class TestCompareVersion {
public static void main(String[] args) {
Solution solution = new Solution();
// 测试用例1
System.out.println(solution.compareVersion("1.2", "1.10")); // -1
// 测试用例2
System.out.println(solution.compareVersion("1.01", "1.001")); // 0
// 测试用例3
System.out.println(solution.compareVersion("1.0", "1.0.0.0")); // 0
// 边界测试
System.out.println(solution.compareVersion("0.1", "1.1")); // -1
System.out.println(solution.compareVersion("1.0.1", "1")); // 1
System.out.println(solution.compareVersion("7.5.2.4", "7.5.3")); // -1
}
}
关键要点总结
- 忽略前导零 :使用
Integer.parseInt()
自动处理 - 处理不同长度:缺失的修订号视为0
- 效率优化:方案二避免了字符串分割的开销
- 边界处理:正确处理版本号末尾的点号和空修订号
这个解决方案具有良好的可读性和效率,能够正确处理所有边界情况。