新浪实习

tinyfisher 发表于 2013-12-16

今天第一天去新浪实习,吐槽下实验室,一直不让实习,太黑。最近比较闲,没啥面试,论文也差不多了,终于找到了人生第一份实习,也算是和北京告别的第一天。当年怀着无比向往的心情来到帝都,时间真快,一转眼就要离开了,从一开始不适应这里干燥的空气,鼻子出血,到现在已经习惯了这里的气侯,甚至雾霾,真要离开竟有一丝不舍,因为这里是北京,有着五彩斑阑的机会和无限的可能,有着无数年轻人的梦想。告别帝都从新浪实习开始吧。第一天,人工查看是否是垃圾邮件,编写python脚本自动发邮件进行测试,代码如下

import smtplib
from email.mime.text import MIMEText
mailto_list=["yxh.8116836@163.com","tinyfisher@foxmail.com"] 
mail_host="smtp.sina.cn"   
mail_user="tinyfisherbupt" 
mail_pass="*****"    
mail_postfix="sina.com"    
def send_mail(to_list,sub,content):    
    me=mail_user+"<"+mail_user+"@"+mail_postfix+">"
    msg = MIMEText(content)
    msg['Subject'] = sub
    msg['From'] = me
    msg['To'] = ";".join(to_list)
    try:
        s = smtplib.SMTP()
        s.connect(mail_host)
        s.login(mail_user,mail_pass) 
        s.sendmail(me, to_list, msg.as_string())
        s.close()
        return True
        except Exception, e:
        print str(e)
        return False
if __name__ == '__main__':
    if send_mail(mailto_list,"subject","content"):
        print "send success"
    else:
        print "send fail"

需要注意的是,你的邮箱需要开启smtp/pop3,登录到你的web邮箱,在里面的设置里开启

一道有趣的面试题

tinyfisher 发表于 2013-10-15

题目:给你两个骰子,每个骰子的6个面都是空的,现在要你把0~9这10个数填到这两个骰子的12个空白面上(数字可以重复),使得能够用这两个骰子表示一个月的号数:从01到31(出自中清龙图)

提示:这两个骰子中的数既可以表示十位,又可以表示个位

思路:1.那就先看从01到09怎么填吧

例如两个骰子A,B;我首先在A中填0,在B中填1,2,3,4,5 此时,按照AB的摆放,可以表示01到05,我再在B中填0,A中填6,7,8,9,此时按照BA的摆放,可以表示06到09,这时A六个面:0,6,7,8,9,空;B中六个面:1,2,3,4,5,0
此时A中还剩一个空位,B已经满。

2.再来看10~19怎么填
因为B中有1,按照BA的摆放,可以表示10,16,17,18,19;要表示其他的必须在A中存放1,此时A:0,6,7,8,9,1;按照AB摆放,可以表示:11,12,13,14,15,10;
此时A,B都满了,其中A:0,6,7,8,9,1;B:1,2,3,4,5,0;
3.再看20~29:
因为B中有2,按照BA摆放,可以表示:20,26,27,28,29,21;可A中已经满了,怎么表示其他的数呢?
面试官提示:如果A有7个面,你怎么做?
如果A有7个面,那我按照上面的思路,在A中再填2,此时A:0,6,7,8,9,1,2;按照AB的摆放可以表示20,21,22,23,24,25;至于30,31是没有问题的。
现在的问题就是:2个骰子12个面,如果13个面,问题解决,但少了一个面,能否将某些数字压缩?

面试官提示:首先看看那些数字是必须存在于两个骰子?看看0,1,2是否必须存在?

首先1和2肯定存在,因为要表示11和22,0也是必须存在,若只有一个面有0,肯定不能表示01到09;
ok,此时A:0,1,2;B:0,1,2;那么还剩下6个面和7个数:3,4,5,6,7,8,9,现在的问题是:怎么把这7个数压缩成六个?
我:“这不可能吧?”
面试官:“我给你的是骰子,不是数组,想想有没有其他方法?”
我:“我用刀切一个骰子,变成13个面”(囧)
面试官:“我可没给你刀,骰子可以随意摆,再想想?”
我:“难道是6跟9算一个?”
面试官:“嗯,不错,想的还挺快。”

有点脑经急转弯的意思,面试官后来说了他为什么出这道题:程序员在编代码的时候,可能会陷入思维定式,有时候我们的空间和时间有限,必须要提高程序的效率,还有就是代码的重用,6跟9倒一下就可以,代码中可重用的有很多,需要注意。

总的来说,这道题还是非常有趣的,面试官是北邮师兄,通过一步步的沟通提示,完成这道题,感觉还是不错的,哈哈~

面试算法题整理

tinyfisher 发表于 2013-10-14

