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

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

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

#include <iostream>
using namespace std;
#include <string>
#include <sstream>
#include <cmath>
int getNum(string str) {
    int num = 0;
    if (str.length() == 0) {
        return -1;
    }
    for (int i = str.size() - 1, j = 0; i >= 0; i--, j++) {
        if ('0' <= str[i] && str[i] <= '9') {
            num = num + (str[i] - '0') * (pow(10, j));
        } else {
            return -1;
        }
    }
    return num;
}
bool bm(unsigned b) {
    if (!b) {
        return false;
    }
    b = ~b + 1;
    if (b == 1) {
        return false;
    }

    if ((b & (b - 1)) == 0) {
        return true;
    }
    return false;
}
int main() {
    string str;
    int A = 0, B = 0, C = 0, D = 0, E = 0, err = 0, p = 0;
    // 各种类型的IP地址的计数,也可以使用数组来记,不过这样比较清楚
    string ip;      // 每轮的ip
    string bitMask; // 每轮的子网掩码
    string num;     // 每轮的数字
    int realNum;
    int i;      // 地址标志
    int type;   // 类型标志
    bool flag;  // 合法标志
    bool pri;   // 私有标志
    bool count; // 不计数特殊标志位
    int num1;   // 私有判断辅助1
    int num2;   // 私有判断辅助2
    unsigned b;
    string bmNum;
    while (getline(cin, str)) {
        istringstream is(str);
        getline(is, ip, '~');
        is >> bitMask;

        // 接下来对ip进行检查
        istringstream ipCode(ip);
        // 初始化所有标志位
        i = 1;
        flag = true;
        pri = false;
        count = true;
        b = 0;
        type = 0;
        while (getline(ipCode, num, '.') && flag) {
            realNum = getNum(num);
            switch (i) {
                case 1: {
                        num1 = realNum;
                        if (realNum >= 1 && realNum <= 126) {
                            type = 1;
                        } else if (realNum >= 128 && realNum <= 191) {
                            type = 2;
                        } else if (realNum >= 192 && realNum <= 223) {
                            type = 3;
                        } else if (realNum >= 224 && realNum <= 239) {
                            type = 4;
                        } else if (realNum >= 240 && realNum <= 255) {
                            type = 5;
                        } else if (realNum == 0 || realNum == 127) {
                            flag = false;
                            count = false;
                        } else {
                            flag = false;
                        }

                        break;
                    }
                case 2: {
                        num2 = realNum;
                        if (!(realNum >= 0 && realNum <= 255)) {
                            flag = false;
                        }
                        break;
                    }
                case 3: {
                        if (!(realNum >= 0 && realNum <= 255)) {
                            flag = false;
                        }

                        break;
                    }
                case 4: {
                        if (!(realNum >= 0 && realNum <= 255)) {
                            flag = false;
                        }

                        break;
                    }
            }
            i++;
        }
        if (flag && count) {
            // 进行私有ip判断
            if (num1 == 10) {
                pri = true;
            } else if (num1 == 172 && (num2 >= 16 && num2 <= 31)) {
                pri = true;
            } else if (num1 == 192 && num2 == 168) {
                pri = true;
            }

            // 进行子网掩码判断
            istringstream bmCode(bitMask);
            while (getline(bmCode, bmNum, '.')) {
                b = (b << 8) + getNum(bmNum);
            }
            flag = bm(b);
        }
        // 最后进行计数
        if (count && flag) {
            if (pri) {
                p++;
            }

            switch (type) {
                case 1:
                    A++;
                    break;
                case 2:
                    B++;
                    break;
                case 3:
                    C++;
                    break;
                case 4:
                    D++;
                    break;
                case 5:
                    E++;
                    break;
            }
        } else if (count && !flag) {
            err++;
        }
    }

    cout << A << " " << B << " " << C << " " << D << " " << E << " " << err << " "
         << p << endl;
}

主要是输入的拆分和掩码的判断

istringstream的功能主要是创建了一个流,可以像cin一样使用getline操作,同时getline又支持自定义分隔符,这样就搞定了输入到数字的转化,接下来就是繁琐的逻辑判断了。

掩码的判断参考了以下思路:

  1. 如何判断一个掩码地址是不是满足前面连续是1,然后全是0?
  2. 将掩码地址转换为32位无符号整型,假设这个数为b。
  3. 如果此时b为0,则为非法掩码将b按位取反后+1
  4. 如果此时b为1,则b原来是二进制全1,非法掩码
  5. 如果b和b-1做按位与运算后为0,则说明是合法掩码,否则为非法掩码

中间还踩到了字符转数字的坑,如果字符串接受到为空,使用stoi直接转化会报错,而我自己写的函数会返回默认的0,这样就判断不出错误了,在调试后发现了这个问题,最后自己写的getNum函数添加了判断接受字符串是否为空的功能。

做这种题目真的很需要耐心下来认真看题目,其实逻辑很清晰。

华为机试刷题记录 文章被收录于专栏

记录一下手打代码的解题思路方便复习

全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务