版本号比较 | 豆包MarsCode AI刷题

6 阅读6分钟

问题描述

给你两个版本号 version1 和 version2,请你比较它们。

版本号由一个或多个修订号组成,各修订号由一个 . 连接。每个修订号由多位数字组成,可能包含前导零。每个版本号至少包含一个字符。修订号从左到右编号,下标从 0 开始,最左边的修订号下标为 0,下一个修订号下标为 1,以此类推。例如,2.5.33 和 0.1 都是有效的版本号。

比较版本号时,请按从左到右的顺序依次比较它们的修订号。比较修订号时,只需比较忽略任何前导零后的整数值。也就是说,修订号 1 和修订号 001 相等。如果版本号没有指定某个下标处的修订号,则该修订号视为 0。例如,版本 1.0 小于版本 1.1,因为它们下标为 0 的修订号相同,而下标为 1 的修订号分别为 0 和 10 < 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。

思路

  1. 分割字符串:首先,我们需要将版本号按 . 进行分割,得到每个修订号。C++中可以通过 std::stringstream 来分割字符串,std::getline 可以将字符串按指定分隔符(如 .)逐个提取出来。
  2. 转换为整数:每个修订号本质上是一个数字字符串,可能包含前导零。为了避免前导零干扰比较,我们将每个修订号转换为整数,使用 std::stoi 来处理。
  3. 补齐缺失的修订号:有可能两个版本号长度不同,短的版本号会缺少一些修订号。按照题意,缺少的修订号视为 0。
  4. 逐个比较修订号:比较两个版本号的每个修订号。如果某个版本号的修订号大于另一个版本号,则该版本号更大,返回 1。如果较小,返回 -1。如果所有修订号都相同,则返回 0
  5. 边界条件:需要注意处理缺失修订号的情况,当某个版本号比另一个短时,我们应认为缺失部分的修订号为 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更小
}

遍历所有修订号,逐一比较 version1version2 中的修订号。如果一个版本号缺少某个修订号,则该修订号视为 0

  • 如果 num1 > num2,则 version1 更大,返回 1
  • 如果 num1 < num2,则 version1 更小,返回 -1
3. 最终返回值

如果两个版本号所有修订号都相等,则返回 0

总结与建议

思路总结
  1. 字符串分割:使用 std::stringstreamstd::getline. 分割版本号字符串。
  2. 修订号转换:将每个修订号转换为整数,避免前导零问题。
  3. 补齐缺失的修订号:通过比较两个版本号的修订号数目来处理缺失的修订号,缺失的视为 0
  4. 逐个比较:按顺序比较修订号,得出最终比较结果。
对入门同学的建议
  • 理解字符串操作:要熟悉 C++ 中字符串的处理方法,特别是如何按分隔符分割字符串。std::getline 是一个常用的工具,能够按指定分隔符读取数据。
  • 掌握基本数据类型和转换:了解如何将字符串转换为整数,以及如何处理整数中的前导零问题。
  • 考虑边界情况:在设计程序时,要特别注意边界条件,比如版本号长度不同的情况,处理缺失的修订号时要视为 0
  • 逐步调试与测试:遇到问题时,建议分步调试程序,逐个检查每个步骤的结果,尤其是字符串的分割和整数转换部分。