Compare Version Numbers

Updated on 12 May, 2025
Compare Version Numbers header image

Problem Statement

In software development, versioning is crucial and often represented by a string comprising numerical revisions separated by dots (.). The task here is to compare two such version strings, version1 and version2. Each version string is dissected into segment-by-segment revisions from left to right, with each segment being evaluated as an integer (ignoring any leading zeros). If version1 and version2 have a different number of revisions, the comparison treats the absent segments in the shorter string as zero.

The function is expected to output specific values based on the comparison:

  • Return -1 if version1 is less than version2.
  • Return 1 if version1 is greater than version2.
  • Return 0 if both version strings are considered equal.

This comparison serves in contexts where software versions need to be aligned or checked for compatibility, updates, or dependencies.

Examples

Example 1

Input:

version1 = "1.2", version2 = "1.10"

Output:

-1

Explanation:

version1's second revision is "2" and version2's second revision is "10": 2 < 10, so version1 < version2.

Example 2

Input:

version1 = "1.01", version2 = "1.001"

Output:

0

Explanation:

Ignoring leading zeroes, both "01" and "001" represent the same integer "1".

Example 3

Input:

version1 = "1.0", version2 = "1.0.0.0"

Output:

0

Explanation:

version1 has less revisions, which means every missing revision are treated as "0".

Constraints

  • 1 <= version1.length, version2.length <= 500
  • version1 and version2 only contain digits and '.'.
  • version1 and version2 are valid version numbers.
  • All the given revisions in version1 and version2 can be stored in a 32-bit integer.

Approach and Intuition

Understanding and comparing version strings involves several intuitive steps:

  1. Begin by splitting both version1 and version2 using the dot (.) as a delimiter. This separates each version into its constituent revisions.
  2. Iterate over the resulting list of revisions. Convert each revision from a string to an integer, which allows for accurate numeric comparisons and ignores leading zeros.
  3. When one version string contains more revisions than the other, treat missing revisions in the shorter string as "0" during the comparison. This is often the case for software where version 1.0 is equivalently treated as 1.0.0.0.
  4. Compare corresponding revisions in the sequence:
    • As soon as a difference is found, return -1 or 1 based on whether the revision from version1 is lesser or greater than version2.
    • If all corresponding revisions are equal and there are no more revisions to compare, return 0.

This approach ensures that the version comparison is thorough and directly relates to the common practice in software versioning, where minor updates (higher revisions) have critical implications for functionality and compatibility.

Solutions

  • C++
  • Java
  • C
  • JavaScript
  • Python
cpp
class Solution {
public:
    pair<int, int> extractChunk(string& ver, int len, int index) {
        if (index > len - 1) {
            return make_pair(0, index);
        }

        int endIndex = index;
        while (endIndex < len && ver[endIndex] != '.') {
            ++endIndex;
        }

        int segment = stoi(ver.substr(index, endIndex != len - 1 ? endIndex - index : len - index));
        index = endIndex + 1;

        return make_pair(segment, index);
    }

    int compareVersion(string ver1, string ver2) {
        int index1 = 0, index2 = 0;
        int length1 = ver1.size(), length2 = ver2.size();

        while (index1 < length1 || index2 < length2) {
            pair<int, int> chunk1 = extractChunk(ver1, length1, index1);
            index1 = chunk1.second;
            pair<int, int> chunk2 = extractChunk(ver2, length2, index2);
            index2 = chunk2.second;

            if (chunk1.first != chunk2.first) {
                return chunk1.first > chunk2.first ? 1 : -1;
            }
        }
        return 0;
    }
};

In the "Compare Version Numbers" problem, the provided C++ solution involves comparing two version strings to determine which version is newer, older, or if both are the same. Below is an overview of how this code achieves the solution and what each segment accomplishes:

  • Extraction of Version Segments:

    • A private method extractChunk assists in breaking down the version strings into numeric parts (chunks) separated by dots ('.'). For example, in the version string "1.2.3", the segments would be 1, 2, and 3.
    • This method uses a starting index to identify where the current segment starts. It then scans the string until it hits a dot or the end of the string, at which point it extracts the numeric value of the segment.
    • The method returns a pair containing the numeric value of the extracted segment and the updated index position, which indicates where the next segment starts.
  • Comparison Logic:

    • compareVersion computes the sizes of both version strings and initializes indices to traverse them.
    • It continues to extract and compare segments from each version as long as there are remaining segments in either of the version strings.
    • During each loop iteration, the extractChunk method provides the next segment from each version. These segments are compared:
      • If they differ, the method immediately returns 1 or -1 to indicate which version is greater.
      • If they are the same, the loop continues to the next segments.
    • If all corresponding segments of both versions are equal and there are no more segments to compare, the method concludes that the versions are equal and returns 0.

