题解 | #识别有效的IP地址和掩码并进行分类统计#

识别有效的IP地址和掩码并进行分类统计

https://www.nowcoder.com/practice/de538edd6f7e4bc3a5689723a7435682

#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
#include <bitset>
using namespace std;

//思路:(首先排除0.*.*.* 和127.*.*.* 的IP地址 ,因为这种IP地址不属于任何一类需要计数的类型)
//1.判断子网掩码是否正确:错误属于IP或掩码错误情况,相应计数加1,继续下一条字符串判断,重新开始1;正确进入2
//2.此时掩码正确,判断IP地址是否正确:错误属于IP或掩码错误情况,相应计数加1,继续下一条字符串判断,重新开始1;正确进入3
//3.此时IP正确,判段属于A/B/C/D/E哪类地址,同时判断是否属于私有地址,相应计数加1,继续下一条字符串判断,重新开始1
int main(){
    string mstr;
    //计数变量
    int Aaddress = 0; 
    int Baddress = 0; 
    int Caddress = 0; 
    int Daddress = 0; 
    int Eaddress = 0; 
    int ErrorIpOrMask = 0; 
    int PrivateIP = 0;
    while (getline(cin, mstr)){//循环处理多个字符串
        //**************************************************************************************//
        //获取两个字符串 , IP地址和子网掩码
        int len = mstr.length();//单个字符串的长度
        int Middle = mstr.find('~'); //查找 ~ 的位置 
        string strIp = mstr.substr(0,Middle);//存放单个字符串Ip地址部分//stringA.substr(int startIndex, int needLength)
        string strMask = mstr.substr(Middle+1,len - Middle- 1 );//存放单个字符串子网掩码部分

        //**************************************************************************************//
        //排除0.*.*.* 和127.*.*.* 的IP地址
        int ipPoint1 = strIp.find('.');
        string ip1 = strIp.substr(0, ipPoint1);
        if(ip1 == "0" || ip1 == "127"){
            continue;
        }
        
        //**************************************************************************************//
        //判断子网掩码是否正确
        int maskPoint1 = strMask.find( '.' );//查找子网掩码中第1个点
        string mask1 = strMask.substr(0 ,maskPoint1); 
        if( mask1 == "" || stoi(mask1) > 255 ){ //不能为空位
            ErrorIpOrMask++;
            continue;
        }
        bitset<8> bMask1(stoi(mask1)); //将字符串形式的数字转为整型后,获取其8位二进制值
        
        int maskPoint2 = strMask.find( '.' , maskPoint1 + 1);//从maskPoint1 + 1位置开始,查找子网掩码中第2个点
        string mask2 = strMask.substr(maskPoint1 + 1 , maskPoint2 - maskPoint1 - 1 ); 
        if( mask2 == "" || stoi(mask2) > 255 ){ //不能为空位
            ErrorIpOrMask++;
            continue;
        }
        bitset<8> bMask2(stoi(mask2));
        
        int maskPoint3 = strMask.find( '.' ,maskPoint2 + 1);//查找子网掩码中第一个点
        string mask3 = strMask.substr(maskPoint2 + 1, maskPoint3 - maskPoint2 -1 );
        if( mask3 == "" || stoi(mask3) > 255 ){ //不能为空位
            ErrorIpOrMask++;
            continue;
        }
        bitset<8> bMask3(stoi(mask3));

        string mask4 = strMask.substr(maskPoint3+1 , strMask.length() - maskPoint3 -1 );
        if( mask4 == "" || stoi(mask4) > 255 ){ //不能为空位
            ErrorIpOrMask++;
            continue;
        }
        bitset<8> bMask4(stoi(mask4));
        
        //子网掩码 全0非法 , 全1 非法
        if(bMask1.count() + bMask2.count() + bMask3.count() + bMask4.count() == 32 ||
          bMask1.count()+ bMask2.count() + bMask3.count() + bMask4.count() == 0){
            ErrorIpOrMask++;
            continue;
        }
        int vMask[32] = {0};//将二进制的子网掩码放入整型数组vMask,用于判断子网掩码中的连续1
        for(int i = 0 ; i< 32 ;i++){
            if(i>=0 && i<= 7){
                vMask[i] = bMask1[7 - i];
            }
            else if(i>=8 && i<= 15){
                vMask[i] = bMask2[ 7 - i + 8];
            }
            else if(i>=16 && i <= 23){
                vMask[i] = bMask3[7 - i+ 16];
            }
            else if(i>=24 && i< 31){
                vMask[i] = bMask4[7- i + 24];
            }
        }
        
        bool ErrorContinue = false; //判断是否存在连续的1 ,不连续1非法 i,j 双指针判断
        for(int i = 0 , j = 1 ; j < 32 ;  ){
            if(vMask[i] == 0 && vMask[j] == 1){ //对一串子网掩码而言,出现 ****01***即是非法的掩码
                ErrorContinue = true;
                break;
            }
            i++;
            j++;
        }
        if(ErrorContinue){
            ErrorIpOrMask++;
            continue;
        }
        
        //**********************************************************************************//
        //判断IP地址是否正确
        if(ip1 == "" || stoi(ip1) > 255 ){
            ErrorIpOrMask++;
            continue;
        }
        
        int ipPoint2 = strIp.find('.' , ipPoint1 +1 );
        string ip2 = strIp.substr(ipPoint1 + 1, ipPoint2 - ipPoint1 - 1);
        if(ip2 == "" || stoi(ip2) > 255){
            ErrorIpOrMask++;
            continue;
        }
        int ipPoint3 = strIp.find('.' , ipPoint2 +1 );
        string ip3 = strIp.substr(ipPoint2 + 1, ipPoint3 - ipPoint2 - 1);
        if(ip3 == "" || stoi(ip3) > 255){
            ErrorIpOrMask++;
            continue;
        }
        
        string ip4 = strIp.substr(ipPoint3 + 1 , strIp.length() - ipPoint3 - 1);
        if(ip4 == "" || stoi(ip4) > 255){
            ErrorIpOrMask++;
            continue;
        }
        
        //**************************************************************************************//
        //判断属于哪一类IP地址
        int judge1 = stoi(ip1);
        int judge2 =stoi(ip2);
        if(judge1 >= 1 && judge1 <=126){ // A 类
            Aaddress++;
            if(judge1 == 10){
                PrivateIP++;
            }
        }
        else if(judge1 >= 128 && judge1<= 191){ // B 类
            Baddress++;
            if(judge1 == 172 &&  judge2 >= 16 && judge2 <= 31){
                PrivateIP++;
            }
        }
        else if(judge1 >= 192 && judge1 <= 223){// C 类
            Caddress++;
            if(judge2 == 168){
                PrivateIP++;
            }
        }
        else if(judge1 >= 224 && judge1 <= 239){// D 类
            Daddress++;
        }
        else if(judge1 >= 240 && judge1 <= 255){// E 类
            Eaddress++;
        }

    }
    
    cout<<Aaddress<<" "<<Baddress<<" "<<Caddress<<" "<<Daddress<<" "<<Eaddress<<" "<<ErrorIpOrMask<<" "<<PrivateIP<<" "<<endl;
}