最近面试跪了不少,都基本是跪在算法题上,现在把遇到的一些题目记录下来,方面以后复习

1.一个字符串只有0和1,如“110011110000”,找到这个串中的最长子串,使得子串的0和1个数相等,比如:1000010111000001,阴影的部分有4个0、4个1(出自美团)

思路:最简单的想法就是遍历所有的子串,之后判断该子串是否满足条件N^2子串,每个子串扫一遍判断0、1是否出现的次数相等,复杂度为O(N^3),稍加思考就会发现, 如果一个长度为n的子串满足条件,加么这n个元素的和加起来一定=(n/2),这样在循环的过程中,增量加就可以了,不需要每个子串从头计算,复杂度降为O(N^2);伪码:

int maxlen = 0, sum = 0, currlen = 0;
for(int i = 0; i < N; ++i)
{
    sum = 0;
    for(int j = i; j < N; ++j)
    {
        currlen = j - i + 1;
        sum += int(A[j]);
        if(currlen%2 == 0 && sum == currlen/2 && currlen > maxlen)
            maxlen = currlen;
	}
}

还有没有办法进一步降低算法的复杂度呢?

面试官说有这样一种巧妙的解法:定义一个数据B[N], B[i]表示从A[0…i]中 num_of_0 - num_of_1,0的个数与1的个数的差,那么如果A[i] ~ A[j](A[i],A[j]选一个包含)是符合条件的子串,一定有 B[i] == B[j],因为中间的部分0、1个数相等,相减等于0。 只需要扫一遍A[N]就能把B[N]构造出来了。这样问题就转换成了求距离最远的一对数,使得B[i] == B[j],因为B[i]的范围一定是[-N,N],-N到N的范围都存起来,建一个-N到N的hash表,index就是-N到N,value就是index相等的两个数的最长距离,这样每扫到B[i],如果hash表里的值还不存在,填i,若已经存在,填i和里面值得差,即为当前长度,需要更新最大长度这个值。其实代码真的非常简单,一个循环就搞定了,这就是算法和思考的乐趣:)

int A[N],B[N];
int num[2*N + 1];
int count[2] = {0,0}, maxlen = 0, currlen = 0;
memset(C, 2*N, -1);
for(int i = 0; i < N; ++i)
{
   count[ int(A[i]) ] += 1;
   B[i] = count[1] - count[0];
   if( num[ B[i] + N ] == -1)//尚不存在,B的下标是差,值是A的下标 
       num[ B[i] + N ] = i; 
   else//already exist
   {
       currlen = i - num[ B[i] + N ] + 1; //num[ B[i] + N ]是B[i]已存在的下标
       if(currlen > maxlen)
           maxlen = currlen;
   }
}

2.编程实现把一个字符串从“a1b2c4”转成“abbcccc”,不准申请新的内存,原字符串可以认为后面的空间足够大(出自美团)

思路:统计所有的数字之和何以得到最终字符串的长度,然后利用两个指针str1指向原字符串尾,str2指向新字符串尾,记录str1的数字n,和前面的字符m,str2从后向前写n个m,直到str1指向第一个字符。

问题:可能会出现覆盖问题,例如“a1b2c3”转成“abbccc”,原字符串和新字符串长度都是6,按照我上面的算法,第一步之后字符串会变成“a1bccc”,这是我无法得到b的次数2,因为2被c覆盖了。

为什么会覆盖?
原因在“a1”上,“a1”最后要变成“a”,原字符串多占了一位,导致后面的出现覆盖,所以对于所有的“X1”要进行预处理。

怎么处理
遍历一遍字符串,每遇到“1”,把后面的字符串向前移动一位,例如“a1b2c3”变成“ab2c3”,这个时候,再对“ab2c3”进行我之前的处理,第一步变成“ab2ccc”,是没有问题的。

注意:因为把1去掉之后,原字符串的格式发生了变化,遍历的时候需要注意判断一下。

3.整数分割,比如给定一整数3,其有如下情况:3=3,3=1+2,3=1+1+1,求一个数的所有分割组合(出自创新工场行云)

n=m1+m2+…+mi; (其中mi为正整数,并且1 <= mi <= n),则{m1,m2,…,mi}为n的一个划分。

如果{m1,m2,…,mi}中的最大值不超过m,即max(m1,m2,…,mi)<=m,则称它属于n的一个m划分。这里我们记n的m划分的个数为f(n,m);

例如n=4时,他有5个划分,{4},{3,1},{2,2},{2,1,1},{1,1,1,1};

该问题是求出n的所有划分个数,即f(n, n)。下面我们考虑求f(n,m)的方法;
根据n和m的关系,考虑以下几种情况:

(1) 当n=1时,不论m的值为多少(m>0),只有一种划分即{1};

