版本号升级统计

版本号升级统计

问题背景

在软件开发中,产品通过版本号来区分不同的迭代。我们需要实现一个逻辑,来比较一个新版本和一组已发布的旧版本,并统计出其中有多少个版本是低于新版本的(即需要升级)。

版本号格式

  • 版本号由一个或多个数字段组成。
  • 这些数字段之间由点(.)连接。
  • 例如: 1, 1.0, 1.2.03.04.56 都是合法的版本号。
  • 版本 1.0, 1.0.0.0, 1.00.00 被视为不同的版本字符串,但它们的数值比较遵循下述规则。

版本比较规则

要比较两个版本号(例如 v1v2),我们遵循以下步骤:

  1. 分段 : 将两个版本号按点(.)分割成数字段列表。例如,"100.05.0" 变为 [100, 5, 0]

  2. 逐段比较: 从左到右(从第一个段开始)依次比较两个列表对应位置的数字。

    • 如果 v1 的某段数字 小于 v2 的对应段数字,则 v1 低于 v2,比较结束。
    • 如果 v1 的某段数字 大于 v2 的对应段数字,则 v1 高于 v2,比较结束。
    • 如果两段数字相等,则继续比较下一段。
  3. 长度不同处理 : 如果在比较完所有共同长度的段后,数字都完全相同(例如比较 100.50100.50.1),那么段数更少的版本为更低版本

任务要求

给定一个已发布版本的列表 oldVersions 和一个新版本 newVersion,请统计出 oldVersions 中有多少个版本是低于 newVersion 的,并返回这个数量。


输入格式

  • oldVersions: 第一个参数,一个字符串列表,代表已发布的版本号。

    • 0 <= oldVersions.length <= 1000 (样例显示为10,但可能更大)
    • 1 <= oldVersions[i].length <= 50
    • 已发布版本列表中无重复版本号。
  • newVersion: 第二个参数,一个字符串,代表新版本号。

    • 1 <= newVersion.length <= 50
  • 版本号段值 : 0 <= 每个数字段的值 < 2^31


输出格式

  • 一个整数,表示 oldVersions 中需要升级的版本数量。

样例说明

样例 1

  • 输入:

    • oldVersions = ["100.200", "20.500", "100.5", "100.05.0", "0.0.0.0", "100.50.1", "100.50.0"]
    • newVersion = "100.50"
  • 输出 : 4

  • 解释:

    我们将每个 oldVersions 中的版本与新版本 100.50 进行比较:

已发布版本 比较过程 结果 需要升级?
"100.200" 第1段: 100=100。第2段: 200 > 50。 更高
"20.500" 第1段: 20 < 100。 更低
"100.5" 第1段: 100=100。第2段: 5 < 50。 更低
"100.05.0" 第1段: 100=100。第2段: 5 < 50。 更低
"0.0.0.0" 第1段: 0 < 100。 更低
"100.50.1" 前2段相同,但它有第3段,而新版本没有。 更高
"100.50.0" 前2段相同,但它有第3段,而新版本没有。 更高
markdown 复制代码
总计有 **4** 个版本需要升级。

样例 2

  • 输入:

    • oldVersions = []
    • newVersion = "5.0.0"
  • 输出 : 0

  • 解释:

    已发布版本列表为空,因此需要升级的版本数量为 0。

java 复制代码
import java.util.Arrays;
import java.util.Comparator; // 仅用于另一种排序写法,本解法直接比较
import java.util.Scanner;

public class Solution {
    /**
     * 核心比较函数:比较两个版本号字符串 version1 和 version2 的大小。
     *
     * @param version1 第一个版本号字符串
     * @param version2 第二个版本号字符串
     * @return -1 如果 version1 < version2
     * 0 如果 version1 == version2
     * 1 如果 version1 > version2
     */
    private int compareVersions(String version1, String version2) {
        // 1. 使用 "\." 作为分隔符分割版本号。
        //    '.' 在正则表达式中是特殊字符,需要用两个反斜杠转义。
        String[] parts1 = version1.split("\\.");
        String[] parts2 = version2.split("\\.");

        // 2. 确定需要比较的总轮次,即两个版本号段数的最大值。
        int maxLength = Math.max(parts1.length, parts2.length);

        // 3. 从左到右(从最高位段到最低位段)逐段比较。
        for (int i = 0; i < maxLength; i++) {
            // a. 获取当前段的数值。
            //    如果某个版本号已经没有后续段了(即 i 超出了其 parts 数组的长度),
            //    则其当前段的数值视为 0。
            //    例如,比较 "1.2" 和 "1.2.1" 时,在第三轮 (i=2):
            //    "1.2" 的第三段值视为 0,而 "1.2.1" 的第三段值是 1。
            //    这正确地实现了"短的版本更小"的规则。
            int val1 = (i < parts1.length) ? Integer.parseInt(parts1[i]) : 0;
            int val2 = (i < parts2.length) ? Integer.parseInt(parts2[i]) : 0;

            // b. 比较当前段的数值
            if (val1 < val2) {
                return -1; // 发现 version1 更低,立即返回
            }
            if (val1 > val2) {
                return 1;  // 发现 version1 更高,立即返回
            }
            // 如果当前段相等,则继续比较下一段
        }

        // 4. 如果所有已比较的段都相等,则两个版本号相等。
        //    例如 "1.0" 和 "1.0.0.0",在比较前两段时都相等,
        //    后续 "1.0" 的段视为 0,"1.0.0.0" 的段也是 0,所以最终相等。
        //    注意:题目说 "1.0", "1.0.0.0" 视为不同版本,这是指它们在输入列表中是
        //    不同的字符串个体,但在数值比较上是等价的。
        return 0;
    }

