最终的100分代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
class IP{
int[] value;
int mask;
public IP() {
this.value = new int[4];
for(int i=0;i<4;i++) {
this.value[i]=0;
}
}
@Override
public String toString() {
return value[0]+"."+value[1]+"."+value[2]+"."+value[3]+"/"+mask;
}
}
public class Main {
public static void main(String[] args) throws IOException{
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(bf.readLine());
String rawIp;
// 转换为标准形式
ArrayList<IP> ipArr = new ArrayList<IP>();
for(int i=0;i<n;i++) {
rawIp = bf.readLine();
ipArr.add(toIp(rawIp));
}
// 排序
Collections.sort(ipArr, new Comparator<IP>() {
@Override
public int compare(IP o1,IP o2) {
int flag = greaterThan(o1,o2);
if(flag==0) {
// 前缀长度
if(o1.mask>o2.mask) {
flag = 1;
}else {
flag = -1;
}
}
return flag;
}
});
IP[] newArr = new IP[ipArr.size()]; // 转为数组
boolean[] delete = new boolean[ipArr.size()]; // 是否被删除
ipArr.toArray(newArr);
int relation;
int right = 0;
int len = newArr.length;
boolean flag = false;
for(int i=0;i<len-1;) {
// 删除跳过
if(delete[i]) {
i++;
continue;
}
// 找到右边一个
do {
right++;
if(right>=len) {
flag = true;
break;
}
}while(delete[right] || right==i);
if(flag) {
break;
}
relation = relation(newArr[i],newArr[right]);
if(relation==1) {
// 包含
// System.out.println("吞 "+newArr[i]+" <- "+newArr[right]+" 删"+right);
delete[right] = true;
}else if(relation==2) {
// 合并
// System.out.println("合 "+newArr[i]+" & "+newArr[right]+" 删"+right);
newArr[i].mask -= 1;
delete[right] = true;
if(i>0) {
right=i-1;
i--;
while(delete[i]) {
i--;
}
}
}else {
i++;
}
}
for(int i=0;i<newArr.length;i++) {
if(!delete[i]) {
System.out.println(newArr[i]);
}
}
}
// 包含返回1,合并返回2
public static int relation(IP a,IP b) {
if(a.mask<=b.mask) {
int part = (a.mask-1)/8;
int digit = a.mask - part*8;
for(int i=0;i<part;i++) {
if(a.value[i]!=b.value[i]) {
return 0;
}
}
int ap = a.value[part] >> (8-digit);
int bp = b.value[part] >> (8-digit);
if(ap==bp) {
return 1;
}
if(a.mask==b.mask && bp-ap==1 && ((ap>>1)==(bp>>1))) {
return 2;
}
}
return 0;
}
// 比较两个IP
public static int greaterThan(IP o1,IP o2) {
int flag = 1;
int a = (o1.value[0]<<8) + o1.value[1] - (o2.value[0]<<8) - o2.value[1];
if(a>0) {
}else if(a<0) {
flag = -1;
}else {
int b = (o1.value[2]<<8) + o1.value[3] - (o2.value[2]<<8) - o2.value[3];
flag = b;
}
return flag;
}
// 处理输入的ip
public static IP toIp(String rawIp) {
int split = rawIp.indexOf('/');
String value = rawIp;
int mask = 0;
// 含有'/',分割
if(split>0) {
value = rawIp.substring(0, split);
mask = Integer.parseInt(rawIp.substring(split+1, rawIp.length()));
}
IP ip = new IP();
ip.mask = mask;
// 处理地址
for(int i=0;i<4;i++) {
if(value.contains(".")) {
// 继续分割
split = value.indexOf('.');
ip.value[i] = Integer.parseInt(value.substring(0,split));
value = value.substring(split+1,value.length());
}else if(value.length()>0) {
// 只有数字
ip.value[i] = Integer.parseInt(value);
value = "";
// 若无前缀长度
if(ip.mask==0) {
ip.mask = (i+1)*8;
}
}else {
// 空
ip.value[i] = 0;
}
}
return ip;
}
}
踩的两个最大的坑:
- 同级合并的细节
- 超时
悲惨的改代码过程:
第一步,处理不同格式ip输入
测试输入
7
101.6.6.0/24
101.6.6/23
101/8
1/32
101.6.6.0
101.6
1
标准形式
101.6.6.0/24
101.6.6.0/23
101.0.0.0/8
1.0.0.0/32
101.6.6.0/32
101.6.0.0/16
1.0.0.0/8
第二步,排序
1.0.0.0/8
1.0.0.0/32
101.0.0.0/8
101.6.0.0/16
101.6.6.0/23
101.6.6.0/24
101.6.6.0/32
此时提交可通过测试点1-4,有60分
下一步,从小到大合并,80分
最后一步,同级合并
测试1
输入
4
206.0.68.0/25
206.0.68.128/25
206.0.69.0/25
206.0.69.128/25
输出
206.0.68.0/23
测试2
输入
12
206.0.68.0/25
206.0.68.128/25
206.0.69.0/25
206.0.69.128/25
206.0.70.0/26
206.0.70.64/26
206.0.70.128/26
206.0.70.192/26
206.0.71.128/26
206.0.71.64/26
206.0.71.192/26
206.0.71.0/26
输出
206.0.68.0/22
测试3
输入
3
206.0.71.64/25
206.0.71.192/26
206.0.71.0/26
这种也可以合并,不过似乎不用考虑?
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;
class IP{
int[] value;
int mask;
public IP() {
this.value = new int[4];
for(int i=0;i<4;i++) {
this.value[i]=0;
}
}
@Override
public String toString() {
return value[0]+"."+value[1]+"."+value[2]+"."+value[3]+"/"+mask;
}
}
public class Main {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int n = Integer.parseInt(s.nextLine());
String rawIp;
// 转换为标准形式
ArrayList<IP> ipArr = new ArrayList<IP>();
for(int i=0;i<n;i++) {
rawIp = s.nextLine();
ipArr.add(toIp(rawIp));
}
// 排序
Collections.sort(ipArr, new Comparator<IP>() {
@Override
public int compare(IP o1,IP o2) {
int flag = greaterThan(o1,o2);
if(flag==0) {
// 前缀长度
if(o1.mask>o2.mask) {
flag = 1;
}else {
flag = -1;
}
}
return flag;
}
});
// 从小到大合并
for(int i=0;i<ipArr.size()-1;i++) {
if(contain(ipArr.get(i),ipArr.get(i+1))) {
ipArr.remove(i+1);
}
}
// 同级合并
for(int i=0;i<ipArr.size()-1;i++) {
if(canMerge(ipArr.get(i),ipArr.get(i+1))) {
ipArr.get(i).mask -= 1;
ipArr.remove(i+1);
if(i>0) {
i -= 2;
}
}
}
for(int i=0;i<ipArr.size();i++) {
System.out.println(ipArr.get(i));
}
}
// 检查是否可以合并
public static boolean canMerge(IP a,IP b) {
boolean flag = false;
if(a.mask==b.mask) {
int part = (a.mask-1)/8;
int digit = a.mask - part*8;
IP newA = new IP();
for(int i=0;i<4;i++) {
newA.value[i] = a.value[i];
}
newA.value[part] += 1<<(8-digit);
if(greaterThan(newA,b)==0) {
flag=true;
}
}
return flag;
}
// 检查a是否包含b
public static boolean contain(IP a,IP b) {
boolean flag = false;
if(a.mask<=b.mask) {
IP aMax = getMaxIp(a);
IP bMax = getMaxIp(b);
if(greaterThan(b,a)>=0 && greaterThan(aMax,bMax)>=0) {
flag = true;
}
}
return flag;
}
// 比较两个IP
public static int greaterThan(IP o1,IP o2) {
int flag = 1;
int a = (o1.value[0]*256 + o1.value[1]) - (o2.value[0]*256 + o2.value[1]);
if(a>0) {
}else if(a<0) {
flag = -1;
}else {
int b = (o1.value[2]*256 + o1.value[3]) - (o2.value[2]*256 + o2.value[3]);
if(b<0){
flag = -1;
}else if(b==0) {
flag = 0;
}
}
return flag;
}
// 根据mask获取最大IP
public static IP getMaxIp(IP ip) {
IP maxIP = new IP();
int ms = 32-ip.mask;
int[] m = new int[4];
for(int i=3;i>=0;i--) {
if(ms>=8) {
m[i]=8;
ms-=8;
}else {
m[i]=ms;
break;
}
}
for(int i=0;i<4;i++) {
maxIP.value[i] = ip.value[i] + (1<<m[i]) - 1;
}
return maxIP;
}
// 处理输入的ip
public static IP toIp(String rawIp) {
int split = rawIp.indexOf('/');
String value = rawIp;
int mask = 0;
// 含有'/',分割
if(split>0) {
value = rawIp.substring(0, split);
mask = Integer.parseInt(rawIp.substring(split+1, rawIp.length()));
}
IP ip = new IP();
ip.mask = mask;
// 处理地址
for(int i=0;i<4;i++) {
if(value.contains(".")) {
// 继续分割
split = value.indexOf('.');
ip.value[i] = Integer.parseInt(value.substring(0,split));
value = value.substring(split+1,value.length());
}else if(value.length()>0) {
// 只有数字
ip.value[i] = Integer.parseInt(value);
value = "";
// 若无前缀长度
if(ip.mask==0) {
ip.mask = (i+1)*8;
}
}else {
// 空
ip.value[i] = 0;
}
}
return ip;
}
}
结果:得分80,时间使用1.39s,空间使用171.7MB
把Scanner改成BufferedReader
结果:得分80,时间使用1.234s,空间使用103.4MB
难道是超时
心好痛
修改从小到大合并的方法
一些测试数据
10.0/9
10.28/18
10.0/9
10.1/9
10.0/1
10.0/32
101.6.6.0/24
101.6.7.0/24
101.6.6.0/24
101.6.6.128/24
结果:得分80,时间使用890ms,空间使用95.19MB
快了一些,但是还是80分,说明前面不是超时的问题,还是同级合并有问题
改啊改啊改
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
class IP{
int[] value;
int mask;
public IP() {
this.value = new int[4];
for(int i=0;i<4;i++) {
this.value[i]=0;
}
}
@Override
public String toString() {
return value[0]+"."+value[1]+"."+value[2]+"."+value[3]+"/"+mask;
}
}
public class Main {
public static void main(String[] args) throws IOException{
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(bf.readLine());
String rawIp;
// 转换为标准形式
ArrayList<IP> ipArr = new ArrayList<IP>();
for(int i=0;i<n;i++) {
rawIp = bf.readLine();
ipArr.add(toIp(rawIp));
}
// 排序
Collections.sort(ipArr, new Comparator<IP>() {
@Override
public int compare(IP o1,IP o2) {
int flag = greaterThan(o1,o2);
if(flag==0) {
// 前缀长度
if(o1.mask>o2.mask) {
flag = 1;
}else {
flag = -1;
}
}
return flag;
}
});
int relation;
for(int i=0;i<ipArr.size()-1;) {
relation = relation(ipArr.get(i),ipArr.get(i+1));
if(relation==1) {
// System.out.println("吞 "+ipArr.get(i)+" <- "+ipArr.get(i+1));
ipArr.remove(i+1);
}else if(relation==2) {
// System.out.println("合 "+ipArr.get(i)+" & "+ipArr.get(i+1));
ipArr.get(i).mask -= 1;
ipArr.remove(i+1);
if(i>0) {
i--;
}
}else {
i++;
}
}
for(int i=0;i<ipArr.size();i++) {
System.out.println(ipArr.get(i));
}
}
// 包含返回1,合并返回2
public static int relation(IP a,IP b) {
if(a.mask<=b.mask) {
int part = (a.mask-1)/8;
int digit = a.mask - part*8;
for(int i=0;i<part;i++) {
if(a.value[i]!=b.value[i]) {
return 0;
}
}
int ap = a.value[part] >> (8-digit);
int bp = b.value[part] >> (8-digit);
if(ap==bp) {
return 1;
}
if(a.mask==b.mask && bp-ap==1 && ((ap>>1)==(bp>>1))) {
return 2;
}
}
return 0;
}
// 比较两个IP
public static int greaterThan(IP o1,IP o2) {
int flag = 1;
int a = (o1.value[0]*256 + o1.value[1]) - (o2.value[0]*256 + o2.value[1]);
if(a>0) {
}else if(a<0) {
flag = -1;
}else {
int b = (o1.value[2]*256 + o1.value[3]) - (o2.value[2]*256 + o2.value[3]);
if(b<0){
flag = -1;
}else if(b==0) {
flag = 0;
}
}
return flag;
}
// 处理输入的ip
public static IP toIp(String rawIp) {
int split = rawIp.indexOf('/');
String value = rawIp;
int mask = 0;
// 含有'/',分割
if(split>0) {
value = rawIp.substring(0, split);
mask = Integer.parseInt(rawIp.substring(split+1, rawIp.length()));
}
IP ip = new IP();
ip.mask = mask;
// 处理地址
for(int i=0;i<4;i++) {
if(value.contains(".")) {
// 继续分割
split = value.indexOf('.');
ip.value[i] = Integer.parseInt(value.substring(0,split));
value = value.substring(split+1,value.length());
}else if(value.length()>0) {
// 只有数字
ip.value[i] = Integer.parseInt(value);
value = "";
// 若无前缀长度
if(ip.mask==0) {
ip.mask = (i+1)*8;
}
}else {
// 空
ip.value[i] = 0;
}
}
return ip;
}
}
呜呜呜90了
终于把同级合并改对了
看看还能不能快一点
把最后的遍历从链表改成了数组,成功!
awsl