题解 | #识别有效的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,然后全是0?
- 将掩码地址转换为32位无符号整型,假设这个数为b。
- 如果此时b为0,则为非法掩码将b按位取反后+1
- 如果此时b为1,则b原来是二进制全1,非法掩码
- 如果b和b-1做按位与运算后为0,则说明是合法掩码,否则为非法掩码
中间还踩到了字符转数字的坑,如果字符串接受到为空,使用stoi直接转化会报错,而我自己写的函数会返回默认的0,这样就判断不出错误了,在调试后发现了这个问题,最后自己写的getNum函数添加了判断接受字符串是否为空的功能。
做这种题目真的很需要耐心下来认真看题目,其实逻辑很清晰。
华为机试刷题记录 文章被收录于专栏
记录一下手打代码的解题思路方便复习