版本号比较
题目要求
在某个项目中,每个版本都用版本号标记,由一个或多个修订号组成,修订号之间由点号.分隔。每个修订号可能有多位数字,并且可能会包含前导零。你需要根据两个版本号 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
算法思路
-
去除点号:
- 创建了两个空字符串
s1和s2。 - 通过遍历
version1和version2,将所有非点号(.)的字符添加到s1和s2中。这一步的目的是将版本号中的点号去掉,以便将剩余的数字字符串转换为整数进行比较。
- 创建了两个空字符串
-
长度调整:
- 检查
s1和s2的长度,如果它们不相等,您通过在较短的字符串后面添加零('0')来使它们长度相等。这一步是为了处理版本号长度不一致的情况,确保两个版本号在比较时有相同数量的修订号。
- 检查
-
转换为整数:
- 使用
std::stoi将s1和s2转换为整数num1和num2。这一步是将字符串形式的版本号转换为数值形式,以便进行数值比较。
- 使用
-
比较整数:
- 比较
num1和num2的值,如果num1大于num2,则返回1;如果num1小于num2,则返回-1;如果两者相等,则返回0。
- 比较
时间复杂度分析
- 去除点号:两个
for循环分别遍历version1和version2字符串,将非点号字符添加到s1和s2字符串中。每个循环的时间复杂度是O(n),其中n是对应版本号字符串的长度。因此,这部分的时间复杂度是O(n + m),其中n是version1的长度,m是version2的长度。 - 补零:如果
s1和s2的长度不同,代码会通过添加零来使它们长度相等。这部分的时间复杂度是O(k),其中k是s1和s2长度之差的绝对值。在最坏的情况下,k可以等于版本号的最大长度,因此这部分的时间复杂度可以认为是O(n),其中n是两个版本号中较长的那个的长度。 - 转换为整数并比较:使用
std::stoi函数将字符串转换为整数并进行比较。std::stoi函数的时间复杂度是O(p),其中p是字符串的长度。由于我们已经确保了s1和s2的长度相等,这部分的时间复杂度是O(p),其中p是s1或s2的长度。
综合以上各部分,整体时间复杂度是O(n + m + p),其中n是version1的长度,m是version2的长度,p是处理后s1或s2的最大长度。在最坏的情况下,如果两个版本号都非常长,时间复杂度将接近O(n + m + p)。
代码
#include "iostream"
#include <string>
int solution(std::string version1, std::string version2) {
// Edit your code here
std::string s1, s2;
for (int i = 0; i < version1.length(); i++) {
if (version1[i] != '.')
s1 += version1[i];
}
for (int i = 0; i < version2.length(); i++) {
if (version2[i] != '.')
s2 += version2[i];
}
//std::cout << s1 << " " << s2 << std::endl;
int a;
if (s1.length() > s2.length()) {
a = s1.length() - s2.length();
for (int i = 0; i < a; i++)
s2 += '0';
}
if (s1.length() < s2.length()) {
a = s2.length() - s1.length();
for (int i = 0; i < a; i++)
s1 += '0';
}
int num1 = std::stoi(s1);
int num2 = std::stoi(s2);
//std::cout << num1 << " " << num2 << std::endl;
if (num1 > num2)
return 1;
else if (num1 < num2)
return -1;
else
return 0;
return -1;
}
优化
- 代码问题:将整个版本号转换为一个整数可能会非常低效,特别是当版本号很长时。此外,这种方法不能很好地处理不同长度的版本号,因为它假设所有修订号都是同等重要的,而实际上,版本号的比较是从左到右进行的,每个修订号都可能有不同的权重。
- 优化:在拆分版本号时转换为整数,避免了不必要的字符串拼接和后续的字符串到整数的转换。逐个比较版本号的每个部分,而不是将整个版本号转换为一个整数。这样可以避免处理非常大的整数,并且在找到第一个不同的修订号时立即返回结果,而不是等待整个字符串转换完成。
优化后的代码
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
int solution(std::string version1, std::string version2) {
// 拆分版本号
std::istringstream iss1(version1);
std::istringstream iss2(version2);
std::vector<int> nums1, nums2;
std::string token;
while (std::getline(iss1, token, '.')) {
nums1.push_back(std::stoi(token));
}
while (std::getline(iss2, token, '.')) {
nums2.push_back(std::stoi(token));
}
// 逐个比较修订号
int len = std::max(nums1.size(), nums2.size());
for (int i = 0; i < len; ++i) {
int num1 = i < nums1.size() ? nums1[i] : 0;
int num2 = i < nums2.size() ? nums2[i] : 0;
if (num1 > num2) {
return 1;
} else if (num1 < num2) {
return -1;
}
}
// 如果所有修订号都相等,返回0
return 0;
}
优化后的时间复杂度
- 拆分版本号:使用
std::getline和std::stoi来拆分版本号字符串为整数数组。这个过程的时间复杂度是O(n),其中n是版本号中字符的数量。这是因为我们需要遍历整个字符串来拆分修订号,并且对于每个修订号,我们需要将其转换为整数。 - 逐个比较修订号:我们比较两个版本号的修订号,这个过程的时间复杂度是O(m),其中m是两个版本号中较长的修订号数组的长度。这是因为我们需要遍历较长的数组来比较每个修订号。
因此,总的时间复杂度是O(n + m),其中n是version1中字符的数量,m是version2中字符的数量。在最坏的情况下,如果两个版本号都非常长,时间复杂度将接近O(n + m)。