整体的解题思路在代码中有详细的注释,个人认为这道题主要难点在于细节的处理。
  • 第一,是对IP地址的特殊情况处理,在判断子网掩码前需要排除 0.*.*.* 和  127.*.*.* 的IP地址 ,因为这种IP地址不属于任何一类需要计数的类型;
  • 第二,不论是对于IP地址还是子网掩码而言,都必须符合   a . b . c. d 这种格式,19.8..8 这种属于非法的IP地址,这一点在题目中也有提到,可以通过判断a/b/c/d位是否为空来排除错误情况,并且为了保证可以将a/b/c/d转换为8位的二进制,还需要在转换为比特数之前判断a/b/c/d是否处于0- 255 的区间;
  • 第三,是对子网掩码判断,不考虑和IP地址相适配的情况下,对于一个合法的子网掩码来说,由连续的1 加连续的0 共32比特组成;(关于子网掩码和 IP地址相适配,是说:对于A类地址,可指派的网络号最小为1,最大为126, 即8位网络号和24位的主机号,在划分子网的情况下,子网掩码不再是255.0.0.0,且连1大于8,不适配是在连1长度小于8的情况下;对于B类地址,16位的网络号和16位的主机号;对于C 类地址,由24位网络号和8位的主机号组成 )。本题的测试用例好像默认是相互适配的,当然在划分子网的情况下,如前所述,借用一部分的主机位来充当网络位是完全正确的。






#华为笔试##牛客网#
全部评论
我知道了,我***了
点赞 回复 分享
发布于 2023-04-19 13:05 辽宁
为啥是vMask[i] = bMask1[7 - i]; 不是vMask[i] = bMask1[i];
点赞 回复 分享
发布于 2023-04-19 13:03 辽宁

相关推荐

xwqlikepsl:感觉很厉害啊,慢慢找
点赞 评论 收藏
分享
HaxyBT:那我提前下班总可以了吧
点赞 评论 收藏
分享
评论
4
4
分享

创作者周榜

更多
牛客网
牛客企业服务