Taro Logo

Restore IP Addresses

Medium
1 views
a month ago

A valid IP address consists of exactly four integers separated by single dots. Each integer is between 0 and 255 (inclusive) and cannot have leading zeros.

  • For example, "0.1.2.201" and "192.168.1.1" are valid IP addresses, but "0.011.255.245", "192.168.1.312" and "192.168@1.1" are invalid IP addresses.

Given a string s containing only digits, return all possible valid IP addresses that can be formed by inserting dots into s. You are not allowed to reorder or remove any digits in s. You may return the valid IP addresses in any order.

Example 1:

Input: s = "25525511135"
Output: ["255.255.11.135","255.255.111.35"]

Example 2:

Input: s = "0000"
Output: ["0.0.0.0"]

Example 3:

Input: s = "101023"
Output: ["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

Constraints:

  • 1 <= s.length <= 20
  • s consists of digits only.
Sample Answer
def restoreIpAddresses(s):
    def isValid(segment):
        # Check if the segment is between 0 and 255
        # and doesn't have leading zeros (unless it's just "0")
        return 0 <= int(segment) <= 255 and (segment == "0" or not segment.startswith("0"))

    def backtrack(start, dots, currentIP):
        if dots == 4:
            if start == len(s):
                result.append(currentIP[:-1])  # Remove the trailing dot
            return

        for i in range(start, min(start + 3, len(s))):
            segment = s[start:i + 1]
            if isValid(segment):
                backtrack(i + 1, dots + 1, currentIP + segment + ".")

    result = []
    backtrack(0, 0, "")
    return result

# Example usage:
s = "25525511135"
print(restoreIpAddresses(s))

s = "0000"
print(restoreIpAddresses(s))

s = "101023"
print(restoreIpAddresses(s))

# Edge Cases
s = ""
print(restoreIpAddresses(s))

s = "11111111111111111111111111111"
print(restoreIpAddresses(s))

s = "010010"
print(restoreIpAddresses(s))

Explanation:

This code implements a backtracking algorithm to find all possible valid IP addresses that can be formed from a given string s. Here's a breakdown of how it works:

  1. restoreIpAddresses(s) Function:

    • This is the main function that takes the input string s and returns a list of valid IP addresses.
    • It initializes an empty list called result to store the valid IP addresses.
    • It calls the backtrack helper function to generate IP addresses recursively.
    • Finally, it returns the result list.
  2. isValid(segment) Function:

    • This helper function checks if a given segment of the string is a valid IP address segment.
    • It returns True if the segment meets the following conditions:
      • The segment is an integer between 0 and 255 (inclusive).
      • The segment does not have leading zeros, unless it is just "0".
  3. backtrack(start, dots, currentIP) Function:

    • This is a recursive helper function that generates IP addresses using backtracking.
    • start: The starting index of the remaining part of the string s to process.
    • dots: The number of dots already placed in the currentIP.
    • currentIP: The current IP address being built.
    • Base Case: If dots is 4, it means we have placed 3 dots and formed 4 segments. If start is also equal to the length of s, it means we have used all the digits in s and formed a valid IP address. In this case, we add the currentIP (without the trailing dot) to the result list.
    • Recursive Step:
      • It iterates through possible segment lengths (1, 2, or 3) from the start index.
      • For each possible segment, it checks if it's a valid segment using the isValid function.
      • If the segment is valid, it recursively calls backtrack with the updated start index, dots count, and the currentIP with the new segment added.

Naive Solution:

A naive solution would involve generating all possible combinations of inserting three dots into the string s and then checking if each combination forms a valid IP address. This would involve a lot of redundant calculations and checks, making it inefficient.

Optimal Solution:

The provided code represents the optimal solution, which uses backtracking to efficiently explore the possible IP address combinations while pruning invalid branches early on. Backtracking is a general algorithm for finding all (or some) solutions to some computational problems, notably constraint satisfaction problems, that incrementally builds candidates to the solutions, and abandons a candidate ("backtracks") as soon as it determines that the candidate cannot possibly be completed to a valid solution.

Big(O) Runtime Analysis:

The time complexity is difficult to precisely determine due to the constraints imposed by IP address validity. However, we can analyze the factors influencing it:

  • String Length: Let n be the length of the input string s.
  • Looping within Backtrack: The backtrack function iterates through at most three possibilities (segment lengths of 1, 2, or 3).
  • Maximum Recursive Depth: The recursion depth is fixed at 4 (for the four segments of an IP address).
  • isValid Function: This function takes O(1) time because the segment length is at most 3.

In the worst-case scenario (e.g., "111111111111"), the algorithm explores numerous paths but is bounded by the IP address structure. A loose upper bound is O(3^4) = O(81), but since not all paths are valid, this is an overestimate. A more accurate consideration gives a time complexity closer to O(1), but in reality, it depends on the input string. Thus, O(1) describes it best, considering practical input constraints.

Big(O) Space Analysis:

  • Result List: The space required to store the result (valid IP addresses).
  • Recursion Stack: The space used by the recursion stack during the backtrack calls.

The recursion depth is limited to 4, so the recursion stack takes O(1) space. The number of valid IP addresses can vary but is limited by the input string length. Thus, in the worst case, the space complexity to store all the results is O(1), considering that the number of valid IP addresses is limited by the length of the input string and is not unbounded. Therefore, space complexity is O(1).

Edge Cases:

  • Empty String: If the input string is empty, the algorithm should return an empty list.
  • String Length > 12: If the string length is greater than 12, it's impossible to form a valid IP address (since each segment can have at most 3 digits, and an IP address has 4 segments, so 4 * 3 = 12).
  • Leading Zeros: IP address segments cannot have leading zeros, except for the segment "0".
  • Invalid Segments: Each segment must be between 0 and 255 (inclusive).
  • String with Non-Digit Characters: The string should contain only digits. If it contains any other characters, it cannot form a valid IP address.
  • "010010": This case can produce outputs like ['0.10.0.10', '0.100.1.0'] and tests the condition that leading zeros are not allowed. Testing for this input confirms that it works correctly.