问题描述
给你两个版本号 version1
和 version2
,请你比较它们。
版本号由一个或多个修订号组成,各修订号由一个 .
连接。每个修订号由多位数字组成,可能包含前导零。每个版本号至少包含一个字符。修订号从左到右编号,下标从 0 开始,最左边的修订号下标为 0,下一个修订号下标为 1,以此类推。例如,2.5.33
和 0.1
都是有效的版本号。
比较版本号时,请按从左到右的顺序依次比较它们的修订号。比较修订号时,只需比较忽略任何前导零后的整数值。也就是说,修订号 1
和修订号 001
相等。如果版本号没有指定某个下标处的修订号,则该修订号视为 0。例如,版本 1.0
小于版本 1.1
,因为它们下标为 0 的修订号相同,而下标为 1 的修订号分别为 0
和 1
,0 < 1
。
返回规则如下:
- 如果
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
解释:version1 没有第三级修订号,这意味着它的第三级修订号默认为 0
。
题目分析
给定两个版本号,版本号由多个修订号组成,每个修订号通过 .
连接。每个修订号是一个数字,可以包含前导零。我们需要按从左到右的顺序依次比较修订号的大小,且如果某个版本号的修订号不存在,认为该修订号为 0。最终根据比较结果返回:
- 如果
version1 > version2
,返回 1; - 如果
version1 < version2
,返回 -1; - 如果
version1 == version2
,返回 0。
思路
- 分割字符串:首先,我们需要将版本号按
.
进行分割,得到每个修订号。C++中可以通过std::stringstream
来分割字符串,std::getline
可以将字符串按指定分隔符(如.
)逐个提取出来。 - 转换为整数:每个修订号本质上是一个数字字符串,可能包含前导零。为了避免前导零干扰比较,我们将每个修订号转换为整数,使用
std::stoi
来处理。 - 补齐缺失的修订号:有可能两个版本号长度不同,短的版本号会缺少一些修订号。按照题意,缺少的修订号视为 0。
- 逐个比较修订号:比较两个版本号的每个修订号。如果某个版本号的修订号大于另一个版本号,则该版本号更大,返回
1
。如果较小,返回-1
。如果所有修订号都相同,则返回0
。 - 边界条件:需要注意处理缺失修订号的情况,当某个版本号比另一个短时,我们应认为缺失部分的修订号为 0。
代码详解
#include <iostream>
#include <vector>
#include <sstream>
int solution(std::string version1, std::string version2) {
// 使用字符串流将版本号按'.'分割成各个修订号
std::stringstream ss1(version1), ss2(version2);
std::string token;
std::vector<int> v1, v2;
// 将version1中的修订号转化为整数并存入v1
while (std::getline(ss1, token, '.')) {
v1.push_back(std::stoi(token)); // 转为整数并存入v1
}
// 将version2中的修订号转化为整数并存入v2
while (std::getline(ss2, token, '.')) {
v2.push_back(std::stoi(token)); // 转为整数并存入v2
}
// 比较两个版本号,按照修订号顺序进行比较
int maxLength = std::max(v1.size(), v2.size()); // 确定最长的修订号序列
for (int i = 0; i < maxLength; ++i) {
int num1 = i < v1.size() ? v1[i] : 0; // 如果v1没有该修订号,默认为0
int num2 = i < v2.size() ? v2[i] : 0; // 如果v2没有该修订号,默认为0
if (num1 > num2) return 1; // version1更大
if (num1 < num2) return -1; // version1更小
}
return 0; // 两个版本号相等
}
int main() {
std::cout << (solution("0.1", "1.1") == -1) << std::endl;
std::cout << (solution("1.0.1", "1") == 1) << std::endl;
std::cout << (solution("7.5.2.4", "7.5.3") == -1) << std::endl;
std::cout << (solution("1.0", "1.0.0") == 0) << std::endl;
return 0;
}
1. 字符串分割和整数转换
std::stringstream ss1(version1), ss2(version2);
std::string token;
std::vector<int> v1, v2;
首先,我们将两个版本号字符串转换为 std::stringstream
对象。std::stringstream
允许我们按指定的分隔符(此处为 .
)逐个读取字符串。
然后,定义 std::vector<int>
存储每个修订号。v1
存储 version1
中的修订号,v2
存储 version2
中的修订号。
while (std::getline(ss1, token, '.')) {
v1.push_back(std::stoi(token)); // 转为整数并存入v1
}
使用 std::getline
按 .
分割 version1
,并将每个修订号转换为整数(std::stoi
)存入 v1
。
同样的操作适用于 version2
。
2. 比较修订号
int maxLength = std::max(v1.size(), v2.size());
我们计算两个版本号中修订号的最大长度,因为两个版本号可能具有不同数量的修订号。需要按最长的修订号序列进行比较,较短的版本号视为在缺失的位置有修订号 0
。
for (int i = 0; i < maxLength; ++i) {
int num1 = i < v1.size() ? v1[i] : 0; // 如果v1没有该修订号,默认为0
int num2 = i < v2.size() ? v2[i] : 0; // 如果v2没有该修订号,默认为0
if (num1 > num2) return 1; // version1更大
if (num1 < num2) return -1; // version1更小
}
遍历所有修订号,逐一比较 version1
和 version2
中的修订号。如果一个版本号缺少某个修订号,则该修订号视为 0
。
- 如果
num1 > num2
,则version1
更大,返回1
。 - 如果
num1 < num2
,则version1
更小,返回-1
。
3. 最终返回值
如果两个版本号所有修订号都相等,则返回 0
。
总结与建议
思路总结
- 字符串分割:使用
std::stringstream
和std::getline
按.
分割版本号字符串。 - 修订号转换:将每个修订号转换为整数,避免前导零问题。
- 补齐缺失的修订号:通过比较两个版本号的修订号数目来处理缺失的修订号,缺失的视为
0
。 - 逐个比较:按顺序比较修订号,得出最终比较结果。
对入门同学的建议
- 理解字符串操作:要熟悉 C++ 中字符串的处理方法,特别是如何按分隔符分割字符串。
std::getline
是一个常用的工具,能够按指定分隔符读取数据。 - 掌握基本数据类型和转换:了解如何将字符串转换为整数,以及如何处理整数中的前导零问题。
- 考虑边界情况:在设计程序时,要特别注意边界条件,比如版本号长度不同的情况,处理缺失的修订号时要视为
0
。 - 逐步调试与测试:遇到问题时,建议分步调试程序,逐个检查每个步骤的结果,尤其是字符串的分割和整数转换部分。