【打卡】牛客网:BM85 验证IP地址

发布时间:2024年01月14日

之前涉及到IP地址的题有:

  1. BM74 数字字符串转化成IP地址
  2. BM22 比较版本号

BM85题目要求:

IPv4:

  1. 4组十进制数,范围是0-255
  2. 每组前无“0”
  3. 分隔符是“.”

IPv6:

  1. 8组十六进制数,忽略大小写
  2. 每组前可以有“0”,保证每组由4个字符组成
  3. 分隔符是“:”

IPv4错误示例:

  1. 不是4组:254.254.254
  2. 位数大于3:2541.254.254.254
  3. 分隔符连续:254.254..254
  4. 不是十进制数(0-9):254.254.a.254
  5. 出现前导“0”:254.254.054.254
  6. 不在0-255的范围:254.254.256.254

IPv6的错误示例:

  1. 不是8组
  2. 位数大于4
  3. 分隔符连续
  4. 不是十六进制数(0-9,a-f,A-F)

关于前导“0”

  1. IPv6允许出现前导“0”,即,a:a:0a:a:a:a:a:a
  2. 允许出现连续“0”,即,a:a:00a:a:a:a:a:a、a:a:000:a:a:a:a:a、a:a:0000:a:a:a:a:a

BM85的测试用例

牛客网的测试用例很水,程序错了都能通过9个。 (IPv4、IPv6没有分隔符连续的用例、IPv4没有前导“0”的用例)

我写的:

  1. 这种用if判断的题,关键是能考虑所有情况。
  2. 以分隔符对字符串进行分隔的split()函数:
    1. c++好像没有split(),需要自己定义。(python有)
  3. 判断是否是数字:
    1. 可以用isdigit(ip[i][j]),或者ip[i][j] > '0' && ip[i][j] < '9'
    2. isdigit(ip[i][j])更保险,还判断了是否为空,保证后面的stoi()能正常运行。
  4. string转为int
    1. 用stoi()函数:int num = stoi(ip[i])
  5. substr()调试很久:
    1. substr(i,n),表示在位置i截取n个字符
    2. 不是表示substr(start, end),即,截取[位置start,位置end)。

以下是我的代码:

我的split()函数写得稀烂,根据用例调试很久。模板的split()写得好一些。?

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 验证IP地址
     * @param IP string字符串 一个IP地址字符串
     * @return string字符串
     */
      vector<string> split(string str, char c) {
        vector<string> ans;
        int start = -1;
        int end = 0;
        while (end < str.size()) {
            if (str[end] == c) { //粗心,不是end == c
                if(end == str.size() - 1){
                    ans.push_back(str.substr(start + 1, end - start)); 
                    ans.push_back("");
                    start = end;
                }
                ans.push_back(str.substr(start + 1, end - start - 1)); //"1"是1组,“1.1..1”是4组,“.1.1.1”是4组,“1.1.1.1.”是4组
                start = end;
            }
            else if (end == str.size() - 1) {  //调试很久,不然最后一组不能放入
                ans.push_back(str.substr(start + 1, end - start)); 
                start = end;
            }
            end++;
        }
        return ans;
    }
    bool isIPv4(string IP) {
        vector<string> ip = split(IP, '.');
        //必须有4组
        if (ip.size() != 4)
            return false;
        //每组进行分析
        for (int i = 0; i < 4; i++) {
            //每组不为空,且最多有3个字符
            if (ip[i].size() == 0 || ip[i].size() > 3) 
                return false;
            //不能有前导“0”
            if(ip[i].size()>1 && ip[i][0] == '0')
                return false;
            //必须是十进制字符
            for (int j = 0; j < ip[i].size(); j++)
                if (!((ip[i][j] >= '0' && ip[i][j] <= '9')))
                    return false;
            //必须在0-255范围
            int num = stoi(ip[i]); //调试,ip[i]必须是数字,必须【非空】。
            if (num > 255) 
                return false;
        }
        return true;
    }

    bool isIPv6(string IP) {
        vector<string> ip = split(IP, ':');
        //必须有8组
        if (ip.size() != 8)
            return false;
        //每组进行分析
        for (int i = 0; i < 8; i++) {
            //每组不为空,且最多有4个字符
            if (ip[i].size() == 0 || ip[i].size() > 4)
                return false;
            //必须是十六进制字符
            for (int j = 0; j < ip[i].size(); j++)
                if (!((ip[i][j] >= '0' && ip[i][j] <= '9') ||
                    (ip[i][j] >= 'a' && ip[i][j] <= 'f') ||
                    (ip[i][j] >= 'A' && ip[i][j] <= 'F'))){ //粗心,忘记加等号“=”。
                        cout<<ip[i][j]<<endl;;
                        return false;
                    }
        }
        return true;
    }
    string solve(string IP) {
        // write code here
        bool flag1 = isIPv4(IP);
        bool flag2 = isIPv6(IP);

        if (flag1)
            return "IPv4";

        if (flag2)
            return "IPv6";

        return "Neither";
    }
};

模板的:

?模板的split(),在while循环中,会把截取的字符串去掉,所以每次只需要截取前n个即可。

      vector<string> split(string str, char c) {
        vector<string> ans;
        int end;
        while((end = str.find(c)) && end != str.npos){
            ans.push_back(str.substr(0,end));
            str = str.substr(end+1);
        }
        ans.push_back(str); //易粗心漏掉
        return ans;
    }

一些关键点:

  1. string::npos
    1. string::type_size 类型,也就是find()返回的类型。
    2. 定义
      1. size_t npos = -1,-1为size_t的最大值。
    3. 表示返回值,表示没有匹配项。
      1. 例如,定义size_t index =?str.find("abc"),再判断if(index == string::npos)
    4. 作为长度参数,表示直到字符串结束。
      1. 例如,str1.replace(index, string::npos, str2)
    5. 注:建议直接使用if(str.find("abc") == string::npos)。
      1. 因为如果先定义int index = str.find("abc") ,再判断if(index == string::npos),比较结果可能为false。

C++中std::string::npos的用法_C 语言_脚本之家 (jb51.net)

C++中string::npos的用法总结-CSDN博客

  1. while((赋值语句))
    1. 先执行赋值语句,然后对左值进行判断。如果左值为0,则while退出;否则,while继续循环。
    2. 再加一个括号(),告知编译器:赋值操作符“=”是对的,而不是判断符“==”的误写。
    3. while((c = *p ++))? ?// 读取字符串中的字符,直到字符串结尾。具体步骤是:先把*p赋值给c,然后执行指针移位,再判断c的值。如果c值为0,代表字符串结束,退出循环。
    4. while(b=a,b-=1)? ?// 依次运行,以最后的一段作为结果。

?C语言中,while()语句括号内可以是赋值语句吗? (sogou.com)

此外,刷到i++和++i的区别:

C++在使用while循环时关于i++和++i的注意事项_while是不是只能用i++-CSDN博客

文章来源:https://blog.csdn.net/weixin_47173826/article/details/135583476
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。