(2) 当m=1时,不论n的值为多少,只有一种划分即n个1,{1,1,1,…,1};

(3) 当n=m时,根据划分中是否包含n,可以分为两种情况:

(a).划分中包含n的情况,只有一个即{n};

(b).划分中不包含n的情况,这时划分中最大的数字也一定比n小,即n的所有(n-1)划分。

因此 当n=m时,f(n,n) =1 + f(n,n-1);

(4) 当n < m时,由于划分中不可能出现负数,因此就相当于f(n,n);

(5) 当n > m时,根据划分中是否包含最大值m,可以分为两种情况:

(a).划分中包含m的情况,即{m, {x1,x2,…xi}}, 其中{x1,x2,… xi} 的和为n-m,因此这种情况下为f(n-m,m)

(b).划分中不包含m的情况,则划分中所有值都比m小,即n的(m-1)划分,个数为f(n,m-1);

因此,当n > m时 f(n, m) = f(n-m, m)+f(n,m-1);

综上:

f(n,m)=1;(n=1||m=1)  

f(n,m)=f(n,n);(n<m)  

f(n,m)=1+ f(n, m-1);(n=m)  

f(n,m)=f(n-m,m)+f(n,m-1); (n>m)  

阿里巴巴二面总结

tinyfisher 发表于 2013-09-26

