《编程之美》读书笔记(一)

2.1求二进制数中1的个数

http://blog.csdn.net/bvbook/archive/2008/04/15/2292823.aspx

一个8byte的整数,求其二进制表示中1的个数。

四个算法:

1)循环除2判断余数是否为1

2)和0x01异与(&),判断最后一位是否为1,然后右移一位,循环往复。

算法1和2的时间复杂度都是o(logN)

3)这个算法比较狠,一个一个抹去最后一个1,这样时间复杂度就只和1的个数有关。

主要是n & (n-1) ,这个技巧很重要,能计算出末尾最后一个1的位置。

while(v)

{

    n = n & (n-1)

    num++;

}

return num;

4)8byte,它的值只有256种可能,所以更狠的做法是做一个int[256]的数组,把这些值事先都对号入座,然后arr[i]随便取哪个,时间复杂度o(1)。

 

话说,32位的算法,不是科班出身的我,并没有看懂。

另一道扩展题目,是先对A和B做异或,然后再计算结果值中1的个数。

C#程序员们,牢记啊:

|运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0 简单地说,有1位为1就是1

不要和XOR混,后者相同时为0,不同为1。

&与运算规则:只有都为1,才是1;否则,一概返回0。

 

2.2 不要被阶乘吓倒

http://www.kuqin.com/algorithm/20080505/7874.html

第一道题,N!末尾有几个0?

其实就是在算有多少个5。[N/5]+[N/25]+[N/125]+……,其中[N/5]表示从1到N中,有多少可以被5整除的数?

这是一种“扒皮抽筋”的思想:

ret=0

while(N)

{

    ret += N / 5;

    N /= 5;

}

 

第2道题,N!的二进制表示中,从末尾向前,第一个1的位置?

其实就是计算从1到N有多少个2的质因数——有X个2,那么N!的二进制末尾就有X个0,那么第一个1的位置就是N+1。

继续使用“扒皮抽筋”的思想:[N/2]+[N/4]+[N/8]+……

 

扩展题目:判断N是否为2的方幂?

N & (N-1) == 0,当然,还要同时保证N〉0;

 

2.3 寻找发帖水王

http://blog.csdn.net/zhong317/archive/2009/07/15/4350690.aspx

每次删除2个不同的ID,这个算法很有意思,比如说a、a、b、c、a、b、a、a,那么nTimes先升到2,然后,因为b、c的出现,又降到0,于是重新制定candidate。最后nTimes总会大于0,candidate不再变化。

扩展题目太复杂了,我建议范围缩小为:有2个发帖很多的ID,都已超过了1/3,如何找出?思路仍然是,每遇到3个不一样的就杀一次,从而保证,仍然有2个ID都超过1/3。

于是我们要建立数组:nTimes[0]和nTimes[1],要建立相对应的值candidate[0]和candidate[1],说一下过程:

比如说前三个数是a、a、b,那么candidate[0]=a,candidate[1]=b,nTimes[0]=2,nTimes[1]=1,下面问题就来了,

如果第4个数是a或b,就相应增加nTimes[0]和nTimes[1]的数量值。

如果第4个数是c,分别和candidate[0]和candidate[1]比较都不一样,于是我们认为找到了3个不一样的数,杀掉,杀的过程是nTimes[0]和nTimes[1]都减去1,如果其中哪个变成了0,就清除相应的candidate,这里nTimes[1]减去1后变成了0,所以candidate[1]要清空,等待下一个值进来。

这样循环下去,最后candidate[0]和candidate[1]就是我们要找的两个水王。

 

扩展题目的要求是找3个发帖超过1/4的ID,可以按照我刚才的思路玩下去。

 

由此题可见分治、贪心、递推思想的妙处。

 

2.4 “1”的数目

计算f(N)中1的个数,这道题目告诉我们,枚举+归纳法的重要性。大体枚举到4位数,就能归纳出之后的所有情况了。第N位上出现1的次数,由3种因素决定:N位上的数字、N位以上的数字、N位以下的数字。

于是对第N位上的数字,分3种情况讨论:

1)为0:更高位数字X10的N次方

2)为1:不仅由高位决定:更高位数字X10的N次方;还要受低位影响:当前N位及以下的值+1

3)大于1:(更高位数字+1)X10的N次方

 

计算f(N)=N

我对书中的解法不同意。算出10的11次方这个上界,是可以接受的,但是接下来用递减的方式找出N,是很费劲的。我建议使用二分法,o(longN)的效率要比o(N)快很多。

 

扩展题目分析:本题目的二进制方式

 

2.5 寻找最大的K个数

唉,又是排序,恶补一通排序算法的知识先。唉,不是科班出身的人就是吃亏啊,如果有来生,但是,我连程序员这一行都不一定做。

 

2.6 精确表达浮点数

 

2.7 最大公约数问题

辗转相除法不好,辗转相减法也不好。

遇到0就右移,都是1就相减,直到有一个为0。

 

2.8 找符合条件的整数

 

2.9 Fib数列

其实我最喜欢用空间换时间,不管是F(n)=F(n-1)+F(n-2),还是F(n)=F(n-1)+F(n-2)+F(n-3)。

当然,用单位矩阵的N次幂,也是一个好办法。

 

2.10

找出数组中的最大最小数:貌似最快只能是1.5N,谁让最大和最小距离那么悬殊。

找出N个数组中的最二大数:两个两个一组排序,大的在前(奇数位),只要奇数位的,排成一个新的数组(概念上)——继续反复,直到剩下4-5个。

如何从N个数中选出最大(小)的n个数?http://blog.csdn.net/fisher_jiang/archive/2008/05/23/2473698.aspx

败者树(loser tree)

 

2.11 寻找最近点对

http://topic.csdn.net/u/20091024/12/989417AA-60E9-45D1-A96F-A623695FC6D7.html

 

2.20 程序理解和时间分析

http://blog.csdn.net/jcwKyl/archive/2009/02/14/3889802.aspx

注:这个博主的其他算法文章都很不错

 

2.21 只考加法的面试题

http://blog.csdn.net/haykey/archive/2008/10/29/3175373.aspx

 

3.1 字符串移位包含的问题

如果s2可以由s1循环移位得到,那么s2一定在s1s1上

貌似有一个算法,叫做“最小表示法”

 

3.2 电话号码对应英语单词

 

3.3 从无头单链表中删除节点

狸猫换太子:

curr.Data = curr.Next.Data;

curr.Next = curr.Next.Next;

 

3.6

“链表相交”扩展问题 http://hi.baidu.com/azuryy/blog/item/18e85b02ec34a4094bfb51de.html

 

 

 

单链表反转问题:

posted @ 2009-12-13 01:25  包建强  Views(2174)  Comments(2Edit  收藏  举报