allow 1.2.3.4/30 deny 1.1.1.1 allow 127.0.0.1 allow 123.234.12.23/3 deny 0.0.0.0/0
输入 ip 按顺序匹配规则,优先匹配前面的规则,如果没有规则可以匹配则视为合法。注意:掩码为 0 的时候表示匹配所有 ip。
一开始做的时候用遍历匹配的方法,直接超时了。后来才想到用字典树的方法来做,这道题本质上是一道字典树变形。
class Node { byte flag;//0代表普通节点,1代表允许规则终点,2代表禁止规则终点 int seq;//规则顺序 Node[] next = new Node[2]; Node(byte flag){ this.flag = flag; } }
mask = 32
代码如下:
public void insert(String ip, byte flag) { seq++; int mask = 32; int index = ip.indexOf('/'); //检测是否有掩码 if (index != -1) { mask = Integer.parseInt(ip.substring(index + 1)); } else { index = ip.length(); } //把ip地址转化为二进制形式 String binary = toBinary(ip.substring(0, index)); char[] binarys = binary.toCharArray(); Node node = root; for (int i = 0; i < mask; i++) { int pos = binarys[i] - '0'; if (node.next[pos] == null){ node.next[pos] = new Node((byte) 0); } node = node.next[pos]; } //后面的规则不能覆盖前面的 if (node.flag == 0){ node.flag = flag; } if (node.seq == 0) { node.seq = seq; } }
代码如下:
public boolean isAllow(String ip){ String binary = toBinary(ip); char[] binarys = binary.toCharArray(); Node node = root; int seq = Integer.MAX_VALUE; boolean isAllow = true; int i = 0; int pos = 0; while (node != null){ //字典树最多会有33个节点,而ip的二进制最多只有32位 //另一种避免判断的方法是在ip的二进制后面补一个0 if (i < binarys.length){ pos = binarys[i] - '0'; } if (node.flag == 1){ if (node.seq < seq){ isAllow = true; seq = node.seq; } } else if (node.flag == 2){ if (node.seq < seq){ isAllow = false; seq = node.seq; } } else { //flag=0说明是普通节点,直接跳过即可。 } node = node.next[pos]; i++; } return isAllow; }
完整代码