文章目录

  • LeetCode 468. 验证IP地址 - 详细解析
    • 题目描述
      • IPv4验证规则:
      • IPv6验证规则:
    • 最优Java解决方案(注释完整版)
    • 关键变量含义及代码技巧
      • 代码技巧详解
        • 1. 前导零检查的最佳实践
        • 2. IPv6为什么不能用Character.isDigit()
        • 3. 针对性注释设计
    • 算法核心思路
    • 可视化演示过程
      • 测试用例1:有效IPv4 - "172.16.254.1"(优化版演示)
      • 测试用例2:有效IPv6 - "2001:0db8:85a3:0:0:8A2E:0370:7334"(优化版演示)
      • 测试用例3:无效IPv4(前导零)- "192.168.01.1"(优化版演示)
      • 测试用例4:无效IPv4(超出范围)- "256.256.256.256"(优化版演示)
      • 测试用例5:无效IPv6(段过长)- "02001:0db8:85a3:0000:0000:8a2e:0370:7334"
      • 测试用例6:无效格式(非法字符)- "192.168@1.1"
    • 算法复杂度分析
    • 关键技术点详解
      • String的isEmpty() vs isBlank()方法对比
        • 详细对比示例:
        • 在IP验证中的应用:
        • 安全的null检查:
      • split() 方法的 limit 参数
    • 代码优化技巧总结
    • 代码优势对比
    • 常见陷阱

LeetCode 468. 验证IP地址 - 详细解析

题目描述

给定一个字符串 queryIP。如果是有效的 IPv4 地址,返回 “IPv4” ;如果是有效的 IPv6 地址,返回 “IPv6” ;如果不是上述类型的 IP 地址,返回 “Neither” 。

IPv4验证规则:

  • 格式:“x1.x2.x3.x4”
  • 0 <= xi <= 255
  • xi 不能包含前导零(除了"0"本身)

IPv6验证规则:

  • 格式:“x1:x2:x3:x4:x5:x6:x7:x8”
  • 1 <= xi.length <= 4
  • xi 是十六进制字符串(0-9, a-f, A-F)
  • 允许前导零

最优Java解决方案(注释完整版)

class Solution {public String validIPAddress(String queryIP) {if (queryIP.contains(".")) {return isValidIPV4(queryIP) ? "IPv4" : "Neither";} else if (queryIP.contains(":")) {return isValidIPV6(queryIP) ? "IPv6" : "Neither";} else return "Neither";}boolean isValidIPV4(String ip) {String[] parts = ip.split("\\.", -1);if (parts.length != 4) {return false;}for (String part : parts) {int n = part.length();if (n == 0 || n > 3) { // 针对""和2555的输入return false;}if (n > 1 && part.startsWith("0")) { // 针对10.01.1.1输入,前导零return false;}for (char c : part.toCharArray()) { // 针对非数字输入if (!Character.isDigit(c)) {return false;}}int num = Integer.parseInt(part); // 针对256.0.0.1输入if (!(num >= 0 && num <= 255)) {return false;}}return true;}boolean isValidIPV6(String ip) {String[] parts = ip.split(":", -1);if (parts.length != 8) {return false;}for (String part : parts) {int n = part.length();if (n == 0 || n > 4) { // 针对空串和11111输入return false;}for (char c : part.toCharArray()) {// 这里不能替换为Character.isDigit(c)if (!((c >= '0' && c <= '9') ||(c >= 'a' && c <= 'f') ||(c >= 'A' && c <= 'F'))) {return false;}}}return true;}
}

关键变量含义及代码技巧

变量名含义作用
queryIP输入的待验证IP字符串算法的输入参数
parts分割后的IP段数组存储按".“或”:"分割的各个部分
part单个IP段字符串用于验证每个独立的IP段
nIP段的长度int n = part.length() 提高代码可读性
numIPv4段的整数值用于检查IPv4段是否在0-255范围内
c字符变量用于逐字符检查是否符合格式要求

代码技巧详解

1. 前导零检查的最佳实践
if (n > 1 && part.startsWith("0")) { // 针对10.01.1.1输入,前导零return false;
}

为什么用 startsWith("0") 而不是 charAt(0) == '0'

