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

本地运行没有错误,提交上去以后反馈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[N];//读取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];
    }
 } 
 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值