最早开始关注360应该是从著名的『3Q』大战开始吧,当时觉得敢于和腾讯在QQ尚为PC霸主的年代为敌的公司应该也不是什么善茬。后来由于360也算是PC上『全家桶』鼻祖的原因,对于这家公司或多或少有一些偏见。再后来由于大学室友做安全方面的原因,开始逐渐了解这家典型的技术驱动型公司。这家公司就像它的创始人老周的为人一样,简单、直接,敢于和任何人、任何公司在自己认准的领域『为敌』。另外360前台的小姐姐真的非常漂酿,可以去当明星了。
第一轮面试
1. 自己动手实现C语言函数memcpy()
我自己其实对于C语言不是那么熟悉,这个函数之前也没用过,但是上星期恰好面试小米的时候,面试官出过相似的问题,加上自己也在上面的文章中总结过,所以直接将memmove()的实现写上了。下面的是在网上查到的版本,也就是将内存重叠问题考虑在内的优化版。
void* memcpy(void *dst, const void *src, size_t size) {
char *psrc, *pdst;
if (dst == NULL || src == NULL)
return NULL;
if (dst <= str) {
psrc = src;
pdst = dst;
while (size--)
*pdst++ = *psrc++;
} else {
psrc = src + size - 1;
pdst = dst + size - 1;
while (size--) {
*pdst-- = *psrc--;
}
return pdst;
}
2. 给定一个非负数N,代表有N对"()",要求将括号成对的所有情况输出。例如给定的数为3,则共有如下的4种情况。
( ) ( ) ( )
( ( ) ) ( )
( ) ( ( ) )
( ( ( ) ) )
我给出的两种方案后面经过证实都是有问题,下面的程序为正解。
http://www.code123.cc/841.html
void print_pare(int l, int r, char str[], int cnt) {
if (l < 0 || r < 0) return;
//当左、右两边括号剩余都为0时打印字符串
if (l == 0 && r == 0) {
for (int i = 0; i < cnt; ++i)
cout << str[i];
cout<<endl;
} else {
//当左边括号剩余大于0时,左括号可以插入
if (l > 0) {
str[i] = '(';
print_pare(l - 1, r, str, cnt + 1);
//当右括号剩余大于做括号时,右括号可以插入
} else {
str[i] = ')';
print_pare(l, r - 1, str, cnt + 1);
}
}
}
3. 要求自己定义相应的数据结构,从上到下打印一颗二叉树。
struct BinaryTreeNode {
int val;
BinaryTreeNode* left;
BinaryTreeNode* right;
};
void PrintTreeFromTopToBottom (BinaryTreeNode* root) {
if (root) {
queue<BinaryTreeNode*> TreeNodes;
TreeNodes.push(root);
while (!TreeNodes.empty()) {
BinaryTreeNode* pNode = TreeNodes.front();
TreeNodes.pop();
printf("%d ", pNode->val);
if (pNode->left) TreeNodes.push(pNode->left);
if (pNode->right) TreeNodes.push(pNode->right);
}
}
}
当我完成上述代码后,面试官又问我能否将上述代码改一下,变成按层输出。我当时的想法是增加一个变量记录每层节点数,下层节点数则为2陪,每当输出一个节点,变量减1,当变量为0是,该层打印完毕。思路是对的,但是需要两个变量,一个用来记录当层节点数,一个用来记录下一层的节点数。
struct BinaryTreeNode {
int val;
BinaryTreeNode* left;
BinaryTreeNode* right;
};
void PrintTreeFromTopToBottom (BinaryTreeNode* root) {
if (root) {
queue<BinaryTreeNode*> TreeNodes;
TreeNodes.push(root);
int current = 1, next = 0;
while (!TreeNodes.empty()) {
BinaryTreeNode* pNode = TreeNodes.front();
TreeNodes.pop();
--current;
printf("%d ", pNode->val);
if (pNode->left) {
++next;
TreeNodes.push(pNode->left);
}
if (pNode->right) {
++next;
TreeNodes.push(pNode->right);
}
if (current == 0) {
printf("\n");
current = next;
next = 0;
}
}
}
}
4. 关于动态联编的,给了如下两条语句,问会不会出现问题。经过Google,这应该就是原题 http://coolshell.cn/articles/9543.html/
Base *p = new Derived[10];
delete [] p;
会出现的问题及原因耗子哥已经写的很清楚了,在这里我就不再赘述了。
5. TCP头部有哪些字段。
这种类似的问题好几家公司也都问过了http://6152587.blog.51cto.com/6142587/1229425
6. 除此之外还问了几个非技术方面的问题。比如,如果你所在的公司使用版本控制工具,但在某一次上传代码的过程中只能在你和同事之间的版本二选一,你是否会选择将同事的代码进行覆盖。
我问他能否先和同事进行一下沟通,他说不能。然后,我的回答是选择上传我的代码,由于我比较相信自己。
然后,他告诉我,在任何情况下都不能将同事的代码在未经同意的情况下将其覆盖。否则,这即使对别人劳动的不尊重,也会损害自己的名声,而且在公司如果每个人都这么干的话会产生严重的后果。
这里,正确的方法是,选择将自己的代码进行备份或者分支,等到能和同事进行沟通的时候再具体解决。
除此之外,他还和我聊了将来服务端和客户端程序猿谁的发展更好等等,收益颇丰。我还问他对于现而言,我那方面最需要提高,他的回答是,工程能力。好吧,又回到这了,我特么到底啥时候才能工作!
第二轮面试
二轮面试在下午,他没问基础算法和数据结构上的问题,而是问了我些其他问题,生活和学习方面的都有。
比如我在生活和学习中遇到过最具有挑战的一件事,我是怎么解决的;如果让你学习一门新的语言,你将怎么学(比如公司需要的golang);使用过哪些unix系统C++API,和windows的区别在哪;如何理解服务器系统的I/O操作(我都不清楚这是什么,http://www.cnblogs.com/hustcat/archive/2010/04/10/1708909.html);对于同步异步、阻塞非阻塞的是否了解;对于STL的底层实现是否进行过研究等等。
总体来说聊的时间不够长,原因只有一个,就是我对上面那些问题真的不熟悉,就是自己太菜了。用他的话来说,就是对于系统编程方面的能力不够。哎,啥也别说了,还是赶紧学习吧。
第三轮面试
聊了挺长时间的,从薪资到福利待遇,从人生到理想,方方面面的。
结果
面试完第二天,HR给我打电话发了口头offer,下周一就要入职了。这也算是自己满意的公司,这漫长的找工作之旅,这痛苦的一年多终于结束了,我要开始新生活啦!