【字符串】BM85 验证IP地址

一、题目

牛客题目链接验证IP地址_牛客题霸_牛客网

LeeCode 题目链接:468. 验证IP地址 - 力扣(LeetCode)

题目描述:

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

有效的IPv4地址 是 “x1.x2.x3.x4” 形式的IP地址。 其中 0 <= xi <= 255 且 xi 不能包含 前导零。例如: “192.168.1.1” 、 “192.168.1.0” 为有效IPv4地址, “192.168.01.1” 为无效IPv4地址; “192.168.1.00” 、 “192.168@1.1” 为无效IPv4地址。

一个有效的IPv6地址 是一个格式为“x1:x2:x3:x4:x5:x6:x7:x8” 的IP地址,其中:

  • 1 <= xi.length <= 4
  • xi 是一个 十六进制字符串 ,可以包含数字、小写英文字母( 'a' 到 'f' )和大写英文字母( 'A' 到 'F' )。
  • 在 xi 中允许前导零。

如 "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 地址。

示例 1:

输入:queryIP = "172.16.254.1"

输出:"IPv4"

解释:有效的 IPv4 地址,返回 "IPv4"

示例 2:

输入:queryIP = "2001:0db8:85a3:0:0:8A2E:0370:7334"

输出:"IPv6"

解释:有效的 IPv6 地址,返回 "IPv6"

示例 3:

输入:queryIP = "256.256.256.256"

输出:"Neither"

解释:既不是 IPv4 地址,又不是 IPv6 地址

提示:

  • queryIP 仅由英文字母,数字,字符 '.' 和 ':' 组成。

二、解题思路&代码实现

方法一:分割字符串比较法(推荐使用)

思路:

先对IP字符串进行分割,然后依次判断每个分割是否符合要求。

具体做法:

  • step 1:写一个分割函数split(或者内置函数)。
  • step 2:遍历IP字符串,遇到.或者:将其分开储存在一个数组中。
  • step 3:遍历数组,对于IPv4,需要依次验证分组为4,分割不能缺省,没有前缀0或者其他字符,数字在0-255范围内。
  • step 4:对于IPv6,需要依次验证分组为8,分割不能缺省,每组不能超过4位,不能出现除数字小大写a-f以外的字符。

复杂度分析:

  • 时间复杂度:O(n),n为字符串IP的长度,判断部分只遍历4组或者8组,但是分割字符串需要遍历全部
  • 空间复杂度:O(1),储存分割字符串的临时空间为常数4或者8。

代码实现:

java:

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 验证IP地址
     * @param IP string字符串 一个IP地址字符串
     * @return string字符串
     */
    public String solve (String IP) {
        // write code here
        if (isIPv4(IP)) {
            return "IPv4";
        } else if (isIPv6(IP)) {
            return "IPv6";
        } else {
            return "Neither";
        }
    }

    boolean isIPv4(String IP) {
        if (IP.indexOf('.') == -1) {
            return false;
        }
        String[] s = IP.split("\\.");
        //IPv4 必定为4组
        if (s.length != 4) {
            return false;
        }
        for (int i = 0; i < s.length; i++) {
            //1.有一个分割为0,说明两个点相连
            if (s[i].length() == 0) {
                return false;
            }
            //2.比较数字位数及不为0时不能有前缀零
            if (s[i].length() < 0 || s[i].length() > 3 || (s[i].charAt(0) == '0' &&
                    s[i].length() != 1)) {
                return false;
            }
            int num = 0;
            //3.遍历每个分割字符串,必须为数字
            for (int j = 0; j < s[i].length(); j++) {
                char c = s[i].charAt(j);
                if (c < '0' || c > '9') {
                    return false;
                }
            }
            //4.转为为数字比较,0-255 之间
            num = Integer.parseInt(s[i]);
            if (num < 0 || num > 255) {
                return false;
            }
        }
        return true;
    }
    boolean isIPv6(String IP) {
        if (IP.indexOf(':') == -1) {
            return false;
        }
        String[] s = IP.split(":", -1);
        //IPv6 必定为8组
        if (s.length != 8) {
            return false;
        }
        for (int i = 0; i < s.length; i++) {
            //1.每个分割不能拆过4位
            if (s[i].length() == 0 || s[i].length() > 4) {
                return false;
            }

            //2.不能出现a-fA-F以外的大小写字符
            for (int j = 0; j < s[i].length(); j++) {
                char c = s[i].charAt(j);
                boolean expr = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' &&
                               c <= 'F');
                if (!expr) {
                    return false;
                }
            }
        }
        return true;
    }
}

 php 实现:

