|
| 1 | +# 165. Compare Version Numbers |
| 2 | + |
| 3 | +Given two version strings, `version1` and `version2`, compare them. |
| 4 | +A version string consists of revisions separated by dots `'.'`. |
| 5 | +The value of the revision is its integer conversion ignoring leading zeros. |
| 6 | + |
| 7 | +To compare version strings, compare their revision values in left-to-right order. |
| 8 | +If one of the version strings has fewer revisions, treat the missing revision values as `0`. |
| 9 | + |
| 10 | +Return the following: |
| 11 | + |
| 12 | +- If `version1` < `version2`, return -1. |
| 13 | +- If `version1` > `version2`, return 1. |
| 14 | +- Otherwise, return 0. |
| 15 | + |
| 16 | +**Constraints:** |
| 17 | + |
| 18 | +- `1 <= version1.length, version2.length <= 500` |
| 19 | +- `version1` and `version2` only contain digits and '.'. |
| 20 | +- `version1` and `version2` are valid version numbers. |
| 21 | +- All the given revisions in `version1` and `version2` can be stored in a 32-bit integer. |
| 22 | + |
| 23 | +## 基礎思路 |
| 24 | + |
| 25 | +本題要我們比較兩個版本號字串,並判斷哪一個版本號較大、較小或是否相等。 |
| 26 | +在思考解法時,我們需要特別注意幾個重點: |
| 27 | + |
| 28 | +- 每個版本號是由多個「修訂段(revision)」組成,並以 `'.'` 分隔; |
| 29 | +- 每段的比較是以整數進行,**前導零應被忽略**(例如 `"01"` 等同於 `1`); |
| 30 | +- 若某個版本有較少的段數,**缺少的段數視為 0**(例如 `"1.0"` 等同於 `"1"` 或 `"1.0.0"`)。 |
| 31 | + |
| 32 | +為了解決這個問題,我們可以採用以下策略: |
| 33 | + |
| 34 | +- **分割與轉換**:先將版本字串用 `'.'` 分割,並將每段轉為整數,以方便後續比較; |
| 35 | +- **對齊長度**:找出兩個版本的最大段數,缺少的部分視為 `0` 補齊; |
| 36 | +- **逐段比較**:從左到右逐一比較對應的段數,一旦某段不同即可決定結果; |
| 37 | +- **全部相等處理**:若所有段數皆相等,代表兩個版本號完全相同,回傳 `0` 即可。 |
| 38 | + |
| 39 | +## 解題步驟 |
| 40 | + |
| 41 | +### Step 1:將版本字串拆解為整數修訂序列 |
| 42 | + |
| 43 | +先把兩個版本依點號切開,並轉成整數陣列(自動忽略前導零)。 |
| 44 | + |
| 45 | +```typescript |
| 46 | +// 將版本字串分割為修訂數值陣列 |
| 47 | +const revisionsOfVersion1 = version1.split('.').map(Number); |
| 48 | +const revisionsOfVersion2 = version2.split('.').map(Number); |
| 49 | +``` |
| 50 | + |
| 51 | +### Step 2:確定需要比較的最大段數 |
| 52 | + |
| 53 | +取兩者修訂段數的最大值,確保能補齊較短的一方(以 0 視之)。 |
| 54 | + |
| 55 | +```typescript |
| 56 | +// 決定需要比較的最大修訂段數 |
| 57 | +const maximumLength = Math.max(revisionsOfVersion1.length, revisionsOfVersion2.length); |
| 58 | +``` |
| 59 | + |
| 60 | +### Step 3:逐段由左到右比較修訂值 |
| 61 | + |
| 62 | +依序取出對應段的數值;若某一方沒有該段,直接以 0 代替。發現差異即可回傳結果。 |
| 63 | + |
| 64 | +```typescript |
| 65 | +// 逐段比較每個修訂值 |
| 66 | +for (let index = 0; index < maximumLength; index++) { |
| 67 | + const revisionValue1 = index < revisionsOfVersion1.length ? revisionsOfVersion1[index] : 0; |
| 68 | + const revisionValue2 = index < revisionsOfVersion2.length ? revisionsOfVersion2[index] : 0; |
| 69 | + |
| 70 | + if (revisionValue1 > revisionValue2) { |
| 71 | + return 1; |
| 72 | + } |
| 73 | + |
| 74 | + if (revisionValue1 < revisionValue2) { |
| 75 | + return -1; |
| 76 | + } |
| 77 | +} |
| 78 | +``` |
| 79 | + |
| 80 | +### Step 4:若所有段都相同,回傳相等 |
| 81 | + |
| 82 | +當整個比較流程未提早返回,代表所有段值皆相等。 |
| 83 | + |
| 84 | +```typescript |
| 85 | +// 所有修訂值皆相等 |
| 86 | +return 0; |
| 87 | +``` |
| 88 | + |
| 89 | +## 時間複雜度 |
| 90 | + |
| 91 | +- 分割字串與映射為整數為線性;逐段比較亦為線性,整體與修訂段數成正比。 |
| 92 | +- 總時間複雜度為 $O(n)$。 |
| 93 | + |
| 94 | +> $O(n)$ |
| 95 | +
|
| 96 | +## 空間複雜度 |
| 97 | + |
| 98 | +- 額外使用兩個修訂陣列,其長度與輸入段數成正比。 |
| 99 | +- 總空間複雜度為 $O(n)$。 |
| 100 | + |
| 101 | +> $O(n)$ |
0 commit comments