回溯算法之复原IP地址

回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

百度百科说的有点晦涩,就是递归算法,但是有要注意的点:

  • 保留现场,在进行递归的时候,保存上一次的状态,递归回来之后仍然能回到上次的状态
  • 结束条件,满足条件的时候保存结果

题目

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

示例:

输入: "25525511135"
输出: ["255.255.11.135", "255.255.111.35"]
复制代码

解答

我做的算法题不多,但是个人经验,在做题的时候最好能手动的在纸上画图,模拟程序运行的图。

  • 一张大白纸
  • 认真的画图

不过也可能再电脑上画图会更方便,我们先思考程序的运行大致应该是什么路径。如图:

限定条件:

  • 因为是IP地址,所以有一定的条件限制,数字不能大于255,不能小于0
  • 在图上可以看出来,得出是否是IP地址的在第3层。
  1. 先想到大概的变量。
  • 层级
  • 当前的字符串
  • 剩余的字符串
  • 保存结果的集合
  1. 写出终止递归的条件
private void restoreAddressNew(String source, String currentStr, Integer currentLevel, Integer offset, List<String> res) {
	if (currentLevel == 3) {
            if (isValidNew(source.substring(offset))
                    ) {
                res.add(currentStr + "." + source.substring(offset));
            }
            return;
     }
     ....
}        
复制代码
  1. 写出校验是否合法IP中段位的函数
    private boolean isValidNew(String str) {
        if (str.length() == 0 || str.length() > 3 || Integer.parseInt(str) < 0 || Integer.parseInt(str) > 255
                || (str.startsWith("0") && str.length() > 1)
                ) {
            return false;
        }
        return true;
    }
复制代码
  1. 写进行递归的条件
private void restoreAddressNew(String source, String currentStr, Integer currentLevel, Integer offset, List<String> res) {
        if (currentLevel == 3) {

            if (isValidNew(source.substring(offset))
                    ) {
                res.add(currentStr + "." + source.substring(offset));
            }
            return;
        }

    	// 递归段
        for (int i = 1; i <= 3; i++) {
            if (offset > source.length() || (offset + i) > source.length()) {
                return;
            }
            String seg = source.substring(offset, offset + i);
            // 用于保存原先的状态
            String oldStr = currentStr;
            
            // 防止出现以 "."开头的地址
            if (currentStr.length() == 0) {
                currentStr = seg;
            } else {
                currentStr = currentStr + "." + seg;
            }
            if (isValidNew(seg)) {
                restoreAddressNew(source, currentStr, currentLevel + 1, offset + i, res);
                // 处理完之后恢复状态
                currentStr = oldStr;
            }
        }
    }
复制代码
  1. 如果有不确定的地方,在其中可以输出当前的状态,判断当前的结果
  2. 完整的方案
public class RestoreIPAddress {

    public static void main(String[] args) {
        List<String> strings = new RestoreIPAddress().restoreIpAddressesNew("25525511135");
    }

    private List<String> restoreIpAddressesNew(String s) {
        List<String> result = new ArrayList<>();
        restoreAddressNew(s, "", 0, 0, result);
        return result;
    }

    
    private void restoreAddressNew(String source, String currentStr, Integer currentLevel, Integer offset, List<String> res) {
        if (currentLevel == 3) {

            if (isValidNew(source.substring(offset))
                    ) {
                res.add(currentStr + "." + source.substring(offset));

            }
            return;
        }

        for (int i = 1; i <= 3; i++) {
            if (offset > source.length() || (offset + i) > source.length()) {
                return;
            }
            String seg = source.substring(offset, offset + i);
            String oldStr = currentStr;
            if (currentStr.length() == 0) {
                currentStr = seg;
            } else {
                currentStr = currentStr + "." + seg;
            }
            if (isValidNew(seg)) {
                restoreAddressNew(source, currentStr, currentLevel + 1, offset + i, res);
                currentStr = oldStr;
            }
        }
    }

    private boolean isValidNew(String str) {
        if (str.length() == 0 || str.length() > 3 || Integer.parseInt(str) < 0 || Integer.parseInt(str) > 255
                || (str.startsWith("0") && str.length() > 1)
                ) {
            return false;
        }
        return true;
    }
    
}

复制代码

中间犯的错误

  • 第一次忘了保存现场,就会出现”数据打架“,数据很奇怪
  • 出现过"."开头的地址情况

都是想问题不够全面导致的,程序运行的快,人算的慢,但是程序运行的规则是人定义的。只有自己能想清楚规则,才能指导计算机做正确的事情,否则当自己都迷糊的时候,程序怎么可能运行的正确。

最后

画图是的个好东西,帮你理清思路,慢慢来,不要着急

参考

转载于:https://juejin.im/post/5c903fe35188252da5594fa9

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值