给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。

本文深入探讨了一种从字符串中恢复IP地址的算法实现。通过递归回溯的方法,算法能够找出所有可能的有效IP地址组合,并以列表形式返回。文章详细介绍了如何限制IP段的长度和数值范围,确保生成的IP地址格式正确。
package program;



import java.util.ArrayList;
import java.util.List;

/**
 * @Auther: 大哥的叔
 * @Date: 2019/10/8 15:00
 * @Description:
 */
public class IP {

    public static void main (String[] args) {
        IP ip = new IP();
        String s ="25525511135";
        ip.restoreIpAddresses(s);
    }
    public List<String> restoreIpAddresses(String s) {
        List<String> ans = new ArrayList<>();//保存最终的所有结果
        backtrack(s,0,new StringBuilder(),ans,0);
        System.out.println(ans);
        return ans;
    }

    /**
     *
     * @param s 传入的参数
     * @param st 开始的位置
     * @param t 临时存储的划分结果
     * @param ans 保存所有的解
     * @param c 当前加入的部分
     */
    private void backtrack(String s,int st,StringBuilder t,List<String> ans,int c){
        //如果剩余的长度大于剩下的部分都取 3 位数的长度,那么直接结束
        if ( (s.length() - st) > (3*(4 - c))){
            return;
        }
        //当前刚好到达了末尾
        if (st == s.length()){
            if (c == 4) {//加入结果
                ans.add(new String(t.substring(0,t.length()-1)));
            }
            return;
        }
        //当前超过末位,或者已经到达了 4 部分结束掉
        if (st>s.length()||c==4){
            return;
        }
        //保存的当前的解
        StringBuilder builder = new StringBuilder(t);
        //加入1
        t.append(s.charAt(st)+""+'.');
        backtrack(s,st+1,t,ans,c+1);

        if (s.charAt(st)=='0')return;
        //加入2#10 33
        if(st+1<s.length()){
            t = new StringBuilder(builder);
            t.append(s.substring(st,st+2)+""+'.');
            backtrack(s,st+2,t,ans,c+1);
        }
        //加入3 #225
        if(st+2<s.length()){
            t = new StringBuilder(builder);
            int n =Integer.parseInt(s.substring(st,st+3));
            if(n>=0&&n<=255){
            t.append(s.substring(st,st+3)+""+'.');
            backtrack(s,st+3,t,ans,c+1);
            }

        }
    }

}

 

这是一个经典的 **回溯(Backtracking)** 问题:**复原 IP 地址(Restore IP Addresses)**。 我们需要将一个数字字符串分割成 4 段,每段是一个合法的整数(0–255),且满足 IP 地址格式要求。 --- ### ✅ 解题思路 1. **IP 地址要求**: - 分为 4 段:A.B.C.D - 每段是 `0` 到 `255` 的整数 - 不允许有前导零(除非该段就是 `"0"`) - 合法:`"0"`、`"1"`、`"255"` - 非法:`"01"`、`"00"`、`"000"`、`"300"` 2. **约束条件**: - 字符串长度必须在 `[4, 12]` 范围内才有可能构成有效 IP - 使用 **回溯法枚举所有可能的三处切割位置** 3. **算法选择**:使用 DFS 或嵌套循环暴力枚举三处分割点。 由于最多只有 12 个字符,我们可以用三层循环分别确定前三段的结束位置,最后一段自动确定。 --- ### ✅ C++ 实现代码(高效清晰版) ```cpp #include <iostream> #include <vector> #include <string> #include <cctype> using namespace std; // 判断子串是否为合法IP段 bool isValid(const string& s) { if (s.empty() || s.size() > 3) return false; // 前导零:只允许单独一个'0' if (s[0] == '0' && s.size() > 1) return false; // 转换为数字判断范围 int num = stoi(s); return num >= 0 && num <= 255; } // 返回所有有效的IP地址组合 vector<string> restoreIpAddresses(string s) { vector<string> result; int n = s.size(); // 剪枝:长度不在 [4,12] 直接返回空 if (n < 4 || n > 12) return result; // 枚举第一段结束位置(从0开始,长度1~3) for (int i = 1; i <= 3 && i < n; ++i) { string a = s.substr(0, i); if (!isValid(a)) continue; // 枚举第二段结束位置 for (int j = i + 1; j <= i + 3 && j < n; ++j) { string b = s.substr(i, j - i); if (!isValid(b)) continue; // 枚举第三段结束位置 for (int k = j + 1; k <= j + 3 && k < n; ++k) { string c = s.substr(j, k - j); string d = s.substr(k); // 第四段剩余部分 if (!isValid(c)) continue; if (d.empty() || d.size() > 3) continue; if (!isValid(d)) continue; result.push_back(a + "." + b + "." + c + "." + d); } } } return result; } int main() { ios::sync_with_stdio(false); cin.tie(0); int T; cin >> T; while (T--) { string s; cin >> s; vector<string> ips = restoreIpAddresses(s); if (ips.empty()) { cout << "-1\n"; } else { for (const string& ip : ips) { cout << ip << '\n'; } } } return 0; } ``` --- ### 🔍 代码解释 #### `isValid(s)` 函数功能: - 判断一个字符串是否为合法IP 段。 - 条件: 1. 长度不能超过 3; 2. 不能有前导零(除了 `"0"` 本身); 3. 数值在 `0~255` 之间。 #### 主循环结构(三层嵌套): - `i`: 第一段结尾(索引) - `j`: 第二段结尾 - `k`: 第三段结尾 - 剩下的部分作为第四段 `d` 例如:`s = "25525511135"`,当 `i=3,j=6,k=8`: - a = "255", b = "255", c = "11", d = "135" 然后拼接成:`255.255.11.135` #### 输出控制: - 如果结果为空,输出 `-1` - 否则逐行输出每个合法 IP --- ### 📌 样例验证 #### 输入 1: `"25525511135"` 可能的有效划分: - `255.255.11.135` - `255.255.111.35` ✅ 输出正确。 #### 输入 2: `"25505011535"` 尝试解析时会发现: - 如 `255.050...` 中 `"050"` 是非法的(前导零且不是单个0) 最终无任何合法方案 → 输出 `-1` ✅ 完全符合预期! --- ### ⚙️ 复杂度分析 - 时间复杂度:$O(1)$ 因为每段最多取 3 个长度,总共最多 $3^3 = 27$ 种组合,常数级。 - 空间复杂度:$O(1)$ 存储的结果最多也就十几种。 所以即使输入很多也没问题。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值