您的位置:首页 > 其它

2016年4月微软在线笔试第二题-403 forbidden

2016-04-15 20:15 197 查看
本地运行没有错误,提交上去以后反馈RE,实在想不通,求大神帮看/(ㄒoㄒ)/~~

import java.util.ArrayList;
import java.util.Scanner;

public class Main {
int allowS = 0;//rules allow数组大小
int denyS = 0;
ArrayList<String> allow = new ArrayList<>();//用来存放动态变化的rules,整个类都要使用,则定义为实例变量
ArrayList<String> deny = new ArrayList<>();

public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int N = input.nextInt();
int M = input.nextInt();
Main webser = new Main();
if(1<=N && M<=100000){
webser.rules(N);
String[] output = webser.request(M);
for(int j=0;j<output.length;j++){
System.out.println(output[j]);
}
//sca.close();//写完之后就要close,否则容易忘记
}
input.close();

}
/*
* @param n为rules个数,此方法用来封装rules
*/
public void rules(int n){

@SuppressWarnings("resource")
Scanner sca = new Scanner(System.in);
for(int i=0;i<n;i++){
String s = sca.nextLine();
String[] rule = s.split(" ");//返回字符串数组
if(rule[0].equals("allow")){
allow.add(rule[1]);
allowS++;
}else if(rule[0].equals("deny")){
deny.add(rule[1]);
denyS++;
}
}
//sca.close();如果把这个流关闭了,再调用request方法中的输入流就不行了
}
public String[] request(int m){
//开始匹配,最优的应该是用正则表达式匹配,稍后优化
String[] output1 = new String[m];//没问题
String[] requ = new String[m];//创建请求数组
@SuppressWarnings("resource")
Scanner sca = new Scanner(System.in);
for(int i=0;i<m;i++){
requ[i] = sca.nextLine();//输入请求ip数组
}
//开始遍历每一次request是否符合命中rules
circle:
for(int j=0;j<m;j++){
for(int k=0;k<allow.size();k++){
if(requ[j].equals(allow.get(k))){
output1[j] = "YES";//return "YES";
continue circle;
}else if(allow.get(k).contains("/")){
String requBinary =IPtoInt.ipToint(requ[j]);
String[] allowip = allow.get(k).split("/");
int mask =Integer.parseInt(allowip[1]);//取位数
String allowstr = IPtoInt.ipToint(allowip[0]);
//String allowMask = allowstr.substring(0,mask);//变成字符串后,取前几位
if(requBinary.substring(0, mask).equals(allowstr.substring(0,mask))){
output1[j] = "YES";//return "YES";
continue circle;

}
}
}
for(int k=0;k<deny.size();k++){
if(requ[j].equals(deny.get(k))){
output1[j] = "NO";//return "NO";
continue circle;
}else if(deny.get(k).contains("/")){
String requBinary = IPtoInt.ipToint(requ[j]);
String[] denyip = deny.get(k).split("/");
int mask = Integer.parseInt(denyip[1]);
String denystr = IPtoInt.ipToint(denyip[0]);
String denyMask = denystr.substring(0,mask);
if((requBinary.substring(0,mask)).equals(denyMask)){//必须对比前mask位
output1[j] = "NO";//return "NO";
continue circle;
}
}
}
if(output1[j].length()==0)
output1[j] = "YES";

}
//sca.close();
return output1;//返回字符串数组
}
}
class IPtoInt {
// 重写了方法,将ip地址转换为二进制。
public static String ipToint(String strIP) {
String[] ip = new String[4];
String zero = "00000000";//用来补位的
String[] ipstr = strIP.split("\\.");
// 将每个.之间的字符串转换成整型
ip[0] = Integer.toBinaryString(Integer.parseInt(ipstr[0]));
ip[1] = Integer.toBinaryString(Integer.parseInt(ipstr[1]));
ip[2] = Integer.toBinaryString(Integer.parseInt(ipstr[2]));
ip[3] = Integer.toBinaryString(Integer.parseInt(ipstr[3]));
for(int i=0;i<4;i++){
if(ip[i].length()<8){
ip[i] =zero.substring(0,8-ip[i].length()) + ip[i];//如果每一段ip不足八位,那么用字符串加法高位补0,不用循环,一次性补0,因为ip.length()一直会变
}
}
return ip[0]+ip[1]+ip[2]+ip[3];
}
}


哈哈哈哈,仰天苦笑三声,胡汉三又回来啦。后面debug了一下,搞了两天终于找到错误的原因了,原来
if(output1[j].length()==0)
output1[j] = "YES";