  • 更语义化,表达"以0开头"的意图更清晰
  • startsWith() 内部已经做了边界检查,更安全
2. IPv6为什么不能用Character.isDigit()
// 这里不能替换为Character.isDigit(c)
if (!((c >= '0' && c <= '9') ||(c >= 'a' && c <= 'f') ||(c >= 'A' && c <= 'F'))) {return false;
}

原因分析:

  • Character.isDigit(c) 只检查数字字符(0-9)
  • IPv6需要十六进制字符:数字(0-9) + 字母(a-f, A-F)
  • 必须手动检查三个范围:数字、小写字母、大写字母
3. 针对性注释设计

代码中的注释都标明了具体要处理的边界情况:

  • // 针对""和2555的输入 → 长度检查
  • // 针对10.01.1.1输入,前导零 → 前导零检查
  • // 针对非数字输入 → 字符合法性检查
  • // 针对256.0.0.1输入 → 数值范围检查
  • // 针对空串和11111输入 → IPv6长度检查

算法核心思路

  1. 预判断:通过检查是否包含".“或”:"来初步判断IP类型
  2. 分割验证:将IP按分隔符分割成段,验证段数是否正确
  3. 逐段检查:对每个段进行格式和数值范围验证
  4. 字符级验证:确保每个字符都符合对应IP类型的要求

可视化演示过程

测试用例1:有效IPv4 - “172.16.254.1”(优化版演示)

步骤1:初步判断
queryIP = "172.16.254.1"
包含"." ✓ → 进入IPv4验证步骤2:分割并长度检查
parts = ["172", "16", "254", "1"]
parts.length = 4 ✓ → 段数正确,继续验证步骤3:逐段内联验证
part[0] = "172"
├── 长度检查: 3 ≤ 3 ✓
├── 前导零检查: 首字符'1' ≠ '0' ✓
├── 字符检查: '1','7','2' 全为数字 ✓
└── 数值检查: Integer.parseInt("172") = 172 ≤ 255 ✓part[1] = "16"
├── 长度检查: 2 ≤ 3 ✓
├── 前导零检查: 首字符'1' ≠ '0' ✓
├── 字符检查: '1','6' 全为数字 ✓
└── 数值检查: Integer.parseInt("16") = 16 ≤ 255 ✓part[2] = "254"
├── 长度检查: 3 ≤ 3 ✓
├── 前导零检查: 首字符'2' ≠ '0' ✓
├── 字符检查: '2','5','4' 全为数字 ✓
└── 数值检查: Integer.parseInt("254") = 254 ≤ 255 ✓part[3] = "1"
├── 长度检查: 1 ≤ 3 ✓
├── 前导零检查: 长度=1,无需检查 ✓
├── 字符检查: '1' 为数字 ✓
└── 数值检查: Integer.parseInt("1") = 1 ≤ 255 ✓结果:返回 "IPv4"

测试用例2:有效IPv6 - “2001:0db8:85a3:0:0:8A2E:0370:7334”(优化版演示)

步骤1:初步判断
queryIP = "2001:0db8:85a3:0:0:8A2E:0370:7334"
不包含"." 但包含":" ✓ → 进入IPv6验证步骤2:分割并长度检查
parts = ["2001", "0db8", "85a3", "0", "0", "8A2E", "0370", "7334"]
parts.length = 8 ✓ → 段数正确,继续验证步骤3:逐段内联验证
part[0] = "2001"
├── 长度检查: 4 ≤ 4 ✓
└── 内联十六进制检查:│ '2': '0'≤'2'≤'9' ✓│ '0': '0'≤'0'≤'9' ✓│ '0': '0'≤'0'≤'9' ✓│ '1': '0'≤'1'≤'9' ✓part[1] = "0db8"
├── 长度检查: 4 ≤ 4 ✓
└── 内联十六进制检查:│ '0': '0'≤'0'≤'9' ✓│ 'd': 'a'≤'d'≤'f' ✓│ 'b': 'a'≤'b'≤'f' ✓│ '8': '0'≤'8'≤'9' ✓part[5] = "8A2E"
├── 长度检查: 4 ≤ 4 ✓
└── 内联十六进制检查:│ '8': '0'≤'8'≤'9' ✓│ 'A': 'A'≤'A'≤'F' ✓│ '2': '0'≤'2'≤'9' ✓│ 'E': 'A'≤'E'≤'F' ✓... (其他段类似验证) ...结果:返回 "IPv6"

测试用例3:无效IPv4(前导零)- “192.168.01.1”(优化版演示)

步骤1:初步判断
queryIP = "192.168.01.1"
包含"." ✓ → 进入IPv4验证步骤2:分割并长度检查
parts = ["192", "168", "01", "1"]
parts.length = 4 ✓ → 段数正确,继续验证步骤3:逐段内联验证
part[0] = "192" ✓ (验证通过)
part[1] = "168" ✓ (验证通过)
part[2] = "01"
├── 长度检查: 2 ≤ 3 ✓
├── 前导零检查: 长度>1 且 首字符='0' ✗
└── 立即返回false,无需进行后续计算结果:返回 "Neither"

测试用例4:无效IPv4(超出范围)- “256.256.256.256”(优化版演示)

步骤1:初步判断
queryIP = "256.256.256.256"
包含"." ✓ → 进入IPv4验证步骤2:分割并长度检查
parts = ["256", "256", "256", "256"]
parts.length = 4 ✓ → 段数正确,继续验证步骤3:逐段内联验证
part[0] = "256"
├── 长度检查: 3 ≤ 3 ✓
├── 前导零检查: 首字符'2' ≠ '0' ✓
├── 字符检查: '2','5','6' 全为数字 ✓
└── 数值检查: Integer.parseInt("256") = 256 > 255 ✗结果:返回 "Neither"

测试用例5:无效IPv6(段过长)- “02001:0db8:85a3:0000:0000:8a2e:0370:7334”

步骤1:初步判断
queryIP = "02001:0db8:85a3:0000:0000:8a2e:0370:7334"
不包含"." 但包含":" ✓ → 可能是IPv6步骤2:分割IP
parts = ["02001", "0db8", "85a3", "0000", "0000", "8a2e", "0370", "7334"]
parts.length = 8 ✓ → 段数正确步骤3:逐段验证
part[0] = "02001"
├── 长度检查: 5 > 4 ✗
└── 验证失败!结果:返回 "Neither"

测试用例6:无效格式(非法字符)- “192.168@1.1”

步骤1:初步判断
queryIP = "192.168@1.1"
包含"." ✓ → 可能是IPv4步骤2:分割IP
parts = ["192", "168@1", "1"]
parts.length = 3 ≠ 4 ✗结果:返回 "Neither"

算法复杂度分析