    /**
     * 主逻辑方法:统计需要升级的版本数量。
     *
     * @param oldVersions  已发布的版本号列表 (字符串数组)
     * @param newVersion   新发布的版本号 (字符串)
     * @return 需要升级的版本数量
     */
    public int countUpgrades(String[] oldVersions, String newVersion) {
        // 处理边界情况:如果已发布版本列表为空或 null,则没有需要升级的版本。
        if (oldVersions == null || oldVersions.length == 0) {
            return 0;
        }

        int upgradeCount = 0; // 初始化需要升级的版本计数器

        // 遍历每一个旧版本
        for (String oldVersion : oldVersions) {
            // 调用比较函数,判断旧版本是否低于新版本
            // compareVersions 返回 -1 表示 oldVersion < newVersion
            if (compareVersions(oldVersion, newVersion) < 0) {
                upgradeCount++; // 如果是,则升级计数加 1
            }
        }

        return upgradeCount; // 返回总数
    }
}

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取第一行:已发布版本列表的字符串表示
        String oldVersionsLine = scanner.nextLine();
        // 读取第二行:新版本的字符串
        String newVersionLine = scanner.nextLine();
        
        scanner.close();
        
        // --- 解析输入 ---
        // 解析形如 ["100.200", "20.500", ...] 的字符串
        String[] oldVersions = parseStringArray(oldVersionsLine);
        // 新版本字符串可能也带有引号,进行清理
        String newVersion = newVersionLine.replaceAll(""", "").trim();
        
        // 创建 Solution 类的实例并调用方法
        Solution solution = new Solution();
        int result = solution.countUpgrades(oldVersions, newVersion);
        
        // 输出结果
        System.out.println(result);
    }
    
    /**
     * 辅助方法:解析形如 ["a", "b", "c"] 的输入字符串。
     * @param line 输入行
     * @return 字符串数组
     */
    private static String[] parseStringArray(String line) {
        if (line == null || line.length() <= 2) { // 至少应包含 "[]"
            return new String[0];
        }
        // 移除首尾的 '[' 和 ']'
        line = line.trim();
        if (line.startsWith("[") && line.endsWith("]")) {
            line = line.substring(1, line.length() - 1);
        }
        if (line.isEmpty()) {
            return new String[0];
        }
        // 按 "," 分割,并去除每个元素首尾的引号 " 和空格
        return Arrays.stream(line.split(","))
                     .map(s -> s.trim().replaceAll(""", ""))
                     .toArray(String[]::new);
    }
}
相关推荐
青岛少儿编程-王老师6 分钟前
CCF编程能力等级认证GESP—C++1级—20250628
java·开发语言·c++
hrrrrb1 小时前
【密码学】1. 引言
网络·算法·密码学
lifallen1 小时前
KRaft 角色状态设计模式:从状态理解 Raft
java·数据结构·算法·设计模式·kafka·共识算法
LittleLoveBoy1 小时前
Java HashMap key为Integer时,遍历是有序还是无序?
java·开发语言
经典19921 小时前
Java 设计模式及应用场景
java·单例模式·设计模式
雲墨款哥1 小时前
算法练习-Day1-交替合并字符串
javascript·算法
fishcanf1y2 小时前
记一次与Fibonacci斗智斗勇
算法
oioihoii2 小时前
Visual Studio C++编译器优化等级详解:配置、原理与编码实践
java·c++·visual studio
没有羊的王K2 小时前
SSM框架——Day4
java·开发语言
24kHT2 小时前
2.3 前端-ts的接口以及自定义类型
java·开发语言·前端