微软2016年实习生在线笔试第二题(403 Forbidden)
来源:互联网 发布:现在淘宝卖衣服赚钱吗 编辑:程序博客网 时间:2024/05/02 12:19
题目2 : 403 Forbidden
- 样例输入
5 5allow 1.2.3.4/30deny 1.1.1.1allow 127.0.0.1allow 123.234.12.23/3deny 0.0.0.0/01.2.3.41.2.3.51.1.1.1100.100.100.100219.142.53.100
- 样例输出
YESYESNOYESNO
描述
Little Hi runs a web server. Sometimes he has to deny access from a certain set of malicious IP addresses while his friends are still allow to access his server. To do this he writes N rules in the configuration file which look like:
allow 1.2.3.4/30deny 1.1.1.1allow 127.0.0.1allow 123.234.12.23/3deny 0.0.0.0/0
Each rule is in the form: allow | deny address or allow | deny address/mask.
When there comes a request, the rules are checked in sequence until the first match is found. If no rule is matched the request will be allowed. Rule and request are matched if the request address is the same as the rule address or they share the same first mask digits when both written as 32bit binary number.
For example IP "1.2.3.4" matches rule "allow 1.2.3.4" because the addresses are the same. And IP "128.127.8.125" matches rule "deny 128.127.4.100/20" because 10000000011111110000010001100100 (128.127.4.100 as binary number) shares the first 20 (mask) digits with10000000011111110000100001111101 (128.127.8.125 as binary number).
Now comes M access requests. Given their IP addresses, your task is to find out which ones are allowed and which ones are denied.
输入
Line 1: two integers N and M.
Line 2-N+1: one rule on each line.
Line N+2-N+M+1: one IP address on each line.
All addresses are IPv4 addresses(0.0.0.0 - 255.255.255.255). 0 <= mask <= 32.
For 40% of the data: 1 <= N, M <= 1000.
For 100% of the data: 1 <= N, M <= 100000.
输出
For each request output "YES" or "NO" according to whether it is allowed.
Analysis
本题非常适合我这样的菜鸟:读完题目很容易有一个基本的思路,换句话说,这可以实现这个功能,但不保证性能。
Naive Approach
由题意直观的可以想到以下做法:
- 设计一个类,描述配置规则;
- 按读入顺序保存读入的所有规则;
- 对于每一个待检验的IP,从头遍历规则,若匹配,返回规则的动作;否则,返回允许。
仔细想想Naive Approach的问题,对于一个IP,每次检查的时候复杂度为O(n),特别地,当这个IP没有任合匹配规则时,要尝试完所有的规则。 有什么办法可以准确的知道一个IP适用哪些规则呢?当然,所谓“适用”其实,题目说明的很清楚,即IP的mask
长的前缀必须匹配。
前缀匹配问题,可以用前缀树来解决。因此,可以利用前缀树来确定哪些规则可以适用于一个IP。
Trie Approach
于是有了下面的想法:
- 规则集利用前缀树描述
- 前缀树每个结点记录,到本结点是否为一个规则,规则要求的动作是什么,规则的序号。
- 对于一个IP,遍历前缀树,找到所适用规则中序号最小的,返回该规则的要求,若没有适用规则,返回允许。
- 一个IPv4的地址大小为32bit,也就是可以在常量时间找到适用规则。
至此,剩下的问题就是如果建立前缀树,由于题意要求,最早匹配原则,树的建立可以这样做:
- 若插入新规则i时,该规则的前缀路径上已有规则j, 则规则j的序号一定比i小,也即,规则i被j屏蔽,直接丢弃i即可。
- 注意第一条中,当规则i和j等长时,也适用。
由此,当检查一个IP时,只需要返回这个IP适用的最长规则(为什么?上面的性质可以想一想)
Solution:有了上面的规则,代码就比较简单了。
下面是完整的代码:
#define _CRT_SECURE_NO_WARNINGS#include <iostream>#include <string>using namespace std;//trie节点定义class trieNode {public: trieNode() : order(0) { for (int i = 0; i < 2; ++i) children[i] = NULL; } ~trieNode() { for (int i = 0; i < 2; ++i) { if (children[i] != NULL) { delete children[i]; children[i] = NULL; } } }public: int order; //1 is allow,-1 is deny trieNode *children[2]; //该数组记录指向孩子的指针}; //trie树定义class trie {public: trie() : root(new trieNode) {} void insert(unsigned int ip, int mask, int order); //插入ip bool find(unsigned int ip); //查找ippublic: trieNode *root;};void trie::insert(unsigned int ip, int mask, int order) { trieNode *cur = root; for (int i = 0; i < mask; ++i) { if (cur->order) return; int bit = (ip >> (31 - i)) & 0x01; if (!cur->children[bit]) { cur->children[bit] = new trieNode; } cur = cur->children[bit]; } if (!cur->order) //若原先已经有该条规则,则不覆盖(就先原则) cur->order = order; //设置属性:allow 或 deny}bool trie::find(unsigned int ip) { trieNode *cur = root; int order = 1; for (int i = 0; i < 32; ++i) { int bit = (ip >> (31 - i)) & 0x01; if (cur->order) { order = cur->order; } if (!cur->children[bit]) { break; } cur = cur->children[bit]; } return order > 0 ? true : false;} int main(){ int N, M; cin >> N >> M; trie rule; //define a trie for (int i = 1; i <= N; ++i) { string cmd; //allow or deny cin >> cmd; char ch; unsigned int a, b, c, d, ip; cin >> a >> ch >> b >> ch >> c >> ch >> d; ip = (a << 24) | (b << 16) | (c << 8) | d; int mask = 32; cin >> ch; if (ch == '/') cin >> mask; else cin.putback(ch); //将刚才读取的ch字符返回到输入流中 int order = 1; if (cmd != "allow") order = -1; rule.insert(ip, mask, order); } for (int i = 0; i < M; ++i) { unsigned int a, b, c, d, ip; char ch; cin >> a >> ch >> b >> ch >> c >> ch >> d; ip = (a << 24) | (b << 16) | (c << 8) | d; if (rule.find(ip)) cout << "YES" << endl; else cout << "NO" << endl; } system("pause"); return 0;}
Complexity
- 时间复杂度:建前缀树O(n) 每一个IP检测O(1) 总体O(min(n, m))
- 空间复杂度:主要是缀树空间,树高32(33?),至多m个叶子结点,每个叶子结点至多一个父结点。即O(m)
- 微软2016年实习生在线笔试第二题(403 Forbidden)
- 微软2016实习生笔试--第二题403 Forbidden
- 2016年4月微软在线笔试第二题-403 forbidden
- 微软2016校招4月在线笔试——第二题 403Forbidden
- 微软2017实习生在线笔试题——hihocoder 1289——403 Forbidden
- 2016微软在线编程2:403 Forbidden
- 微软笔试题2:403 Forbidden
- 微软2016校园招聘4月在线笔试2-403 Forbidden
- 微软2016校园招聘4月在线笔试 hihocoder 1289 403 Forbidden
- [Hihocoder 1289] 403 Forbidden (微软2016校园招聘4月在线笔试)
- hihocoder 1289 微软2016校园招聘4月在线笔试-2:403 Forbidden
- 微软2016校园招聘4月在线笔试2-403 Forbidden
- 2015.4.3微软在线笔试第二题
- 微软2014年实习生在线机试第二题及解法
- 2016腾讯实习生在线笔试题
- 京东2016笔实习生在线笔试题
- 2017年腾讯实习生在线笔试编程题(1)
- 2016腾讯实习生在线笔试
- 开发等其他有用网址收藏
- js实现时间
- 实现向服务器上传图片文件、实现不同方式的form表单提交方式
- iOS正则表达式之手机号的验证
- Android视频播放: SurfaceView+MediaPlayer播放视频(二)
- 微软2016年实习生在线笔试第二题(403 Forbidden)
- Java基础语法知识之数据类型
- 人性化的HSL模型
- 专题二 1014
- hadoop运行环境安装与配置+hadoop开发环境配置(二)
- 关于Android启动模式的点点滴滴
- 专题二 1017
- java多线程开发 如何正确关闭线程
- 数据库添加新表时如何判断原来是否存在该表