This solution effectively handles comparisons across versions with varying lengths and different segment counts. It ensures a thorough and direct comparison segment by segment, adhering strictly to numerical differences rather than string-based discrepancies.

java
class Solution {
    public Pair<Integer, Integer> extractPart(String ver, int len, int start) {
        if (start > len - 1) {
            return new Pair(0, start);
        }

        int index, end = start;
        while (end < len && ver.charAt(end) != '.') {
            ++end;
        }

        if (end != len - 1) {
            index = Integer.parseInt(ver.substring(start, end));
        } else {
            index = Integer.parseInt(ver.substring(start, len));
        }

        start = end + 1;

        return new Pair(index, start);
    }

    public int compareVersion(String version1, String version2) {
        int s1 = 0, s2 = 0;
        int l1 = version1.length(), l2 = version2.length();

        int num1, num2;
        Pair<Integer, Integer> chunk;
        while (s1 < l1 || s2 < l2) {
            chunk = extractPart(version1, l1, s1);
            num1 = chunk.getKey();
            s1 = chunk.getValue();

            chunk = extractPart(version2, l2, s2);
            num2 = chunk.getKey();
            s2 = chunk.getValue();
            if (num1 != num2) {
                return num1 > num2 ? 1 : -1;
            }
        }

        return 0;
    }
}
  • Extract version parts and compare:

    • Initialize two pointers s1 and s2 for each version string and iterate until either reaches the end of its respective string.
    • In each iteration, extract the numerical part of each version using the extractPart method which locates the next dot character or end of string to determine the end of the current version number.
    • Convert the substring between start and end into an integer and move the start pointer to the character after the dot (or keep it at the end if there is no dot).
    • Compare the extracted part from each string. If they differ, decide the result of the comparison based on which number is greater.
    • Return 0 if the entire comparison proceeds without finding any differences, indicating that both version numbers are equivalent.
  • Edge Handling:

    • If one version number string is longer and the comparison has not been decided by the end of the shorter string, continue comparing. If only zeros are encountered in the extra portion of the longer string, they do not affect the outcome (the version numbers are still considered equivalent).

This method allows for a precise and efficient comparison of version numbers by breaking down the strings into numerical chunks and directly comparing these integers, ensuring a correct semantic versioning comparison.

c
typedef struct st {
    int num;
    int pos;
} Segment;

Segment extractSegment(char *str, int len, int startPos) {
    if (startPos > len - 1) {
        return (Segment){0, startPos};
    }
    int endPos = startPos;
    while (endPos < len && str[endPos] != '.') {
        endPos++;
    }
    int segmentLength = endPos - startPos;
    char segmentStr[segmentLength + 1];
    strncpy(segmentStr, &str[startPos], segmentLength);
    segmentStr[segmentLength] = '\0';

    int value = atoi(segmentStr);
    startPos = endPos + 1;

    return (Segment){value, startPos};
}

int compareVersionStrings(char *str1, char *str2) {
    int index1 = 0, index2 = 0;
    int length1 = strlen(str1), length2 = strlen(str2);

    Segment seg1, seg2;
    while (index1 < length1 || index2 < length2) {
        seg1 = extractSegment(str1, length1, index1);
        index1 = seg1.pos;
        seg2 = extractSegment(str2, length2, index2);
        index2 = seg2.pos;
        if (seg1.num != seg2.num) {
            return seg1.num > seg2.num ? 1 : -1;
        }
    }
    return 0;
}

This solution for comparing version numbers written in C language involves defining a custom data structure and utilizing string and integer manipulations. Here's a concise summary of how the implementation works:

  • Data Structure: A Segment structure is created to keep track of the numerical value of the version segment and the position in the string.

  • Extraction Mechanism: The extractSegment function is responsible for extracting numerical segments from the version string. It takes a part of the string from the specified start position until a period (.) or the end of the string is reached, converts it into an integer, and updates the start position for the next segment extraction.

  • Comparison Logic: The compareVersionStrings function compares two version strings by repeatedly extracting segments from each version until both strings have been fully parsed. At each step:

    • Retrieves segment from version string 1 and updates its parsing position.
    • Retrieves segment from version string 2 and updates its parsing position.
    • Compares the numerical values of the obtained segments.
    • If there is a mismatch between segments from the two version strings, the function determines which version is greater based on the comparison of these segments.
    • Continues the comparison until both strings have no more segments to compare.
  • Result: If segments of both strings match throughout the scan, the versions are considered equal, signified by returning 0. If one version string's segment is greater than the other at any point, the function returns 1 or -1 accordingly to indicate the greater or lesser version respectively.

