🧠
Brute Force (Pure Recursion with Backtracking)
💡 This approach exists to build intuition by exploring all possible ways to split the string into four parts, validating each segment. It helps beginners understand the problem structure before optimizing.
Intuition
Try every possible split of the string into four parts by recursively choosing 1 to 3 digits for each segment, checking if each segment is valid, and backtracking if not.
Algorithm
- Start from the beginning of the string and try to take 1, 2, or 3 digits as the current segment.
- Check if the current segment is valid (not leading zero unless single '0', and ≤ 255).
- If valid, recurse to find the next segment until 4 segments are formed.
- If 4 segments are formed and the entire string is consumed, add the formed IP address to results.
💡 The challenge is to systematically try all splits and backtrack when a segment is invalid or when the number of segments exceeds four.
from typing import List
def restore_ip_addresses(s: str) -> List[str]:
res = []
def backtrack(start: int, path: List[str]):
if len(path) == 4:
if start == len(s):
res.append(".".join(path))
return
for length in range(1, 4):
if start + length > len(s):
break
segment = s[start:start+length]
if (segment.startswith('0') and len(segment) > 1) or (length == 3 and int(segment) > 255):
continue
backtrack(start + length, path + [segment])
backtrack(0, [])
return res
# Driver code
if __name__ == "__main__":
test_input = "25525511135"
print(restore_ip_addresses(test_input))
Line Notes
def restore_ip_addresses(s: str) -> List[str]:Defines the main function with input string s and output list of strings
def backtrack(start: int, path: List[str]):Helper recursive function tracking current index and collected segments
if len(path) == 4:Base case: if 4 segments collected, check if entire string is used
if start == len(s):Only add to results if all characters are consumed
for length in range(1, 4):Try segments of length 1 to 3
if (segment.startswith('0') and len(segment) > 1) or (length == 3 and int(segment) > 255):Prune invalid segments early
backtrack(start + length, path + [segment])Recurse with updated start and path
return resReturn all valid IP addresses found
import java.util.*;
public class RestoreIPAddresses {
public static List<String> restoreIpAddresses(String s) {
List<String> res = new ArrayList<>();
backtrack(s, 0, new ArrayList<>(), res);
return res;
}
private static void backtrack(String s, int start, List<String> path, List<String> res) {
if (path.size() == 4) {
if (start == s.length()) {
res.add(String.join(".", path));
}
return;
}
for (int len = 1; len <= 3; len++) {
if (start + len > s.length()) break;
String segment = s.substring(start, start + len);
if ((segment.startsWith("0") && segment.length() > 1) || (len == 3 && Integer.parseInt(segment) > 255)) continue;
path.add(segment);
backtrack(s, start + len, path, res);
path.remove(path.size() - 1);
}
}
public static void main(String[] args) {
String testInput = "25525511135";
System.out.println(restoreIpAddresses(testInput));
}
}
Line Notes
public static List<String> restoreIpAddresses(String s)Main method signature returning list of valid IPs
backtrack(s, 0, new ArrayList<>(), res);Start recursion from index 0 with empty path
if (path.size() == 4)Check if 4 segments collected
if (start == s.length())Add to results only if entire string consumed
for (int len = 1; len <= 3; len++)Try segments of length 1 to 3
if ((segment.startsWith("0") && segment.length() > 1) || (len == 3 && Integer.parseInt(segment) > 255)) continue;Skip invalid segments
path.add(segment);Choose current segment
path.remove(path.size() - 1);Backtrack by removing last segment
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Solution {
public:
vector<string> restoreIpAddresses(string s) {
vector<string> res;
vector<string> path;
backtrack(s, 0, path, res);
return res;
}
private:
void backtrack(const string& s, int start, vector<string>& path, vector<string>& res) {
if (path.size() == 4) {
if (start == s.size()) {
string ip = path[0];
for (int i = 1; i < 4; i++) ip += "." + path[i];
res.push_back(ip);
}
return;
}
for (int len = 1; len <= 3; len++) {
if (start + len > s.size()) break;
string segment = s.substr(start, len);
if ((segment[0] == '0' && segment.size() > 1) || (len == 3 && stoi(segment) > 255)) continue;
path.push_back(segment);
backtrack(s, start + len, path, res);
path.pop_back();
}
}
};
int main() {
Solution sol;
string testInput = "25525511135";
vector<string> result = sol.restoreIpAddresses(testInput);
for (auto& ip : result) cout << ip << endl;
return 0;
}
Line Notes
vector<string> restoreIpAddresses(string s)Main function returning vector of valid IPs
void backtrack(const string& s, int start, vector<string>& path, vector<string>& res)Recursive helper with current index and path
if (path.size() == 4)Base case: 4 segments collected
if (start == s.size())Add IP if entire string consumed
for (int len = 1; len <= 3; len++)Try segments of length 1 to 3
if ((segment[0] == '0' && segment.size() > 1) || (len == 3 && stoi(segment) > 255)) continue;Skip invalid segments
path.push_back(segment);Choose segment
path.pop_back();Backtrack by removing last segment
function restoreIpAddresses(s) {
const res = [];
function backtrack(start, path) {
if (path.length === 4) {
if (start === s.length) {
res.push(path.join('.'));
}
return;
}
for (let len = 1; len <= 3; len++) {
if (start + len > s.length) break;
const segment = s.substring(start, start + len);
if ((segment.startsWith('0') && segment.length > 1) || (len === 3 && Number(segment) > 255)) continue;
backtrack(start + len, [...path, segment]);
}
}
backtrack(0, []);
return res;
}
// Test
console.log(restoreIpAddresses("25525511135"));
Line Notes
function restoreIpAddresses(s)Main function to restore IP addresses
function backtrack(start, path)Recursive helper tracking index and segments
if (path.length === 4)Check if 4 segments collected
if (start === s.length)Add to results if entire string consumed
for (let len = 1; len <= 3; len++)Try segments of length 1 to 3
if ((segment.startsWith('0') && segment.length > 1) || (len === 3 && Number(segment) > 255)) continue;Skip invalid segments
backtrack(start + len, [...path, segment]);Recurse with new segment added
TimeO(3^4) = O(81)
SpaceO(4) for recursion stack and path
At each of the 4 segments, we try up to 3 lengths, so 3^4 combinations. Each segment validation is O(1).
💡 For n=12 (max length), this means at most 81 recursive calls, which is manageable but not efficient for larger inputs.
Interview Verdict: Accepted but not optimal
This approach works and is easy to understand but can be improved by pruning and iterative methods.