93. Restore IP Addresses - Explanation
Description
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.
You are 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 = "101023"
Output: ["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]Example 2:
Input: s = "010010"
Output: ["0.10.0.10","0.100.1.0"]Constraints:
1 <= s.length <= 20sconsists of digits only.
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- Backtracking - Exploring all possible combinations by making choices and undoing them when they lead to invalid solutions
- Recursion - Breaking down the problem into smaller subproblems (placing one IP segment at a time)
- String Manipulation - Extracting and validating substrings for IP segment constraints
1. Backtracking
Intuition
A valid IP address has exactly four segments, each containing 1 to 3 digits with a value between 0 and 255. Leading zeros are not allowed except for the segment "0" itself. Backtracking lets us explore all possible ways to place three dots in the string. At each step, we try taking 1, 2, or 3 characters for the current segment, validate it, and recurse for the remaining segments.
Algorithm
- If the string length exceeds 12, return an empty list (maximum valid length is 12 digits).
- Define a recursive function that tracks the current position
i, number of segments placeddots, and the IP being builtcurIP. - Base case: if 4 segments are placed and we have consumed the entire string, add the IP to results.
- For each call, try segment lengths of 1, 2, and 3 characters starting at the current position.
- Skip segments with leading zeros (unless the segment is just "0") and values >= 256.
- Recurse with the next position, incremented segment count, and updated IP string.
- Return all valid IP addresses found.
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
res = []
if len(s) > 12:
return res
def backtrack(i, dots, curIP):
if dots == 4 and i == len(s):
res.append(curIP[:-1])
return
if dots > 4:
return
for j in range(i, min(i + 3, len(s))):
if i != j and s[i] == "0":
continue
if int(s[i: j + 1]) < 256:
backtrack(j + 1, dots + 1, curIP + s[i: j + 1] + ".")
backtrack(0, 0, "")
return resTime & Space Complexity
- Time complexity:
- Space complexity:
Where is equals to as there are at most three digits in a valid segment and is equals to as there are four segments in a valid IP.
2. Iteration
Intuition
Since there are exactly four segments and each can have 1, 2, or 3 characters, we can enumerate all 81 combinations (3^4) of segment lengths directly. For each combination, we check if the total length matches the input string and whether each resulting segment is valid. This avoids recursion overhead while still exploring all possibilities.
Algorithm
- If the string length exceeds 12, return an empty list.
- Use four nested loops, each iterating from 1 to 3 (representing segment lengths
seg1,seg2,seg3,seg4). - If the sum of all four segment lengths does not equal the string length, skip this combination.
- Extract the four substrings based on the current segment lengths.
- Validate each segment: no leading zeros (unless single digit) and value <= 255.
- If all segments are valid, join them with dots and add to
res. - Return all valid IP addresses found.
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
res = []
if len(s) > 12:
return res
def valid(num):
return len(num) == 1 or (int(num) < 256 and num[0] != "0")
def add(s1, s2, s3, s4):
if s1 + s2 + s3 + s4 != len(s):
return
num1 = s[:s1]
num2 = s[s1:s1+s2]
num3 = s[s1+s2:s1+s2+s3]
num4 = s[s1+s2+s3:]
if valid(num1) and valid(num2) and valid(num3) and valid(num4):
res.append(num1 + "." + num2 + "." + num3 + "." + num4)
for seg1 in range(1, 4):
for seg2 in range(1, 4):
for seg3 in range(1, 4):
for seg4 in range(1, 4):
add(seg1, seg2, seg3, seg4)
return resTime & Space Complexity
- Time complexity:
- Space complexity:
Where is equals to as there are at most three digits in a valid segment and is equals to as there are four segments in a valid IP.
Common Pitfalls
Allowing Leading Zeros in Multi-Digit Segments
Segments like "01" or "001" are invalid in IP addresses, but "0" alone is valid. The validation must specifically reject multi-digit segments that start with zero while accepting single-digit zeros.
Missing the Upper Bound Check for Segment Values
Each segment must be at most 255. Forgetting to check this constraint or using < 256 instead of <= 255 can lead to subtle bugs, especially for three-digit segments like "256" which appear valid at first glance.
Not Validating Total String Length Early
An IP address can have at most 12 digits (four segments of 3 digits each) and at least 4 digits (four segments of 1 digit each). Failing to check these bounds upfront leads to unnecessary computation on inputs that cannot possibly form valid IPs.
Sign in to join the discussion