leetcode 第751题:将IP地址转化为CIDR的C++实现

       上周报名leetcode一周一次的contest,但没注意是限时一个半小时内做完,误了时间。尽管如此,还是尝试去做了constest中的四道题。第一题很简单,第二题就是751题,即将一个IP地址转化为CIDR。

       以题目所给例子为例。参数中给出的IP是“255.0.0.7”,要涵盖的地址数目是10。“255.0.0.7”转化成二进制表示法就是“11111111.00000000.00000000.00000111”。所谓涵盖10个地址,就是将包括“255.0.0.7”在内的后10个地址统一用起始地址+前缀的方法表示。“11111111.00000000.00000000.00000111”末位为1,没有0存在,只能用其表示2^0=1个地址,用“255.0.0.7/32”表达,其中32表示前缀长度;下一个地址“255.0.0.8”的二进制表达是“11111111.00000000.00000000.00001000”,末位包括3个0,足够表示2^3,即8个地址,此时前缀长度为32-3=29,故最终的表达式为“255.0.0.8/29”;此时,还剩下10-1-8=1个地址需要覆盖,而在涵盖过上8个地址之后,下一地址“255.0.0.16”的二进制表达是“11111111.00000000.00000000.00010000”,再容纳1个地址绰绰有余,因此此时前缀长度变为32,相应表达式就是“255.0.0.16/32”。最终的结果就是字符串数组[“255.0.0.7/32”“255.0.0.8/29”“255.0.0.16/32”]。

       具体的C++解法如下所示:

class Solution {
public:
    string swt(string ip){ 
        string ret;
        int leng=ip.size(),i=0,multiplier=1,res=0;
        while(i<leng)
        {
            char c=ip[leng-i-1];
            int s=c-'0';           //转换成数字res
            res+=s*multiplier;
            multiplier*=10;
            i++;
        }
        int k=0,remain=res;
        while((int)(pow(2.0,k*1.0))<=res) k++;          //需要用k位加以表示
        int p=8-k;                        //不足8位之处用0填满
        while(p>0) { ret+='0'; p--; }
        while(k>0)
        {
            int cmp=(int)(pow(2.0,k*1.0-1));
            if(remain>=cmp) { ret+='1'; remain-=cmp; } 
            else ret+='0';
            k--;
        }
        return ret;
    }   
    string convert(string ip){
        string res="";
        int p1,p2,p3,leng=ip.length();
        string temp,tp;
        p1=ip.find('.');          //找第一个下标点的位置
        temp=ip.substr(0,p1);          //取第一个地址的字符串表达
        tp=swt(temp);
        res+=tp; res+='.';
        p2=ip.find('.',p1+1);           //找第二个下标点的位置
        temp=ip.substr(p1+1,p2-p1-1);          //取第二个地址的字符串表达
        tp=swt(temp);
        res+=tp; res+='.';
        p3=ip.find('.',p2+1);           //找第三个下标点的位置
        temp=ip.substr(p2+1,p3-p2-1);          //取第三个地址的字符串表达
        tp=swt(temp);
        res+=tp; res+='.';
        temp=ip.substr(p3+1,leng-p3-1);          //取最后一个地址的字符串表达
        tp=swt(temp);
        res+=tp;
        return res;
    }
    string change(string rr,int number)           //字符串相加
    {
        int p1,p2,p3;          //分别记录三个下标点的位置
        int a,b,c,d;
        string temp,res;
        char t[32];
        p1=rr.find('.');
        p2=rr.find('.',p1+1);
        p3=rr.find('.',p2+1);
        temp=rr.substr(0,p1); strcpy(t,temp.c_str());   
        a=atoi(t);
        temp=rr.substr(p1+1,p2-p1-1); strcpy(t,temp.c_str()); 
        b=atoi(t);
        temp=rr.substr(p2+1,p3-p2-1); strcpy(t,temp.c_str()); 
        c=atoi(t);
        temp=rr.substr(p3+1,rr.length()-p3-1); strcpy(t,temp.c_str());
        d=atoi(t);
        d+=number;          //更新a,b,c,d的值
		number=d/256;
		d%=256;
		if(number!=0)
		{
			c+=number;
			number=c/256;
			c%=256;
			if(number!=0)
			{
				b+=number;
				number=b/256;
				b%=256;
				if(number!=0)
				{
					a+=number;
				}
			}
		}
        sprintf(t,"%d.%d.%d.%d",a,b,c,d);
        res=t;
        return res;
    }
    vector<string> ipToCIDR(string ip, int range) {           
        vector<string> res;
        string tp;
        int num1;
        while(1)
        {
            tp=convert(ip);          //转换成二进制表示法
            int index=tp.size()-1,u,count=0;
            while(tp[index]=='0'||tp[index]=='.') { if(tp[index]=='0') count++; index--; }           //当前可用地址数
            u=min(count,10);          //注意题目中要求最大地址不超过1000
            num1=(int)(pow(2.0,u*1.0));         //可容纳的地址数
            if(num1>=range)          //可容纳地址数在范围内
            {
                int left=range;
                string rr=ip;
                while(left>0)
                {
                    int k=0;
                    string s="",appender;
                    char t[10];
                    while((int)(pow(2.0,k*1.0))<=left) k++;           
                    s+=rr;
                    s+='/';
                    int number=(int)(pow(2.0,k*1.0-1));
                    sprintf(t,"%d",33-k);
                    appender=t;
                    s+=appender;
                    res.push_back(s);
                    left-=number;
                    rr=change(rr,number);
                }
                break;
            }
            else            //超过可容纳范围
            {
                string tr=ip;
                tr+='/';
                char tt[10];
                sprintf(tt,"%d",32-u);
                tr+=tt;
                res.push_back(tr);
                ip=change(ip,num1);
                range-=num1;
            }
        }
        return res;
    }
};
       思路与上面分析的转化的过程是一致的。首先分析当前可容纳的地址数,与需要涵盖的总地址数比较,分两种情形进行处理。题目本身不算难,但复杂在字符串与整型的转换中,同时还要考虑各种边界情况,因此在调试上花了不少时间,不过终于也得到了AC。

猜你喜欢

转载自blog.csdn.net/xbb123456rt/article/details/78910214