小弱石的求职季笔记(二)
比较知名的互联网公司就只投了网易和欢聚,其它的都完美错过......
于是从欢聚那失败归来后,赶紧印了数份简历,每天跑来跑去听宣讲会。
厦门这边正好就来了几家搞游戏的,于是就去看了...
三、厦门吉比特,游戏研发(一面挂,后来问要不要先去实习看看,如果能力可以会转正,没去)
刚看到这个公司的时候,感觉从来没见过...然后看了介绍,居然是以前做出《问道》的那家公司。
吉比特今年开出的待遇非常好,技术类月薪12k~18k,福利在厦门也是比较好的,笔试的时候整个大教室都坐满了,竞争挺激烈的。
笔试的话大部分都是c/c++的基础题,还有一些算法题,也参杂一了些Java和操作系统的问题,平时有做过题目的话基本上就OK。
然后顺利进入一面,面试官挺好的,比较有耐心,也不会专门往***钻的地方提问。
开始时先让自我介绍,然后大概问了一点基本情况,学习成绩什么的,然后就开始问笔试时的一些题。
1. 第一个是最大子序列和问题:
a. 当时不记得动态规划怎么写了,就说了O(n^2)的解法:
int subMaxSum_1(int input[], int size) {//对数组每一位,计算其向后累加和,累加过程中记录最大值,最终结果即为所求最大值 //O(n^2) int subMax = 0; for(int i = 0; i < size; i++) { int sum = 0; for(int j = i; j < size; j++) { sum += input[j]; if(sum > subMax) { subMax = sum; } } } return (subMax > 0) ? subMax : 0 ; }
b. 回去后把动态规划(O(n))的方法撸了出来,加深印象:
int subMaxSum_2(int input[], int size) {//利用动态规划方法 //nAll[i] = max(input[i], nEnd[i], nAll[i-1]) //nAll为0~i的最大的一段数组和,nEnd是包含input[i]在内的最大一段数组和 //O(n) int subMax = 0; int nEnd = input[0]; int nAll = input[0]; for(int i = 1; i < size; i++) { nEnd = max(nEnd + input[i], input[i]); nAll = max(nEnd, nAll); } return nAll; }
2. 第二个问题是最长相同子序列问题,当时好久没看算法,把这个给忘了,感觉要想出来可能还得思考一段时间,于是就说不太会,换个问题。回去后赶紧把这个问题撸出来,以防以后再问:
int subSequenceMax(char *str_1, char *str_2) { //动态规划方法,O(n^2) int len_1 = strlen(str_1); int len_2 = strlen(str_2); int **maxLen; maxLen = (int**) malloc(sizeof(int*) * (len_1 + 1)); for(int i = 0; i < len_1; i++) { //申请空间,需要注意用for循环分别申请 maxLen[i] = (int*) malloc(sizeof(int) * (len_2 + 1)); } for(int i = 0; i <= len_1; i++) { for(int j = 0; j <= len_2; j++) { if(i == 0 || j == 0) { //对矩阵进行初始化 maxLen[i][j] = 0; continue; } if(str_1[i - 1] == str_2[j - 1]) { //如果检查到相同字符,则加1 maxLen[i][j] = maxLen[i - 1][j - 1] + 1; } else { //如果是不同的字符,矩阵内对应的值为前一情况中的最大值 maxLen[i][j] = max(maxLen[i - 1][j], maxLen[i][j - 1]); } } } for(int i = 0; i <= len_1; i++) { for(int j = 0; j <= len_2; j++) { cout << maxLen[i][j] << " " ; } cout << endl; } int result = maxLen[len_1][len_2]; return result; }主要是推出来递推的表达式就搞定了~
3. 换了个问题,就开始让我手写算法了,求1~100的素数,这题看似容易,实际上还有些要稍微深入讨论的问题...
a. 首先想到的就是,遍历and对每个数检查到其开根号的位置:void method_1(int n, int m) { for(int i = n; i <= m;) { bool flag = true; for(int j = 2; j * j <= i; j++) { //这里原本写的是 j <= sqrt(i) + 1, 面试官说,实际上sqrt开销比较大,让我看看怎么更快处理这个地方 //当时就想着 i 开根号有什么更高效的方法,就没想出来,结果竟是 j * j 来替换,头脑没转过弯来啊hh,以后得记住喽 if(i % j == 0) { flag = false; break; } } //if(flag) cout << i << " "; if(i % 2 == 0) i++; else i += 2; } cout << endl; }这里面试官还问,为什么检查到开根号位置就行了,当时本来是有思路说出来的,结果突然想到16,开根号是4,但是又有2 * 8 = 16,突然就短路了......
实际上,如果一个数x = m * n 如果m和n都大于sqrt(x) 则m * n大于x,故肯定有一个因子小于sqrt(x),于是只需要检查到sqrt(x)就够了。
b. 然后面试官说,对于每个非素数都有一个性质,就是它定能分解成素数的乘积,于是利用这个性质再写这个算法,当时由于直接再原来写的算法上补写,写得比较乱,不过基本上是写对的,实际代码应如下:
void method_2(int n, int m) {//利用非素数可以分解为素数乘积的性质,对每个数先采用已知大于1的素数进行测试 //若已知数已测完还未达到开方条件,则再依次加1进行判断 int *result = new int[m]; //记录已找到的素数,用于之后的检查 int count = 0; for(int i = 1; i <= m; i += 2) { bool flag = true; int j = 2; for(int z = 1; z < count; z++) { j = result[z]; if(j * j > i) { break; } if(i % j == 0) { flag = false; j = i; break; } } for(; j * j <= i; j++) { if(i % j == 0) { flag = false; break; } } if(flag) result[count++] = i; } for(int i = count - 1; i >= 0; i--) { if(result[i] < n) { break; } else { cout << result[i] << " "; } } cout << endl; delete result; }
代码实际跑了一下,检查1~10w的素数,确实第二个方法快了很多倍。
最后面试官的评价是:基础不错,学习能力不错,但实际经验太少,需要加强。
过了几天通知面试没过,又再过了几天打电话来问要不要去实习,当时很犹豫,因为没有offer......
四、厦门极致游戏,游戏研发(二面后,没过)
这个极致游戏的老板是当年搞出问道的人,前几年从吉比特出来自己搞了这个公司,目前发展得不错,虽然没有红爆半边天的游戏,但是今年也已经上市了......而且这公司关于加班的理念、制作游戏的理念也比较符合我个人理念,当时二面后就想着,如果能给offer就直接毫不犹豫签了,在这个地方肯定能好好做技术,以后发展机会大,而且开出的薪酬也不错,有6k~10k,福利很多,在厦门这待遇已经是很好了。
燃鹅没拿到offer,这就尴尬啦...
笔试的话也是比较基础的题,不过比较坑的是,有两个大部分:逻辑题,专业题。
逻辑题就是那种智力题,从几个人说的话中获取信息,判断出每个人是什么身份之类的。花了挺多时间在这部分,后来发现不太好做,做了大概3题就赶紧去做专业题了。
专业题不难,也都是些基础的东西,总之算法和数据结构、c/c++基础基本上都是必考的。
一面技术面,面试官主要是问个人做过的项目上的问题,我在简历上写了个Java分布式爬虫的项目,于是就开始追根究底......只要项目自己是有认真做,基本上没太大问题就是。然后也问到了虚函数,这时候对虚函数有过复习,但是没有实际上机去试试,结果...
项目之外的问题主要就是虚函数相关问题,问题其实都挺简单,但当时没答上来,吸取教训,把虚函数相关问题复习复习:
1. 虚函数:
在基类中冠以virtual的成员函数,它提供一种接口界面,允许在派生类中对基类的虚函数重新定义。其主要作用是实现多态。
(多态:是对于不同对象,接收相同消息时,产生不同的动作。)
2. 虚析构函数有什么用处:
一般基类的虚构函数都会声明为虚函数,这是为了防止内存泄露问题的发生。如果不声明为虚函数,当使用基类指向派生类的指针调用析构函数时,只会执行基类的析构,如此子类无法正确析构,导致内存泄露。这里要注意,纯虚析构函数需要给出定义。
3. 纯虚函数:
在基类中为其派生类保留一个函数的名字,以便派生类根据需要对它进行定义。作为接口而存在。纯虚函数一般不能直接调用。
例子: virtual void demo() = 0; 注意这里不用实现。
二面就是HR面了,感觉交谈得挺愉快的,有种这次能成的错觉......
最后总结,还是因为实际经验太少,有很多实战时的最基本的问题,比如虚析构函数作用这类问题都不了解。
得多撸代码才行啊!~
五、厦门飞鱼科技,游戏研发(一面未过)
飞鱼,就是开发了《保卫萝卜》的那个,待遇不错,不过没明说。不过据说加班比较多......
笔试题目基本上也没什么问题。
一面本来是技术面,然而进去后一个面试官直接就开玩手机,然后另一个让我自我介绍。
介绍完后,基本上就是根据简历上面写的项目问了问,也没怎么深入。
感觉就是看不上我,走个流程赶人吧,总之并没问什么技术问题......
目前比较需要记录的就是这几个了......接下来还得继续战斗,跑宣讲会,刷笔试......
给自己加油!