  • 时间复杂度:O(n),其中n是字符串长度。需要遍历整个字符串进行分割和验证
  • 空间复杂度:O(1),除了存储分割后的段数组,不需要额外空间

关键技术点详解

String的isEmpty() vs isBlank()方法对比

在IP验证中,我们经常需要检查字符串是否为空,了解这两个方法的区别很重要:

方法作用Java版本检查内容
isEmpty()检查长度是否为0Java 6+只检查 length() == 0
isBlank()检查是否为空或只有空白字符Java 11+检查 isEmpty() || 全为空白字符
详细对比示例:
String str1 = "";           // 空字符串
String str2 = " ";          // 一个空格
String str3 = "  \t\n ";    // 多个空白字符(空格、制表符、换行符)
String str4 = " a ";        // 包含非空白字符
String str5 = null;         // null值// isEmpty() 结果:
str1.isEmpty()true(长度为0)
str2.isEmpty()false(长度为1)
str3.isEmpty()false(长度为4)
str4.isEmpty()false(长度为3)
// str5.isEmpty() → NullPointerException!// isBlank() 结果 (Java 11+):
str1.isBlank()true(长度为0)
str2.isBlank()true(只有空白字符)
str3.isBlank()true(只有空白字符)
str4.isBlank()false(包含非空白字符)
// str5.isBlank() → NullPointerException!
在IP验证中的应用:
// 检查IP段是否为空的不同方式
private boolean isValidIPv4Part(String part) {// 方式1:直接检查长度(推荐)if (part.length() == 0) return false;// 方式2:使用isEmpty()(等效)if (part.isEmpty()) return false;// 方式3:使用isBlank()(Java 11+,更严格)if (part.isBlank()) return false; // 会拒绝 " " 这样的空格段// ... 其他验证逻辑
}
安全的null检查:
// 推荐的安全检查方式
public static boolean isNullOrEmpty(String str) {return str == null || str.isEmpty();
}public static boolean isNullOrBlank(String str) {return str == null || str.isBlank(); // Java 11+
}

split() 方法的 limit 参数

String[] parts = ip.split("\\.", -1);

split(regex, limit) 中的 limit 参数控制分割行为:

limit值行为示例
limit > 0最多分割成limit个部分"a.b.c".split("\\.", 2)["a", "b.c"]
limit = 0默认行为,移除尾部空字符串"a.b.".split("\\.")["a", "b"]
limit < 0保留所有空字符串(包括尾部)"a.b.".split("\\.", -1)["a", "b", ""]

为什么IP验证必须用 -1

// 测试案例对比
String ip1 = "192.168.1.";     // 末尾多点号
String ip2 = "192..168.1";     // 连续点号// 不使用-1 (默认行为)
ip1.split("\\.")["192", "168", "1"]     // 长度=3,错误!应该是4段
ip2.split("\\.")["192", "", "168", "1"] // 长度=4,但漏掉了空段检测// 使用-1 (正确行为)  
ip1.split("\\.", -1)["192", "168", "1", ""] // 长度=4,能检测到末尾空段
ip2.split("\\.", -1)["192", "", "168", "1"] // 长度=4,能检测到中间空段

代码优化技巧总结

