【C++算法打怪专栏】LeetCode 165. 比较版本号(双指针与字符串流法)
题目描述
给你两个版本号字符串 version1 和 version2 ,请你比较它们。版本号由修订号组成,修订号由点 . 分隔。如果 version1 > version2 返回 1,如果 version1 < version2 返回 -1,否则返回 0。
解法一:stringstream + getline 分割法(代码简洁)
💡 核心思路
利用 C++ 标准库中的 stringstream(字符串流)结合 getline 函数,按照指定分隔符 . 提取每一段修订号,再通过 stoi 转为整数进行比较。若某个版本号段数不足,流读取失败后默认将该段视为 0。
💻 代码实现
cpp
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
class Solution {
public:
int compareVersion(string version1, string version2) {
stringstream ss1(version1), ss2(version2);
string s1, s2;
// 只要其中一个版本号还有未读取的修订段,就继续比较
while (ss1.good() || ss2.good()) {
int v1 = 0, v2 = 0; // 默认缺省段为 0
// 按照 '.' 提取修订号并转换为整数(自动忽略前导零)
if (getline(ss1, s1, '.')) v1 = stoi(s1);
if (getline(ss2, s2, '.')) v2 = stoi(s2);
if (v1 < v2) return -1;
if (v1 > v2) return 1;
}
return 0;
}
};
- 优点:逻辑清晰,代码优雅,省去手动处理字符转数字与前导零的繁琐细节。
- 复杂度分析 :
- 时间复杂度 :O(N+M)O(N + M)O(N+M),其中 NNN 和 MMM 分别为两个字符串的长度。
- 空间复杂度 :O(N+M)O(N + M)O(N+M),使用了字符串流及临时字符串保存切割结果。
解法二:双指针原地方案(极致性能,0 额外空间)
💡 核心思路
定义两个指针分别指向 version1 和 version2 的起始位置,边遍历边用数字累加的方式解析出当前的修订号数值(遇 . 停止),比较完当前段后跳过 . 接着处理下一段。
💻 代码实现
cpp
#include <iostream>
#include <string>
using namespace std;
class Solution {
public:
int compareVersion(string version1, string version2) {
int i = 0, j = 0;
int n1 = version1.size(), n2 = version2.size();
while (i < n1 || j < n2) {
long long num1 = 0, num2 = 0;
// 提取 version1 当前修订号数值
while (i < n1 && version1[i] != '.') {
num1 = num1 * 10 + (version1[i] - '0');
i++;
}
i++; // 跳过 '.'
// 提取 version2 当前修订号数值
while (j < n2 && version2[j] != '.') {
num2 = num2 * 10 + (version2[j] - '0');
j++;
}
j++; // 跳过 '.'
if (num1 < num2) return -1;
if (num1 > num2) return 1;
}
return 0;
}
};
- 优点 :无需创建临时对象与切割子串,能达到 0 ms0\text{ ms}0 ms 执行用时与 O(1)O(1)O(1) 辅助空间开销。
- 复杂度分析 :
- 时间复杂度 :O(max(N,M))O(\max(N, M))O(max(N,M)),线性双指针扫描一遍。
- 空间复杂度 :O(1)O(1)O(1),仅需常数级别的双指针和计数变量。