题解 | #识别有效的IP地址和掩码并进行分类统计#
非常无语的一道题,要通过所有测试用例,有两点非常重要:
1. 0/127开头的ip地址时,子网掩码不要判断,此例直接continue,不做任何计算...
2. 不是1的情况下,先判断子网掩码,子网掩码错误则ip地址不要再判断了...
以上两点不观察测试用例,根本不知道!
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int A = 0, B = 0, C = 0, D = 0, E = 0, W = 0, S = 0;
while (sc.hasNextLine()) {
String line = sc.nextLine();
String[] mix = line.trim().split("~");
String ip = mix[0], mask = mix[1];
// 非常无语的一点,如果ip开头是0,或者127,后面掩码不做任何判断
String f = ip.split("\\.")[0];
if (f.equals("0") || f.equals("127")) continue;
// 掩码判断(非常无语的一点,从测试用例看出,如果子网掩码错误,ip地址不用再判断)
if (judgeMask(mask)) {
W++;
continue;
}
// IP地址判断(其中,A类地址、B类地址、C类地址包含有私网地址)
char classIP = judgeIP(ip);
if (classIP == 'F') W++;
if (classIP == 'A') {
A++;
if (judgePrivateIP(ip, classIP)) S++;
}
if (classIP == 'B') {
B++;
if (judgePrivateIP(ip, classIP)) S++;
}
if (classIP == 'C') {
C++;
if (judgePrivateIP(ip, classIP)) S++;
}
if (classIP == 'D') D++;
if (classIP == 'E') E++;
}
System.out.println(A + " " + B + " " + C + " " + D + " " + E + " " + W + " " + S + " ");
}
public static char judgeIP(String ip) {
String[] partsIP = ip.split("\\.");
if (partsIP[0].equals("0")) return 'G'; // 忽略计数
if (partsIP[0].equals("127")) return 'G'; // 忽略计数
if (partsIP[0].equals("")) return 'F'; // 忽略计数
int p1 = Integer.parseInt(partsIP[0]);
if (p1 >= 1 && p1 <= 126) { // 可能 A
for (int i = 1; i < 4; i++) {
if (partsIP[i].equals("")) return 'F';
if (Integer.parseInt(partsIP[i]) > 255) {
return 'F';
}
}
return 'A';
}
if (p1 >= 128 && p1 <= 191) { // 可能 B
for (int i = 1; i < 4; i++) {
if (partsIP[i].equals("")) return 'F';
if (Integer.parseInt(partsIP[i]) > 255) {
return 'F';
}
}
return 'B';
}
if (p1 >= 192 && p1 <= 223) { // 可能 C
for (int i = 1; i < 4; i++) {
if (partsIP[i].equals("")) return 'F';
if (Integer.parseInt(partsIP[i]) > 255) {
return 'F';
}
}
return 'C';
}
if (p1 >= 224 && p1 <= 239) { // 可能 D
for (int i = 1; i < 4; i++) {
if (partsIP[i].equals("")) return 'F';
if (Integer.parseInt(partsIP[i]) > 255) {
return 'F';
}
}
return 'D';
}
if (p1 >= 240 && p1 <= 255) { // 可能 E
for (int i = 1; i < 4; i++) {
if (partsIP[i].equals("")) return 'F';
if (Integer.parseInt(partsIP[i]) > 255) {
return 'F';
}
}
return 'E';
}
return 'F'; // 表示不和法的IP地址
}
public static boolean judgePrivateIP(String ip, char classIp) {
// ip肯定是合法地址
boolean privateIpFlag = false; // true表示为是私有地址
String[] partsIP = ip.split("\\.");
int p1 = Integer.parseInt(partsIP[0]);
if (p1 == 10) {
privateIpFlag = true;
}
if (p1 == 172) {
int p2 = Integer.parseInt(partsIP[1]);
if (p2 >= 16 && p2 <= 31) privateIpFlag = true;
}
if (p1 == 192) {
int p2 = Integer.parseInt(partsIP[1]);
if (p2 == 168) privateIpFlag = true;
}
return privateIpFlag;
}
public static boolean judgeMask(String mask) {
// 错误掩码:全0,全1,0后面还出现了1;全是0或者全是1同样不合法
boolean illegalityMask = false; // 此掩码是否非法
String[] partsM = mask.split("\\.");
for (int i = 0; i < 4; i++) {
if (partsM[i].equals("")) {
illegalityMask = true;
break;
}
int m = Integer.parseInt(partsM[i]);
// 0.全0,直接判断非法
if (i == 0 && m == 0) {
illegalityMask = true;
break;
}
// 1.大于255,直接判断不合法
if (m > 255) {
illegalityMask = true;
break;
}
// 2.此位置为255,结束此位置判断,开始下一个位置判断
if (m == 255) {
if (i == 3) { // 4个位置全1,同样不合法
illegalityMask = true;
break;
} else {
continue;
}
}
// 3.此位置小于255,则下一位置必须是0
for (int j = i+1; j < 4; j++) {
if (!partsM[j].equals("0")) {
illegalityMask = true;
break;
}
}
// 4.此位置小于255,且下面的位置均为0
if (m == 0) break; // 前面已经排除了全0,且后序位置都为0,此位置也为0,直接判断合法
if (Integer.toBinaryString(m).length() < 8) { // 转换为二进制,长度小于8,则必然不合法
illegalityMask = true;
break;
}
boolean lowShow1 = false; // 低位出现 1
while (m != 0) {
if (m % 2 == 1) lowShow1 = true;
if (lowShow1 && m % 2 == 0) {
illegalityMask = true; // 低位出现1后高位又出现0
break;
}
m = m >> 1;
}
}
return illegalityMask;
}
}
