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

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

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

坑爹的题目条件:IP地址如果是0.*.*.*和127.*.*.*都可以不用判定类别和错误,直接跳过。如果这个条件被忽略了就会导致中间有一个测试样例过不了:127.201.56.50~255.255.111.255(这个不用给错误计数+1)

关于判定掩码是否合法的算法:直接一位一位判定有些繁琐,但是用移位操作来判断就简单不少了(我这里用了取反,不取反一样可以判断,我一开始觉得取反后理解方便一些,但是实际上是等价的)。

use std::io::{self, *};

fn main() {
    let stdin = io::stdin();
    let mut buffer = String::new();
    let (mut a, mut b, mut c, mut d, mut e, mut wrong_cnt, mut private_ip) = (0, 0, 0, 0, 0, 0, 0);
    while let Ok(n) = stdin.read_line(&mut buffer) {
        if n == 0 {
            break;
        }
        let mut inputs = buffer.trim().split('~');
        let ip = inputs.next().unwrap();
        let mask = inputs.next().unwrap();
        let ip_v: Vec<&str> = ip.split('.').collect();
        let mask_v: Vec<&str> = mask.split('.').collect();
        let mut has_wrong = false;
        let mut mask = 0;
        let first_seg: u8;
        if let Ok(seg) = ip_v[0].parse() {
            first_seg = seg;
        } else {
            wrong_cnt += 1;
            has_wrong = true;
            buffer.clear();
            continue;
        }
        if first_seg == 127 || first_seg == 0 {
            buffer.clear();
            continue;
        }
        for i in 0..4 {
            if ip_v[i].is_empty() {
                wrong_cnt += 1;
                has_wrong = true;
                break;
            }
            if mask_v[i].is_empty() {
                wrong_cnt += 1;
                has_wrong = true;
                break;
            } else {
                let mask_seg: u8 = mask_v[i].parse().unwrap();
                mask += (mask_seg as u32) << ((3 - i) * 8);
            }
        }
        if has_wrong {
            buffer.clear();
            continue;
        }
        if mask == 0 || mask == u32::MAX {
            wrong_cnt += 1;
            buffer.clear();
            continue;
        }
	  	// 取反,并从低位开始右移到第一个0的位置(原本的最低位1)
	  	// 用了u32,因为不想出现算数移位操作
        mask = mask ^ u32::MAX;
        while mask % 2 == 1 {
            mask >>= 1;
        }
	  	// 如果此时这个数字含有1(说明原本的数高位存在0),就是一个非法的掩码
        if mask != 0 {
            wrong_cnt += 1;
            buffer.clear();
            continue;
        }
        if first_seg >= 1 && first_seg < 127 {
            a += 1;
        } else if first_seg >= 128 && first_seg < 192 {
            b += 1;
        } else if first_seg >= 192 && first_seg < 224 {
            c += 1;
        } else if first_seg >= 224 && first_seg < 240 {
            d += 1;
        } else {
            e += 1;
        }
        if first_seg == 10 {
            private_ip += 1;
        } else if first_seg == 172 {
            let second_seg: u8 = ip_v[1].parse().unwrap();
            if second_seg >= 16 && second_seg < 32 {
                private_ip += 1;
            }
        } else if first_seg == 192 {
            let second_seg: u8 = ip_v[1].parse().unwrap();
            if second_seg == 168 {
                private_ip += 1;
            }
        }
        buffer.clear();
    }
    println!("{} {} {} {} {} {} {}", a, b, c, d, e, wrong_cnt, private_ip);
}

临场写写出来的代码容易存在冗余逻辑,我让AI帮我精简了下代码,如下:

use std::io::{self, BufRead};

fn parse_ip(ip: &str) -> Option<Vec<u8>> {
    ip.split('.').map(|s| s.parse().ok()).collect()
}

fn parse_mask(mask: &str) -> Option<u32> {
    let mut m = 0u32;
    for (i, part) in mask.split('.').enumerate() {
        let seg: u8 = part.parse().ok()?;
        m |= (seg as u32) << ((3 - i) * 8);
    }
    // 合法掩码:连续 1 再连续 0
    if m == 0 || m == u32::MAX {
        return None;
    }
    let inv = !m;
    if inv & (inv + 1) != 0 {
        return None;
    }
    Some(m)
}

fn classify(first: u8) -> Option<usize> {
    match first {
        1..=126 => Some(0),   // A
        128..=191 => Some(1), // B
        192..=223 => Some(2), // C
        224..=239 => Some(3), // D
        240..=255 => Some(4), // E
        _ => None,
    }
}

fn is_private(ip: &[u8]) -> bool {
    match ip {
        [10, ..] => true,
        [172, s, ..] if (16..=31).contains(s) => true,
        [192, 168, ..] => true,
        _ => false,
    }
}

fn main() {
    let stdin = io::stdin();
    let mut counts = [0; 5];
    let mut wrong = 0;
    let mut private = 0;

    for line in stdin.lock().lines() {
        let line = line.unwrap();
        if line.is_empty() {
            break;
        }
        let mut parts = line.trim().split('~');
        let (ip_str, mask_str) = (parts.next(), parts.next());
        let (Some(ip_str), Some(mask_str)) = (ip_str, mask_str) else {
            wrong += 1;
            continue;
        };

        let Some(ip) = parse_ip(ip_str) else {
            wrong += 1;
            continue;
        };
        if ip[0] == 0 || ip[0] == 127 {
            continue;
        }
        if parse_mask(mask_str).is_none() {
            wrong += 1;
            continue;
        }
        if let Some(idx) = classify(ip[0]) {
            counts[idx] += 1;
        }
        if is_private(&ip) {
            private += 1;
        }
    }

    println!(
        "{} {} {} {} {} {} {}",
        counts[0], counts[1], counts[2], counts[3], counts[4], wrong, private
    );
}

只能说AI还是厉害的~

全部评论

相关推荐

Clavoss:一眼AI,死亏
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

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