注释清晰,思路引导版:
import java.io.*; import java.util.*; public class Main{ static class Addr{ String addrStr; int mask; int addr; public Addr(String addrStr, int mask, int addr){this.addrStr = addrStr; this.mask = mask; this.addr = addr;} } public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine()); LinkedList<Addr> list = new LinkedList<>(); while(n-->0){ String addrStr = br.readLine();//192.168.0.0/16 String[] strs = addrStr.split("/");//[192.168.0.0,16] int mask = Integer.parseInt(strs[1]);//16 strs = strs[0].split("\.");//[192,168,0,0] //下面一句话含义就是将各个位置【最后一位二进制8位不懂,倒数第二位应该在倒数八位后所以向左移动8位,一次类推构建成ip,然后使用|合并(因为不同ip位数对应位置都是0,因此使用|来连接)】 int addr = (Integer.parseInt(strs[0])<<24) | (Integer.parseInt(strs[1])<<16) | (Integer.parseInt(strs[2])<<8) | Integer.parseInt(strs[3]); boolean flag = true; //遍历列表,如果发现有我已经可以覆盖某个,那么移除它,如果发现我已经被覆盖了,那么直接退出就好了 for(Iterator<Addr> it = list.iterator(); it.hasNext(); ){ Addr tmp = it.next(); //如果我覆盖的更广,并且【异或,相同为0,不同为1】找出不同的,向右移动我可以32-mask位,【如mask为1的时候,我只需要考虑第一位进制就好,后面31位都不需要考虑】 //我覆盖的更广,并且和我前几位是相同的 if(mask < tmp.mask && ( (addr ^ tmp.addr) >>> (32-mask) == 0) ) it.remove(); //覆盖是相同的,但是我覆盖的面比当前列表中有的小,那么不需要将我加进去了 //这里判断如果我本身覆盖面小(也就是mask大) 并且列表中的这个可以满足覆盖我(注意是列表中的,这里32减去的是item.mask) if(mask >= tmp.mask && ( (addr ^ tmp.addr) >>> (32-tmp.mask) == 0) ){flag = false; break;} } if(flag) list.add(new Addr(addrStr,mask,addr)); } System.out.println(list.size()); for(Iterator<Addr> it = list.iterator(); it.hasNext(); ){ Addr tmp = it.next(); System.out.println(tmp.addrStr); } } }
无注释,个人精简版:
import java.util.LinkedList; import java.util.Scanner; public class Main03 { static class Addr{ String ipStr; int mask; int addr; public Addr(String ipStr, int mask, int addr) { this.ipStr = ipStr; this.mask = mask; this.addr = addr; } } public static void main(String[] args) { Scanner s=new Scanner(System.in); while (s.hasNext()){ int k=s.nextInt(); LinkedList<Addr> resList=new LinkedList<>(); while (k-->0){ String ipStr=s.next(); String[] strs=ipStr.split("/"); int mask=Integer.parseInt(strs[1]);//可以覆盖的数量 strs=strs[0].split("\.");//每一项就是一块ip地址 int addr=(Integer.parseInt(strs[0])<<24)|(Integer.parseInt(strs[1])<<16)|(Integer.parseInt(strs[2])<<8)|(Integer.parseInt(strs[3])); boolean isNeedAdd=true;//是否需要将这个加进去 LinkedList<Addr> removeList=new LinkedList<>(); for (Addr item : resList) { if(mask<item.mask&&((addr^item.addr)>>(32-mask)==0))removeList.add(item);//使用for( : )不能直接移除,否则会报异常,但是使用iterator可以哦 //这里判断如果我本身覆盖面小(也就是mask大) 并且列表中的这个可以满足覆盖我(注意是列表中的,这里32减去的是item.mask) if(mask>=item.mask&&((addr^item.addr)>>(32-item.mask)==0)){ isNeedAdd=false; break; } } for (Addr addr1 : removeList) { resList.remove(addr1); } if(isNeedAdd){ resList.add(new Addr(ipStr,mask,addr)); } } System.out.println(resList.size()); for (Addr item : resList) { System.out.println(item.ipStr); } } } }