版本号对比

126 阅读7分钟

问题描述

在某个项目中,每个版本都用版本号标记,由一个或多个修订号组成,修订号之间由点号.分隔。每个修订号可能有多位数字,并且可能会包含前导零。你需要根据两个版本号 version1 和 version2,判断哪个版本更新,或者它们是否相同。

例如,2.5.33 和 0.1 都是有效的版本号。

当比较两个版本时,从左到右依次比较它们的修订号。忽略每个修订号的前导零,直接比较修订号对应的整数值。如果其中一个版本没有足够的修订号,缺失部分默认补为0

你需要根据以下规则返回比较结果:

  • 如果 version1 > version2,返回 1
  • 如果 version1 < version2,返回 -1
  • 如果两个版本相等,返回 0

1. 问题理解

本题的核心任务是比较两个给定的版本号,确定它们之间的大小关系或者判断是否相等。版本号由一个或多个修订号组成,修订号之间以点号分隔,且可能包含前导零,在比较时需要忽略前导零并按整数值进行比较,同时对于缺失修订号的情况要默认补为 0。

2. 数据特点及处理要求

  • 版本号结构:版本号是由多个修订号通过点号连接而成的字符串形式。每个修订号可能是多位数字,并且可能带有前导零,比如 “001” 这样的形式。

  • 比较规则

    • 从左到右依次比较各个修订号对应的整数值。这意味着要先比较最左边的第一个修订号,若相等再比较第二个,以此类推。
    • 在比较每个修订号时,需要忽略其前导零,将其作为普通整数来比较。例如,“005” 和 “5” 应视为相等的修订号。
    • 如果其中一个版本的修订号数量少于另一个版本,那么在比较时,缺失的修订号部分默认补为 0。比如,比较 “1.2” 和 “1.2.3” 时,对于 “1.2” 来说,在比较第三个修订号时应将其视为 0。

3. 解决思路分析

拆分版本号为修订号列表

  • 首先,需要将输入的两个版本号 version1 和 version2 分别拆分成对应的修订号列表。可以通过以点号为分隔符对版本号字符串进行拆分操作来实现。这样就能得到两个列表,每个列表中的元素就是各个修订号,便于后续逐个比较。

补齐修订号数量差异

  • 在拆分得到两个修订号列表后,可能会出现两个列表长度不同的情况,即两个版本号的修订号数量不一致。根据题目要求,需要将修订号数量少的那个版本号对应的列表进行补齐,在末尾添加足够数量的 0,使得两个列表长度相等。这样在后续比较时,就能够保证每个位置都有对应的修订号可供比较。

逐个比较修订号

  • 对补齐后的两个修订号列表,从左到右逐个比较列表中的元素(即修订号对应的整数值)。可以使用循环来实现逐个位置的比较。
  • 在比较每个修订号时,先将其转换为整数类型(忽略前导零),然后进行大小比较。如果在某个位置发现两个修订号不相等,就可以根据比较结果直接返回相应的值(1 表示 version1 大于 version2,-1 表示 version1 小于 version2)。

判断整体比较结果

  • 如果通过逐个比较修订号,发现所有位置的修订号都相等,那么就说明两个版本号是相等的,此时应返回 0。

通过以上分析的步骤,就可以根据给定的两个版本号 version1 和 version2,按照题目要求准确地判断出它们之间的大小关系或者确定它们是否相等。

代码

def solution(version1, version2):  
    # Split both version strings into lists  
    v1_segments = version1.split('.')  
    v2_segments = version2.split('.')  
    
    # Compare each segment  
    length = max(len(v1_segments), len(v2_segments))  
    
    for i in range(length):  
        # Get the current segment or 0 if out of bounds  
        v1_part = int(v1_segments[i]) if i < len(v1_segments) else 0  
        v2_part = int(v2_segments[i]) if i < len(v2_segments) else 0  
        
        # Compare the integer values of the segments  
        if v1_part > v2_part:  
            return 1  
        elif v1_part < v2_part:  
            return -1  
    
    # If all segments are equal  
    return 0  

# Test cases  
if __name__ == "__main__":  
    print(solution("0.1", "1.1") == -1)  
    print(solution("1.0.1", "1") == 1)  
    print(solution("7.5.2.4", "7.5.3") == -1)  
    print(solution("1.0", "1.0.0") == 0)

2. 代码逻辑分析

拆分版本号为修订号列表

  • v1_segments = version1.split('.'):通过调用字符串的 split 方法,以点号 . 作为分隔符,将输入的版本号 version1 拆分成一个列表 v1_segments,列表中的每个元素就是版本号 version1 中的一个修订号。
  • v2_segments = version2.split('.'):同样的操作,将版本号 version2 也拆分成一个列表 v2_segments,其元素为版本号 version2 的各个修订号。

确定比较长度并进行逐个比较

  • length = max(len(v1_segments), len(v2_segments)):计算出 v1_segments 和 v2_segments 这两个列表长度的最大值,这个长度将作为后续循环比较的次数,确保能够完整地比较两个版本号的所有修订号,即使它们的修订号数量不一致。

  • 通过循环 for i in range(length):从 0 开始,依次遍历到 length - 1,对两个版本号的各个修订号进行比较。

    • 获取当前修订号或默认值 0

      • v1_part = int(v1_segments[i]) if i < len(v1_segments) else 0:在每次循环中,如果当前索引 i 小于 v1_segments 的长度,说明 v1_segments 列表中存在对应位置的修订号,此时将该修订号通过 int 函数转换为整数类型(在转换过程中会忽略前导零);如果当前索引 i 大于等于 v1_segments 的长度,说明已经超出了 v1_segments 的范围,按照题目要求,此时应将该位置视为 0,所以赋值为 0
      • v2_part = int(v2_segments[i]) if i < len(v2_segments) else 0:与上述对 v1_segments 的处理类似,对于 v2_segments 列表,根据当前索引 i 与列表长度的关系,获取当前位置的修订号并转换为整数类型(忽略前导零),或者在超出范围时赋值为 0
    • 比较当前修订号的整数值:

      • if v1_part > v2_part::将获取到的两个版本号在当前位置的修订号整数值进行比较,如果 v1_part 大于 v2_part,根据题目要求,说明 version1 大于 version2,此时直接返回 1
      • elif v1_part < v2_part::如果 v1_part 小于 v2_part,则说明 version1 小于 version2,按照规则应返回 -1

判断整体比较结果

  • 在循环结束后,如果没有在循环过程中因为某个位置的修订号比较结果而提前返回,说明所有位置的修订号都相等,即两个版本号是相等的,此时通过 return 0 返回 0

3. 使用的算法

这段代码主要使用了以下两种算法思想:

列表拆分与遍历算法

首先通过 split 方法将版本号字符串拆分成修订号列表,然后通过循环遍历这些列表来逐个比较修订号。这种先拆分再遍历比较的方式是处理类似由多个子部分组成的数据结构(如本题中的版本号由多个修订号组成)的常见算法思路,它能够将复杂的数据结构分解为便于处理的单元(即修订号),并通过循环依次对这些单元进行操作和比较。

线性比较算法

在逐个比较修订号的过程中,从左到右依次对两个版本号的各个修订号进行线性的比较,一旦发现某个位置的修订号不相等,就根据比较结果立即返回相应的值。这种线性比较的方式符合题目中从左到右依次比较修订号的要求,并且通过尽早返回结果提高了代码的执行效率,避免了不必要的后续比较操作。

综上所述,这段代码通过上述的代码逻辑和所使用的算法,有效地实现了按照特定规则比较两个版本号大小关系的功能。