|
| 1 | +### 题目描述 |
| 2 | + |
| 3 | +这是 LeetCode 上的 **[468. 验证IP地址](https://leetcode.cn/problems/validate-ip-address/solution/by-ac_oier-s217/)** ,难度为 **中等**。 |
| 4 | + |
| 5 | +Tag : 「模拟」、「双指针」 |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +给定一个字符串 `queryIP`。如果是有效的 `IPv4` 地址,返回 `"IPv4"` ;如果是有效的 `IPv6` 地址,返回 `"IPv6"` ;如果不是上述类型的 `IP` 地址,返回 `"Neither"` 。 |
| 10 | + |
| 11 | +有效的 `IPv4` 地址 是 `"x1.x2.x3.x4"` 形式的 `IP` 地址。 其中$ 0 <= x_i <= 255$ 且 $x_i$ 不能包含 前导零。 |
| 12 | + |
| 13 | +例如: `"192.168.1.1"` 、 `"192.168.1.0"` 为有效 `IPv4` 地址, `"192.168.01.1"` 为无效 `IPv4` 地址; `"192.168.1.00"` 、 `"192.168@1.1"` 为无效 `IPv4` 地址。 |
| 14 | + |
| 15 | +一个有效的 `IPv6` 地址 是一个格式为 `"x1:x2:x3:x4:x5:x6:x7:x8"` 的 `IP` 地址,其中: |
| 16 | + |
| 17 | +* 1ドル <= x_i.length <= 4$ |
| 18 | +* $x_i$ 是一个 十六进制字符串 ,可以包含数字、小写英文字母( `'a'` 到 `'f'` )和大写英文字母( `'A'` 到 `'F'` )。 |
| 19 | +* 在 $x_i$ 中允许前导零。 |
| 20 | + |
| 21 | +例如 `"2001:0db8:85a3:0000:0000:8a2e:0370:7334"` 和 `"2001:db8:85a3:0:0:8A2E:0370:7334"` 是有效的 `IPv6` 地址,而 `"2001:0db8:85a3::8A2E:037j:7334"` 和 `"02001:0db8:85a3:0000:0000:8a2e:0370:7334"` 是无效的 `IPv6` 地址。 |
| 22 | + |
| 23 | +示例 1: |
| 24 | +``` |
| 25 | +输入:queryIP = "172.16.254.1" |
| 26 | + |
| 27 | +输出:"IPv4" |
| 28 | + |
| 29 | +解释:有效的 IPv4 地址,返回 "IPv4" |
| 30 | +``` |
| 31 | +示例 2: |
| 32 | +``` |
| 33 | +输入:queryIP = "2001:0db8:85a3:0:0:8A2E:0370:7334" |
| 34 | + |
| 35 | +输出:"IPv6" |
| 36 | + |
| 37 | +解释:有效的 IPv6 地址,返回 "IPv6" |
| 38 | +``` |
| 39 | +示例 3: |
| 40 | +``` |
| 41 | +输入:queryIP = "256.256.256.256" |
| 42 | + |
| 43 | +输出:"Neither" |
| 44 | + |
| 45 | +解释:既不是 IPv4 地址,又不是 IPv6 地址 |
| 46 | +``` |
| 47 | + |
| 48 | +提示: |
| 49 | +* `queryIP` 仅由英文字母,数字,字符 `'.'` 和 `':'` 组成。 |
| 50 | + |
| 51 | +--- |
| 52 | + |
| 53 | +### 模拟 |
| 54 | + |
| 55 | +为了方便,我们称合法 `IPv4`/`IPv6` 中由 `.`/`:` 分割的部分称为 `item`。 |
| 56 | + |
| 57 | +无论是 `IPv4` 还是 `IPv6`,我们都只需将连续段的 `item` 取出,并结合题意判断即可,一个较为简单的方式使用 `split` 操作来得到所有的 `item`,考虑到某些语言并不内置 `split`,这里采取双指针的方式来做。 |
| 58 | + |
| 59 | +为方便大家理解,今天将题解文字说明写到注释中。 |
| 60 | + |
| 61 | +代码: |
| 62 | +```Java |
| 63 | +class Solution { |
| 64 | + public String validIPAddress(String ip) { |
| 65 | + if (ip.indexOf(".") >= 0 && check4(ip)) return "IPv4"; |
| 66 | + if (ip.indexOf(":") >= 0 && check6(ip)) return "IPv6"; |
| 67 | + return "Neither"; |
| 68 | + } |
| 69 | + boolean check4(String ip) { |
| 70 | + int n = ip.length(), cnt = 0; |
| 71 | + char[] cs = ip.toCharArray(); |
| 72 | + for (int i = 0; i < n && cnt <= 3; ) { |
| 73 | + // 找到连续数字段,以 x 存取 |
| 74 | + int j = i, x = 0; |
| 75 | + while (j < n && cs[j] >= '0' && cs[j] <= '9' && x <= 255) x = x * 10 + (cs[j++] - '0'); |
| 76 | + // 非 item 字符之间没有 item |
| 77 | + if (i == j) return false; |
| 78 | + // 含前导零 或 数值大于 255 |
| 79 | + if ((j - i > 1 && cs[i] == '0') || (x > 255)) return false; |
| 80 | + i = j + 1; |
| 81 | + if (j == n) continue; |
| 82 | + // 存在除 . 以外的其他非数字字符 |
| 83 | + if (cs[j] != '.') return false; |
| 84 | + cnt++; |
| 85 | + } |
| 86 | + // 恰好存在 3 个不位于两端的 . |
| 87 | + return cnt == 3 && cs[0] != '.' && cs[n - 1] != '.'; |
| 88 | + } |
| 89 | + boolean check6(String ip) { |
| 90 | + int n = ip.length(), cnt = 0; |
| 91 | + char[] cs = ip.toCharArray(); |
| 92 | + for (int i = 0; i < n && cnt <= 7; ) { |
| 93 | + int j = i; |
| 94 | + while (j < n && ((cs[j] >= 'a' && cs[j] <= 'f') || (cs[j] >= 'A' && cs[j] <= 'F') || (cs[j] >= '0' && cs[j] <= '9'))) j++; |
| 95 | + // 非 item 字符之间没有 item 或 长度超过 4 |
| 96 | + if (i == j || j - i > 4) return false; |
| 97 | + i = j + 1; |
| 98 | + if (j == n) continue; |
| 99 | + // 存在除 : 以外的其他非数字字符 |
| 100 | + if (cs[j] != ':') return false; |
| 101 | + cnt++; |
| 102 | + } |
| 103 | + // 恰好存在 7 个不位于两段的 : |
| 104 | + return cnt == 7 && cs[0] != ':' && cs[n - 1] != ':'; |
| 105 | + } |
| 106 | +} |
| 107 | +``` |
| 108 | +* 时间复杂度:$O(n)$ |
| 109 | +* 空间复杂度:使用 `toCharArray` 操作会产生新数组,复杂度为 $O(n),ドル使用 `charAt` 操作代替复杂度为 $O(1)$ |
| 110 | + |
| 111 | +--- |
| 112 | + |
| 113 | +### 最后 |
| 114 | + |
| 115 | +这是我们「刷穿 LeetCode」系列文章的第 `No.468` 篇,系列开始于 2021年01月01日,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 |
| 116 | + |
| 117 | +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 |
| 118 | + |
| 119 | +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 |
| 120 | + |
| 121 | +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 |
| 122 | + |
0 commit comments