  1. 关键的 split(-1):确保捕获所有边界情况,包括末尾和中间的空段
  2. 长度预判断:直接检查分割后数组长度,不符合直接返回false
  3. 语义化变量命名:使用 int n = part.length() 提高代码可读性
  4. 语义化方法调用:使用 part.startsWith("0") 替代 part.charAt(0) == '0'
  5. 详细的针对性注释:每个检查都注明具体处理的边界情况
  6. 精确的字符范围检查:IPv6手动检查三个字符范围,不使用Character.isDigit()
  7. 清晰的条件表达式:使用 !(num >= 0 && num <= 255) 明确表达范围检查

代码优势对比

优化项传统写法当前实现优势说明
变量命名part.length() 重复调用int n = part.length()提高可读性,减少重复计算
前导零检查part.charAt(0) == '0'part.startsWith("0")语义更清晰,表达意图更直接
注释设计简单功能注释针对性边界情况注释明确每个检查要处理的具体问题
字符范围检查使用库函数或正则手动三范围检查IPv6需求下更精确,避免误判
条件表达式num < 0 || num > 255!(num >= 0 && num <= 255)逻辑更直观,表达"不在范围内"
长度预检查在循环中检查预先检查数组长度提早退出,避免无效处理

常见陷阱

  1. 忘记检查前导零(IPv4)
  2. 未正确处理空段(如连续分隔符)
  3. 字符范围检查不全面(IPv6的大小写字母)
  4. 数值范围检查遗漏边界值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/921496.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/921496.shtml
英文地址,请注明出处:http://en.pswp.cn/news/921496.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新能源研发,用新型实验记录本:ELN

新能源&#xff08;材料&#xff09;研发如火如荼&#xff0c;竞争激烈。以电池为例&#xff0c;新能源汽车的崛起、储能技术的突破&#xff0c;让电池成为了能源领域的“新宠”。电池研发已经成为热门赛场&#xff0c;各研发团队都在与时间赛跑&#xff0c;试图维持优势或弯道…

大语言模型领域最新进展

CSDN大礼包《人工智能大模型课程》 CSDN大礼包《人工智能平台设计开发课程课程》

【网安干货】--计算机网络知识梳理总结(二)

这是计算机网络知识梳理的第二篇&#xff0c;真正去梳理才发现内容好多好多好多好多好多啊…怕是预计要写四篇 注意&#xff1a;如果看不清可以右键复制图片链接到浏览器访问或另存为照片并放大查看 计算机网络2 计算机网络协议2.1 网络协议的定义与核心要素2.1.1 协议的定义2.…

百度前端社招面经二

社招 百度 前端开发 二面 base 北京 react 17 和 18 的差异react的响应式原理&#xff0c;js是如何驱动模块的webpacke 4 和 5 差异webpacke 热更新原理。Tree Shaking 是干嘛的import 和 require 区别&#xff0c;都会被Tree Shaking吗隐藏元素的几种方式三栏布局&#xff0c;…

结合prompt分析NodeRAG的build过程

之前介绍了NodeRAG的节点类型和安装过程。 linux环境conda安装NodeRAG示例-CSDN博客 这里尝试从prompt代码角度分析NodeRAG如何将文档转化为节点、关系。 1 整体处理流程 NodeRAG定义了如下所示状态及处理流程。 # define the state to pipeline mapping self.state_pipelin…

我改写的二分法XML转CSV文件程序速度追上了张泽鹏先生的

以下是美团龙猫初稿&#xff0c;我改正&#xff0c;DeepSeek重新格式化的代码。 重要改正点&#xff1a; 1.二分查找用goto控制迭代&#xff0c;返回<row的正确位置 2.在缓冲区头填上父标签使expat能连续解析不报错 #include <stdio.h> #include <stdlib.h> #in…

使用Docker安装Stirling-PDF(PDF工具)

1、官方Web端 详见&#xff1a;https://stirlingpdf.io/?langzh_CN 2、安装Docker 合集&#xff1a;Docker安装与使用 3、安装Stirling-PDF 详见&#xff1a; https://docs.stirlingpdf.com/Installation/Docker%20Install https://hub.docker.com/r/stirlingtools/stirli…

【开题答辩全过程】以 基于微信小程序的“XIN”学生组织管理系统为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

Iwip驱动8211FS项目——MPSOC实战1

硬件设计采用RTL8211FS芯片&#xff0c;vitis默认的IWIP库不支持此芯片。 网口相关知识可以翻看前期文章 以太网PHY_MDIO通信&#xff08;基于RTL8211&#xff09;--FPGA学习笔记22-CSDN博客 以太网ARP协议——FPGA学习笔记23_fpga以太网学习-CSDN博客 以太网ICMP协议(ping…

《Science》神经炎症综述思路套用:从机制到跨领域研究范式

2025 年 6 月首都医科大学团队在《Science》发表的综述《Immunological dimensions of neurological disease: from mechanisms to therapeutics》(神经疾病的免疫维度:从机制到疗法),系统性解析了神经炎症的动态演变规律与双面性,提出阶段化、精准化治疗新范式。本文基于…

嵌入式学习笔记--Linux系统编程阶段--DAY07进程间通信--存储映射和共享内存

1.存储映射存储映射 I/O (Memory-mapped I/O) 使一个磁盘文件与存储空间中的一个缓冲区相映射。于是当从缓冲区中取数据&#xff0c;就相当于读文件中的相应字节。于此类似&#xff0c;将数据存入缓冲区&#xff0c;则相应的字节就自动写入文件。这样&#xff0c;就可在不适用 …

.Net程序员就业现状以及学习路线图(四)

一、.Net程序员就业现状分析 1. 市场需求与岗位分布 2025年数据显示&#xff0c;.Net开发岗位在全国IT岗位中占比约0.009%&#xff0c;主要集中在一线城市如深圳、上海等地 2 4。行业分布呈现以下特点&#xff1a;‌软件行业‌&#xff1a;占比43.3% ‌研发领域‌&#xff1a;占…

Monorepo 是什么?如何使用并写自己的第三方库

1. 什么是 Monorepo&#xff1f; Monorepo&#xff08;单仓库&#xff09;指的是把多个项目/包放在一个代码仓库里统一管理。常见结构&#xff1a; /repo-root/packages/ui-lib/utils/apps/web-apppackage.jsonpnpm-workspace.yaml好处&#xff1a; 内部库能直接共享&#xff0…

使用CI/CD部署后端项目(gin)

写在前面&#xff1a;使用CI/CD部署gin项目到服务器中 前端可以参考&#xff1a;使用CI/CD部署nextjs项目 使用 GitHub Actions 配置后端 CI/CD&#xff08;含部署到服务器&#xff09; 本文档介绍如何在 GitHub 仓库中配置 CI/CD&#xff0c;将 PROJECT_NAME 项目自动构建并…

Coze添加知识库解析的Embedding和PaddleOCR模型配置

1. Embedding模型配置 使用ollama模型&#xff0c;导入qwen3的embedding-8B模型&#xff0c;导入流程参考&#xff1a; Ollama离线部署模型 qwen3-Embedding模型文件可从魔塔社区下载&#xff1a; Qwen3-Embedding-8B 1.2 Coze配置 在coze_studio/docker目录下输入: vim .en…

02-Media-6-rtsp_server.py 使用RTSP服务器流式传输H264和H265编码视频和音频的示例程序

rtsp_server.py 是使用k230的板载摄像头和WIFI联网功能,使用RTSP服务器流式传输视频和音频的程序示例。程序核心是创建了一个RtspServer类,该类用于初始化、启动、停止RTSP服务器,并进行视频和音频的流传输。 一、首先,程序导入必要的模块,包括视频编码、传感器、媒体处理…

13-Java-面向对象-封装和this关键字

文章目录封装this关键字封装 告诉我们&#xff0c;如何正确设计对象的属性和方法。原则&#xff1a;对象代表什么&#xff0c;就得封装对应的数据&#xff0c;并提供数据对应的行为 package common;/*** Author: 大海* Date: 2025-09-06*/public class GirlFriend {/*private…

三高项目-缓存设计

三高项目-缓存设计 分流、并发 导流&#xff1a;将原本复杂操作的请求&#xff0c;引导到简单的操作上。以后再来查&#xff0c;不需要经过复杂的计算。 成本&#xff1a;空间&#xff0c;收益&#xff1a;节省了时间。 不要以为仅仅是 redis&#xff0c;map等。 对应。kv…

happen-before原则

什么是 happen-before 原则&#xff1f; happen-before 是一个逻辑关系&#xff0c;用于描述两个操作之间的 “先后顺序”—— 如果操作 A happen-before 操作 B&#xff0c;那么 A 的执行结果必须对 B 可见&#xff0c;且 A 的执行顺序在逻辑上先于 B。也就是保证指令有序性和…

4.1 机器学习 - 评估指标

模型评估是判断 “模型是否有效” 的核心环节&#xff0c;需结合任务类型&#xff08;分类 / 回归&#xff09;、数据分布&#xff08;如类别不平衡&#xff09;和商业目标选择指标。本节聚焦分类任务的核心评估指标&#xff0c;从定义、计算逻辑到适用场景逐一拆解&#xff0c…