春江暮客

春江暮客的个人学习分享网站

Python3 Solution to LeetCode Medium Problem 468: Validate IP Address

2020-07-29 Technology
Python3 Solution to LeetCode Medium Problem 468: Validate IP Address

This article breaks down a classic string-validation problem from LeetCode: determine whether an input is a valid IPv4 address, a valid IPv6 address, or neither.

What makes this problem useful is that it is not only about knowing IP formats. It also tests whether you can separate what the Python standard library accepts from what the problem statement explicitly requires.

Problem link: LeetCode
The article is divided into several parts:

  • Problem description
  • Official examples
  • Thought process and solution methods

Problem Description

  1. Validate IP Address

Write a function to determine if a given input string is a valid IPv4 or IPv6 address.

An IPv4 address is represented in decimal format separated by dots, consisting of 4 decimal numbers ranging from 0 to 255, separated by “.” For example, 172.16.254.1;
Also, numbers in IPv4 cannot start with 0. For example, the address 172.16.254.01 is invalid.

An IPv6 address is represented by 8 groups of hexadecimal numbers, each group representing 16 bits. These groups are separated by “:”. For example, 2001:0db8:85a3:0000:0000:8a2e:0370:7334 is a valid address.
Leading zeros can be omitted, and letters can be uppercase or lowercase. Thus, 2001:db8:85a3:0:0:8A2E:0370:7334 is also a valid IPv6 address (i.e., ignoring leading zeros and case).

However, empty groups cannot be used to represent zero values in IPv6 such that “::” appears. For example, 2001:0db8:85a3::8A2E:0370:7334 is invalid.

Also, extra leading zeros are not allowed in IPv6 groups. For example, 02001:0db8:85a3:0000:0000:8a2e:0370:7334 is invalid.

Note: You may assume there are no extra spaces or special characters in the given string.

Official Examples

Example 1

Input: “172.16.254.1”

Output: “IPv4”

Explanation: This is a valid IPv4 address, so return “IPv4”.

Example 2

Input: “2001:0db8:85a3:0:0:8A2E:0370:7334”

Output: “IPv6”

Explanation: This is a valid IPv6 address, so return “IPv6”.

Example 3

Input: “256.256.256.256”

Output: “Neither”

Explanation: This address is neither a valid IPv4 nor IPv6 address.

Thought Process and Solution Method

The most straightforward method is to directly use Python’s built-in package for IP addresses: ipaddress
This package is designed to handle IPv4 and IPv6 addresses, very convenient for subnet and related operations. Since the problem requires verifying if the input is a valid IPv4 or IPv6, the ipaddress.ip_address method can easily solve this problem. See the official description:

'''
ipaddress.ip_address(address)
Return an IPv4Address or IPv6Address object depending on the IP address passed as argument. Either IPv4 or IPv6 addresses may be supplied; integers less than 2**32 will be considered to be IPv4 by default. A ValueError is raised if address does not represent a valid IPv4 or IPv6 address.

Simply put:  
Given an IP address string, this returns an IPv4 or IPv6 object. If invalid, raises ValueError.

>>>  
ipaddress.ip_address('192.168.0.1')  
IPv4Address('192.168.0.1')  
ipaddress.ip_address('2001:db8::')  
IPv6Address('2001:db8::')  
'''

So the validation code might be:

import ipaddress

class Solution:
    def validIPAddress(self, IP: str) -> str:
        try:
            addtype = type(ipaddress.ip_address(IP))
            if addtype == ipaddress.IPv4Address:
                return "IPv4"
            return "IPv6"

        except ValueError:
            return "Neither"

However, submission reveals an important mismatch: the standard library behavior is not exactly the same as the rules enforced by this LeetCode problem. For example:

01.01.01.01

should return Neither here, because the problem explicitly says IPv4 segments cannot contain leading zeros.

“IPv4 numbers cannot start with 0”

So the safer approach is:

  1. Use ipaddress to identify the broad address type
  2. Add the extra problem-specific checks manually

In other words, this is not a failure of ipaddress itself. The challenge is that the judge uses stricter rules than a simple standard-library pass.

Here is the adjusted code:

import ipaddress

class Solution:
    def validIPAddress(self, IP: str) -> str:
        try:
            addtype = type(ipaddress.ip_address(IP))
            if addtype == ipaddress.IPv4Address:
                for part in IP.split("."):
                    if len(part) > 1 and part[0] == "0":
                        return "Neither"
                return "IPv4"

            parts = IP.split(":")
            for part in parts:
                if len(part) > 4 or part == '':
                    return "Neither"
            return "IPv6"

        except ValueError:
            return "Neither"

After multiple debugging attempts, this code finally passes the tests.

Runtime: 40ms, Memory usage: 13.9MB

The most common mistakes in this problem

If you implement the solution yourself, the most frequent mistakes are usually:

  1. Forgetting to reject leading zeros in IPv4
  2. Forgetting to reject empty IPv6 groups
  3. Treating the standard-library result as the final answer without adding the problem’s extra restrictions

Summary

In fact, the ipaddress package can solve the problem directly, but since the problem adds some extra constraints, it adds some difficulty. Just fix errors step by step based on test feedback. Also, learning the ipaddress package is very useful for handling network addresses.

友情链接

其它