Overall, this approach ensures an accurate comparison of version numbers where each segment is considered independently, enabling precise version management and compatibility checks between different software versioning systems.

js
var versionComparator = function(v1, v2) {
    var extractChunk = function(ver, length, index) {
        if (index > length - 1) {
            return [0, index];
        }
        let end = index;
        while (end < length && ver[end] != ".") {
            end++;
        }
        let num = parseInt(ver.substring(index, end != length - 1 ? end : length));
        index = end + 1;
        return [num, index];
    };

    let index1 = 0,
        index2 = 0;
    let len1 = v1.length,
        len2 = v2.length;

    while (index1 < len1 || index2 < len2) {
        let [num1, newIndex1] = extractChunk(v1, len1, index1);
        index1 = newIndex1;
        let [num2, newIndex2] = extractChunk(v2, len2, index2);
        index2 = newIndex2;
        if (num1 != num2) {
            return num1 > num2 ? 1 : -1;
        }
    }
    return 0;
};

The provided JavaScript function versionComparator compares two version numbers represented as strings. Here's a breakdown of how this function performs the comparison:

  • Each version string is analyzed by repeatedly extracting numerical chunks separated by dots (e.g., "1.0.3" is split into [1, 0, 3]).
  • The function extractChunk is used to extract the next numeric chunk from a provided position within the version string. It handles the parsing and returns the extracted number along with the new position index.
  • The main part of versionComparator uses two index variables to traverse each version string simultaneously, comparing the numerical value of each chunk.
  • Comparison proceeds as long as there is content left in at least one version string:
    • For each step, the numerical value of the current chunk from both version strings is extracted.
    • The two numbers are compared:
      • If they differ, the function immediately returns 1 or -1 depending on which number is greater.
      • If they are equal, the comparison moves to the next chunk.
    • If one version string ends (and thus returns a chunk of 0) while the other still contains numbers, the function accurately continues comparison ensuring versions like "1.0" and "1.0.0" are considered equivalent.
    • Once both version strings are fully traversed, and all compared chunks are equal, the function returns 0.

In essence, this method effectively handles version comparison by accounting for different length strings and positionally compares each segment, ensuring an accurate result based on numerical precedence of version order.

python
class Solution:
    def extract_part(self, ver: str, length: int, start: int) -> List[int]:
        # If start index exceeds length of version string, return zero
        if start > length - 1:
            return 0, start
        
        # Locate the end of the numeric part
        start_end = start
        while start_end < length and ver[start_end] != '.':
            start_end += 1

        # Extract the numeric part
        part = int(ver[start:start_end])

        # Update the start position to the beginning of the next part
        start = start_end + 1

        return part, start

    def compare_version_numbers(self, ver1: str, ver2: str) -> int:
        idx1 = idx2 = 0
        len1, len2 = len(ver1), len(ver2)

        # Continuously compare parts of the version numbers
        while idx1 < len1 or idx2 < len2:
            num1, idx1 = self.extract_part(ver1, len1, idx1)
            num2, idx2 = self.extract_part(ver2, len2, idx2)
            if num1 != num2:
                return 1 if num1 > num2 else -1

        # Versions are identical
        return 0

This Python code defines a solution to the problem of comparing two version numbers provided as strings. Following is a summarization of how this solution operates:

  • An inner helper method extract_part() is responsible for parsing the next numeric section of the version string until a period (.) is encountered or the string ends. This method handles the parsing logic, converting the substring to an integer, and updating the index to point to the start of the next segment after the period.

  • The main method compare_version_numbers() initializes pointers for both version strings. It uses a loop to continuously extract and compare corresponding parts of both version strings until either all parts have been compared or a difference is found.

  • In the main comparison loop, the extract_part() method is called for each version string separately, which returns the numeric part of the version and the next index position to read. If the extracted parts differ, the method immediately returns 1 or -1 based on which version is greater. If all compared parts are equal and the loop completes, it returns 0 indicating both versions are identical.

Here's how the algorithm executes:

  1. Initialize index and length for both version strings.
  2. Loop through both strings while either has more parts to process.
  3. Extract and parse the current numeric part of each version string.
  4. Compare these parts:
    • If they differ, determine which one is larger and return accordingly.
  5. If all processed parts are the same, return 0.

This method ensures a thorough and efficient comparison, handling versions with different lengths or leading zeros accurately.

Comments

No comments yet.