leetcode--93 复原IP地址

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

示例:

输入: "25525511135"
输出:["255.255.11.135", "255.255.111.35"]

首先介绍下IPv4地址:

IPv4 地址由十进制数和点来表示,每个地址由4个十进制数组成,其范围为 0 - 255, 用(".")分割。比如,172.16.254.1

同时注意,IPv4 地址内的数不会以 0 开头。比如,地址 172.16.254.01 是不合法的。

 

解题思路:

1. 暴力搜索:由于每个地址由4个0-255的十进制数组成,可以嵌套4个for循环,每个变量范围为[1, 3],当四个变量的和恰好

等于输入字符串的长度时,即初步找到了四个合适的十进制数,然后判断这四个数是否满足IPv4地址的要求:值域[0, 255],不以0开头。

2. 回溯法:从0开始遍历输入字符串s,当其对应的整型数有效时,进入递归过程,即用同样的方法处理剩下的字符串。

 

回溯法思路的简单描述是:把问题的解空间转化成了图或者树的结构表示,然后使用深度优先搜索策略进行遍历,遍历的过程中记录和寻找所有可行解或者最优解。

基本思想类同于:图的深度优先搜索, 二叉树的后序遍历

 

一 1. 回溯法的详细描述

        详细的描述则为:

        回溯法按深度优先策略搜索问题的解空间树。首先从根节点出发搜索解空间树,当算法搜索至解空间树的某一节点时,先利用剪枝函数判断该节点是否可行(即能得到问题的解)。如果不可行,则跳过对该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索。

        回溯法的基本行为是搜索,搜索过程使用剪枝函数来为了避免无效的搜索。剪枝函数包括两类:1. 使用约束函数,剪去不满足约束条件的路径;2.使用限界函数,剪去不能得到最优解的路径。

        问题的关键在于如何定义问题的解空间,转化成树(即解空间树)。解空间树分为两种:子集树和排列树。两种在算法结构和思路上大体相同。

2. 回溯法应用

       当问题是要求满足某种性质(约束条件)的所有解或最优解时,往往使用回溯法。

       它有“通用解题法”之美誉。

二. 回溯法实现 - 递归和递推(迭代)                               

        回溯法的实现方法有两种:递归和递推(也称迭代)。一般来说,一个问题两种方法都可以实现,只是在算法效率和设计复杂度上有区别。
      【类比于图深度遍历的递归实现和非递归(递推)实现】

 

具体代码:

递推实现:
class Solution {

public:

    vector<string> restoreIpAddresses(string s) {

        vector<string> result;

        string oneResult;

        for(int i=1;i<=3;++i)

            for(int j=1;j<=3;++j)

                for(int m=1;m<=3;++m)

                    for(int n=1;n<=3;++n)

                    {

                        if(i+j+m+n==s.size()){

                           int addres1=stoi(s.substr(0,i));

                           int addres2=stoi(s.substr(i,j));

                           int addres3=stoi(s.substr(i+j,m));

                           int addres4=stoi(s.substr(i+j+m,n));

                           if(addres1<=255&&addres2<=255&&addres3<=255&&addres4<=255){
                                oneResult = to_string(addres1)+'.'+to_string(addres2)+'.'+to_string(addres3)+'.'+to_string(addres4);
                                if(oneResult.size()==3 + s.size()){

                                   result.push_back(oneResult);

                                }

                           }

                        }

                    }

        return result;

    }

};

下面给出迭代搜索法的测试结果:

 

递归法:

class Solution {
public:
    bool isValid93(string s)
    {
        int num = atoi(s.c_str());
        if (num >= 0 && num <= 255 && to_string(num) == s) //to_string(num) == s用来判断字符串首位是否为0
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    void dfs93(string s, int times, string tmp, vector<string>& result)
    {
        if (times == 0)
        {
            if (s.empty())
            {
                result.push_back(tmp);
            }
        }
        else
        {
            for (int i = 1; i <= 3; i++)
            {
                if (s.size() >= i && isValid93(s.substr(0, i)))
                {
                    if (times == 1)
                    {
                        dfs93(s.substr(i), times - 1, tmp + s.substr(0, i), result);
                    }
                    else
                    {
                        dfs93(s.substr(i), times - 1, tmp + s.substr(0, i) + ".", result);
                    }
                }
            }
        }

    }

    vector<string> restoreIpAddresses(string s) {
        vector<string> result;
        int n = s.size();
        dfs93(s, 4, "", result);
        return result;
    }

};

下面给出测试结果:

                       

 

总结:通过对比时间和空间的消耗,能够发现迭代算法的效率要高于递归,但递归算法看起来要更简单些

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值