二面面试官澄观,一看就很牛逼的样子,年龄也比一面的易统大一些,拿着我的简历,顺手拿了几个零食把我带到大厅,开始面试
1.你擅长什么?
我去,突出一个防不胜防,没有自我介绍,也不问项目,简历扫了一眼,扔一边。
这个问题不好答,我怕给自己挖一个坑,我就说linux用的还行,他说哪方面,我说系统使用方面,常用命令比较熟,他就问了一个问题,把一个文件夹里的.cpp文件中的BUPT换成alibaba,怎么实现?
sed -i “s/BUPT/alibaba/g” ./*.cpp

个人感觉这个问题就是坑啊,如果不是特别擅长,很容易被问住,好比让你在简历上选填你精通什么,然后问到你挂。
2.学生期间有什么可以展示的,不限技术
随意发挥

3.有用过多线程或者多进程么?在什么情况下用的?两者有什么区别
项目中有个监听线程,监听到3G网卡掉线,自动重连。
多线程好处:节约资源,并发快
多进程好处:安全,即使子进程挂了,父进程不会挂
多线程缺点:不安全,一个线程挂掉,整个进程挂了
多进程缺点:资源占用比较多,并发性不如线程

4.apache知道吗?看过源码吗?是多进程还是多线程的?http请求方法有哪些?服务器怎么知道用户登陆过?
知道,没看过,猜测是多进程的,GET,POST,(其余不常用,没怎么记,面试官貌似不满意)。
通过sessionid,用户请求时,服务器生成一个sessionid传给客户端,客户端用cookie保存sessionid,然后登陆的时候通过cookie把sessionid再发送给服务端。(大致这个意思,面试官大致满意)

5.二叉树求深度,不准递归,树是只读的
我的思路:用队列按层遍历,每一层加一,面试官说:你怎么知道这一层遍历完了?这里想了很久,说再用一个栈保存结果,栈为空的时候,这层完了,此时加一,面试官说:行是行,但浪费空间。

6.求一千亿个数的中位数,这些数无序
我的思路:hash%1000,分成小文件,求出小文件的最大和最小值,然后按照这个区间,使得这1000个小文件按照顺序排列,中位数在中间的小文件里,面试官说:不一定。发现是的,我说那我记录每个文件的个数,根据这个元素个数定位到小文件,对这个小文件排序,根据偏移量,找到中位数,面试官说对。

总结:深入再深入,必须能有一样能征服面试官的,要有亮点,这点我还得加强,本来想说项目,直接被无视。算法题注定是难的,千万别放弃,展示出想要解决他的勇气,可以问面试官要提示,互动的解决这个问题,一旦放弃,这轮面试也就挂了。

关于session和cookie

为什么会有cookie和session呢,大家都知道,http是无状态的协议(无状态是指,当浏览器发送请求给服务器的时候,服务器响应,但是同一个浏览器再发送请求给服务器的时候,他会响应,但是他不知道你就是刚才那个浏览器,简单地说,就是服务器不会去记得你,所以是无状态协议。),客户每次读取web页面时,服务器都打开新的会话,而且服务器也不会自动维护客户的上下文信息,那么要怎么才能实现网上商店中的购物车呢?

session就是一种保存上下文信息的机制,它是针对每一个用户的,变量的值保存在服务器端,通过SessionID来区分不同的客户,session是以cookie或URL重写为基础的,默认使用cookie来实现,系统会创造一个名为JSESSIONID的输出cookie,我们叫做session cookie,以区别persistent cookies,也就是我们通常所说的cookie,注意session cookie是存储于浏览器内存中的,并不是写到硬盘上的,这也就是我们刚才看到的JSESSIONID,我们通常情是看不到JSESSIONID的,但是当我们把浏览器的cookie禁止后,WEB服务器会采用URL重写的方式传递Sessionid,我们就可以在地址栏看到sessionid=KWJHUG6JJM65HS2K6之类的字符串。还有一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把sessionid传递回服务器。

Cookie是通过客户端保持状态的解决方案。从定义上来说,Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。让我们说得更具体一些:当用户使用浏览器访问一个支持Cookie的网站的时候,用户会提供包括用户名在内的个人信息并且提交至服务器;接着,服务器在向客户端回传相应的超文本的同时也会发回这些个人信息,当然这些信息并不是存放在HTTP响应体(Response Body)中的,而是存放于HTTP响应头(Response Header);当客户端浏览器接收到来自服务器的响应之后,浏览器会将这些信息存放在一个统一的位置,对于Windows操作系统而言,我们可以从:[系统盘]:\Documents and Settings[用户名]\Cookies目录中找到存储的Cookie;自此,客户端再向服务器发送请求的时候,都会把相应的Cookie再次发回至服务器。而这次,Cookie信息则存放在HTTP请求头(Request Header)了。有了Cookie这样的技术实现,服务器在接收到来自客户端浏览器的请求之后,就能够通过分析存放于请求头的Cookie得到客户端特有的信息,从而动态生成与该客户端相对应的内容。通常,我们可以从很多网站的登录界面中看到“请记住我”这样的选项,如果你勾选了它之后再登录,那么在下一次访问该网站的时候就不需要进行重复而繁琐的登录动作了,而这个功能就是通过Cookie实现的。

**关于二叉树求深度 **

思路:先层次遍历一遍找出最后一个节点,然后目的变为求这个节点的深度。然后我们用循环一层一层找到它的上一层,找到一次,深度加1,最终可以得到二叉树的深度。不需要栈了。
例如下面的树:
hello
首先按层遍历获得最后一个元素J,然后从根再次按层遍历找到他的父节点E,此时深度+1,再从头按层遍历找到E的父节点B,此时深度加1,直到根节点为止

**关于1000亿个数的中位数 **

我的那种hash%1000的分割法有点问题,因为整数是有范围的,可按照整数范围分割文件,这样就不需要对每个文件排序,然后根据index偏移量找到小文件,只需对这个文件进行排序,取偏移量的数即可

  

创新工场一面总结

tinyfisher 发表于 2013-09-24

跟hr约好了9点去面试,早上7点半起来,觉得不出意外能赶到,结果堵车了,急得要死,还好邮件里有hr的联系方式,提前打个电话说明了情况,对方表示没有关系,这下放心了。到了创新工场是大概9:10,迟到了10分钟左右,然后被hr mm带到一个叫手舞的玻璃房里,里面坐着面试官gg,谈吐穿着都非常儒雅,气氛不算很紧张。
首先自我介绍,然后挑一个项目介绍,扯了扯,面试官开始直奔主题,写代码,早闻创新工场的面试就是这个样子,开始进入正题:
1.快排,时间复杂度,怎么避免最坏情况的出现

砍瓜切菜,至于优化在《算法导论》中看到过,partition的时候不是固定取末尾一个数,而是随机取,甚至可以随机取3个数,取这3个数的中位数作为key。面试官比较满意。

2.一个整型无序数组,要求从中取三个数,要求:这三个数值递增,三个数在原数组中的下标值也递增,说思路
这题时间不够,没想出来。我的思路是:
1.既然无序,那我排序试试看,结果发现如果排序势必会打乱下标的顺序,跟没排序其实没区别
2.那么既然下标已经有序了,我就把所有符合下标递增的三元组找出来,看他们的值是否递增,面试官说:这个肯定可以,有没有优化的办法?
卡住了,实在想不出来了,时间也到了,后来我就问面试官,这题怎么做,他告诉了我答案:
举个例子:2,1,4,3,5
面试官说我们只需要找到总共有多少个三元组,而不需要把他们找出来,充分利用数组下标已递增的特点,固定一个数,比如说4,那么以4为中值的三元组只需要从左边找到比4小的和右边找到比4大的即可。 哎,充分感觉智商不够用。不知道还能不能进二面

总结:基础要牢,排序神马的基本是送分题,但也要深入研究下各个排序的特点,时间复杂度,最差情况,优化等等;至于算法题,还是搞题海战术吧,我这种智商的实在想不出来
今天收到二面通知,开心!