编程之美读书笔记_杂项

编程之美 读书笔记

 

1.1 CPU占用率听你指挥

P7页的那个汇编代码(16位)有点过时。另外,对32位汇编,空循环,常用到的寄存器是eaxecx

 

 

1.5 快速找出机器故障

看了好几遍,还是看不懂题目,尽管猜到了要考什么。问题一问的有点莫名其妙,没说明为什么有个ID会只出现一次,只出现一次的ID是否只有一个;问题二的两个小问题本意都是要求找丢失的ID,但却把这个要求给省略了,按上下文语义,问题二的要求就会是跟前一个问题一样,都是找只出现一次的ID

已知N个数中缺一个数,最高效的是利用 xor 的特性。对书中的解法三,当xor的结果为0,说明丢了一对数,利用附加的总和,再扫一遍,就可以算出丢失的数。

个人认为,解法四不可取。用大数加法,本就影响性能,再用上大数乘法(光保存结果就要占用大量空间),效率更差,而真正麻烦的是,最后解方程得到的结果存在精度问题,不能保证一定等于丢失的数,因而只能做为估计值,还得用其它算法找出丢失的数。

 

 

1.6 饮料供货

看了解法后,越来越糊涂了。题目好像没有限制必须要买V升(当然,如果有1升的饮料,肯定买V升时满意度最大,不过题目也没说明肯定有1升的饮料,解法三的描述有问题)。每种饮料都有个购买量上限,但书中的解法根本就没对每种饮料的购买量有限制。另外,P43页,最后一段,用两个满意度最高的一升凑成容量为两升的饮料岂不是更好。

如果对每种饮料的购买量没有限制,可以才用下面的贪心算法:对相同体积的,只保留满意度最高的,再将满意度除以体积,以这个比值进行降序排列,以这个次序购买(尽量买比值最大的,剩余的,再取能买的饮料中取比值最大的)。

 

 

2.1  求二进制中1的个数

Hacker’s Delight(中文译名:高效程序的奥秘)一书,第五章(5-1 Counting 1-Bits) 详细阐述了各种方法。

另外,由于整数在机器中是以补码形式储存。因而,接口参数类型可以且最好用unsigned 而不是int,这样不仅生成的汇编指令更少(如,除法时,要有额外的指令判断数是否是负数),而且不容易出错(如果没有对负数进行处理,循环移位时,极可能会陷入死循环。)。

 

 

2.2 不要被阶乘吓倒

    P123 代码2-7,当N为负数时,程序死进入死循环,另外写成 while (N >= 1) 不仅能少一次循环,生成的汇编代码,能在移位后,直接对标志位判断是否进入循环,而少一次与0比较。

 

 

2.4  1的数目

假设n=ak*10k+ ak-1*10k-1+…+ a1*101+ a0*100 ( ak-1, ak-2 … a0>=0; ak>=1)

     非最高位中1出现的个数:

当最高位从0ak-1,其它k位数出现的1个数:先从k位中取一位为1,剩余的k-1位组成共可组成k*10k-1个数,所以,1的个数总共为:ak*k*10k-1

最高位为ak时,去除最高位后,剩余的数为n-ak*10k,其中1出现的个数为f(n-ak*10k)

② 最高位出现1的个数:

如果ak>11出现的个数肯定大于ak=11出现的个数,

ak=1时 最高位1出现的个数为:n-ak*10k+1

(若ak>1  1出现的个数为 10k

所以 f(n)>= ak*k*10k-1 + n-ak*10k+1 + f(n-ak*10k) > ak*(k/10 -1)* 10k-1 + n

只要 k>=10, 就有 f(n)>n

 

因此上限为 1010 – 1,比书中给出的上限降了一个数量级。这道好像也是google面试题,以前在ChinaUnix论坛看到有个网友给出了很不错的解法,能在极短的时间内找到所有的 f(n)=n

 

 

2.11 只考加法的面度题

假设数S所表示的连续数,第一个数为a,长度为n,则 S=n*a+n*(n-1)/2

因而 n*(n-1+2*a)=2*S    a=(2*S/n-n+1)/2 n(n-1+2*a)奇偶性不同,如果S不含有大于2的质因子,则S一定不能表示成连续数。2<= n < sqrt(2*S),可以找出所有质因子(遇到一个质因子,让S除以这个质因子,当质因子很多,最大的质因子不是很大时,能在很短时间找到所有质因子),再判断质因子间的各种组合。或者,直接让n2遍历到sqrt(2*S) 输出符合条件的。

 

 

3.1 计算字符串移位包含问题

从第二个字符串B中,找出第一个字符串A第一个字符A0的位置i,从该位置起判断字符串A1…An-1Bi+1…(如果字符串B到达串末,就跳到串首)是否相等,不相等,就在字符串B中找出A0的下一个位置,如果到达B的末尾,则不是字符串包含,否则重复上述字符串是否相等判断。

 

 

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

本质上还是用上了“交换”思想。两个对像之间最好用赋值,而不是取各自的成员再赋值。该方法最好不要用在接口函数当中,因为要删除的是A,而实际上删除的是A的下一个元素B,会使指向B的所用指针失效。

 

 

3.6 编程判断两个链表是否相交

    链表题常用到双指针。如果两个链表没有环,如果相交,那么它们的终点一定是一样的。因此通过判断终点是否一样,来确定是否相交,如果要找出第一个相交的点,只要第一次起跑时计数,第二次起跑时,把起跑线调整下,然后判断跑的过程中是否会相遇。如果链表可能有环,就必须在某个链表上设两个指针,一个每次比另一个多跑一步,如果在到达终点前,跑得慢的和跑得快的相遇了,说明存在环,两个指针停下休息,从另一个链表开头,另一个指针出发,若能与前面的相遇,则说明链表相交,否则不相交。

 

    原文作者:flyinghearts
    原文地址: https://blog.csdn.net/flyinghearts/article/details/5605998
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