<?php

class Solution {
    /**
     * 验证 IP 地址
     * @param string $IP 一个 IP 地址字符串
     * @return string "IPv4", "IPv6" 或 "Neither"
     */
    public function solve(string $IP): string {
        if ($this->isIPv4($IP)) {
            return "IPv4";
        } elseif ($this->isIPv6($IP)) {
            return "IPv6";
        } else {
            return "Neither";
        }
    }

    private function isIPv4(string $ip): bool {
        // 必须包含点号
        if (strpos($ip, '.') === false) {
            return false;
        }

        $parts = explode('.', $ip);
        // 必须正好是4个部分
        if (count($parts) !== 4) {
            return false;
        }

        foreach ($parts as $part) {
            // 不能是空字符串
            if ($part === '') {
                return false;
            }

            // 长度必须在1~3之间
            if (strlen($part) < 1 || strlen($part) > 3) {
                return false;
            }

            // 如果长度大于1,不能以0开头
            if (strlen($part) > 1 && $part[0] === '0') {
                return false;
            }

            // 必须全部是数字字符
            if (!ctype_digit($part)) {
                return false;
            }

            // 转换为整数并检查范围
            $num = intval($part);
            if ($num < 0 || $num > 255) {
                return false;
            }
        }

        return true;
    }

    private function isIPv6(string $ip): bool {
        // 必须包含冒号
        if (strpos($ip, ':') === false) {
            return false;
        }

        $parts = explode(':', $ip);
        // 必须正好是8个部分
        if (count($parts) !== 8) {
            return false;
        }

        foreach ($parts as $part) {
            // 每个部分不能为空或超过4个字符
            if ($part === '' || strlen($part) > 4) {
                return false;
            }

            // 检查每个字符是否为合法的十六进制字符
            for ($i = 0; $i < strlen($part); $i++) {
                $c = $part[$i];
                if (!(($c >= '0' && $c <= '9') ||
                      ($c >= 'a' && $c <= 'f') ||
                      ($c >= 'A' && $c <= 'F'))) {
                    return false;
                }
            }
        }

        return true;
    }
}
方法二:正则表达式(扩展思路)

思路:

IP地址是有规律可言的:IPv4用了4个0-255的数字,用点隔开,IPv6用了4位十六进制的数字,用冒号隔开,共8组,这都可以直接用正则表达式来表示。

具体做法:

  • step 1:IPv4的正则表达式限制数字在0-255,且没有前缀0,用3个点隔开共4组。
  • step 2:IPv6的正则表达式限制出现8组,0-9a-fA-F的数,个数必须是1-4个,用冒号隔开。
  • step 3:调用函数依次比较给定字符串与模板串之间是否匹配,匹配哪一个就属于哪一种IP地址,否则都不是。

复杂度分析:

  • 时间复杂度:O(n),regex_match函数默认O(n)。
  • 空间复杂度:O(1),没有使用额外空间。

代码实现:

java:

import java.util.*;
import java.util.regex.Pattern;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 验证IP地址
     * @param IP string字符串 一个IP地址字符串
     * @return string字符串
     */
    public String solve (String IP) {
        //正则表达式限制0-255 且没有前缀0 四组齐全
        String ipv4 =
            "(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])";
        Pattern ipv4_pattern = Pattern.compile(ipv4);

        //正则表达式限制出现8组,0-9a-fA-F的数,个数必须是1-4个
        String ipv6 = "([0-9a-fA-F]{1,4}\\:){7}[0-9a-fA-F]{1,4}";
        Pattern ipv6_pattern = Pattern.compile(ipv6);

        //调用正则匹配函数
        if (ipv4_pattern.matcher(IP).matches())
            return "IPv4";
        else if (ipv6_pattern.matcher(IP).matches())
            return "IPv6";
        else return "Neither";
    }


}

php :

<?php

class Solution {
    /**
     * 验证 IP 地址
     * @param string $IP 一个 IP 地址字符串
     * @return string "IPv4", "IPv6" 或 "Neither"
     */
    public function solve(string $IP): string {
        // IPv4 正则:匹配0~255之间的数字,不能有前导0(除非是0本身),共4组
        $ipv4Pattern = '/^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])$/';

        // IPv6 正则:匹配8组,每组1~4个十六进制字符(0-9a-fA-F)
        $ipv6Pattern = '/^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/i';

        if (preg_match($ipv4Pattern, $IP)) {
            return "IPv4";
        } elseif (preg_match($ipv6Pattern, $IP)) {
            return "IPv6";
        } else {
            return "Neither";
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值