这一句,写了可空指针,笨呐,然后解决方案是给输出结果的数组output[j]赋初值“YES”,因为如果没有一个rules match,那就是“YES”

后面改了代码后,提交上去还是wrong answer,说明,我有只考虑了一部分测试数据,还有更多的数据是错的,在网上寻求帮助后,终于看到了一位网友的提点:并没有符合一旦match rules即跳出匹配的条件。于是,我重写了request这个方法,变成,每次只判断一行rule与该request是否匹配。而我一直找不到一个条件,用来判断如果没有rules匹配成功,怎么给output数组赋“YES”,后来,我就想到了一个,本人认为,是这个程序里面唯一的亮点(哭),加了个return “noMatch”,这个字符串来决定,请求是否匹配上rules,因为不管是allow还是deny,都是匹配,只不过匹配后返回的信息不同,这也是后面舍弃将allow和deny分别装在两个链表的原因。

更改后的代码,提交后是time limited error,有人提议用前缀树、后缀树减小复杂度,实在改不动了。一个代码,改出七八个bug,花了一个星期,我也真是差劲。
import java.util.Scanner;
//微软笔试第二题 403 forbidden,第四版,改变存放rules结构,不把allow和deny分开,按rules顺序匹配(字符串匹配处理,未加前缀树),时间复杂度粗略估计为o(n^3)
public class Main {

Main(Scanner in){
int N = in.nextInt();
int M = in.nextInt();
@SuppressWarnings("unused")
String delete = in.nextLine();
if(1<=N && M<=100000){
String[] rules = new String
;//读取rules数组
for(int i=0;i<N;i++){
rules[i] = in.nextLine();
}
String[] request = new String[M];//读取request数组
for(int j=0;j<M;j++){
request[j] = in.nextLine();
}
/*
* @param output[]为输出结果
*/
String[] output = new String[M];
for(int j=0;j<M;j++){
for(int i =0;i<N;i++){
output[j]=matchRules(request[j], rules[i]);
if(output[j].equals("noMatch")){
output[j] = "YES";
continue;
}else{
break;
}

}
System.out.println(output[j]);
}
}
in.close();
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
@SuppressWarnings("unused")
Main forbidden = new Main(in);

}
/*
* @param n为rules个数,此方法用来封装rules
* @param s为每一行读取的rules string
*/
public String matchRules(String request,String rules){

String[] ruleSplit = rules.split(" ");//把rules前面的标记和ip分割
if(ruleSplit[0].equals("allow")){
if(request.equals(ruleSplit[1])){
return "YES";
}else if(ruleSplit[1].contains("/")){
String requBina = IPtoInt.ipToint(request);
String[] ruleSplit2 = ruleSplit[1].split("/");//rule后面有/的分割
int mask = Integer.parseInt(ruleSplit2[1]);
String ruleBina = IPtoInt.ipToint(ruleSplit2[0]);
if(requBina.substring(0,mask).equals(ruleBina.substring(0,mask))){
return "YES";
}
}
}else if(ruleSplit[0].equals("deny")){
if(request.equals(ruleSplit[1])){
return "NO";
}else if(ruleSplit[1].contains("/")){
String requBina = IPtoInt.ipToint(request);
String[] ruleSplit2 = ruleSplit[1].split("/");//rule后面有/的分割
int mask = Integer.parseInt(ruleSplit2[1]);
String ruleBina = IPtoInt.ipToint(ruleSplit2[0]);
if(requBina.substring(0,mask).equals(ruleBina.substring(0,mask))){
return "NO";
}
}
}
return "noMatch";

}

}
class IPtoInt {
// 重写了方法,将ip地址转换为二进制。这个方法不错,比原方法简单
public static String ipToint(String strIP) {
String[] ip = new String[4];
String zero = "00000000";//用来补位的
String[] ipstr = strIP.split("\\.");
//整形转换为字符串二进制,tobinarystring这个函数本身,就不会补八位
ip[0] = Integer.toBinaryString(Integer.parseInt(ipstr[0]));
ip[1] = Integer.toBinaryString(Integer.parseInt(ipstr[1]));
ip[2] = Integer.toBinaryString(Integer.parseInt(ipstr[2]));
ip[3] = Integer.toBinaryString(Integer.parseInt(ipstr[3]));
for(int i=0;i<4;i++){
if(ip[i].length()<8){
ip[i] =zero.substring(0,8-ip[i].length()) + ip[i];//如果每一段ip不足八位,那么用字符串加法高位补0,不用循环,一次性补0,因为ip.length()一直会变
}
}
return ip[0]+ip[1]+ip[2]+ip[3];
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: