随笔分类 -  编程之美

编程之美 读书笔记 算法
摘要:《编程之美》读书笔记25: 2.21只考加法的面试题我们知道:1+2 = 3;4+5 = 9;2+3+4 = 9。等式的左边都是两个或两个以上连续的自然数相加,是不是所有的整数都可以写成这样的形式呢?问题1: 对于一个64位正整数,输出它所有可能的连续自然数(两个以上)之和的算式。问题2: 大家在测试上面程序的过程中,肯定会注意到有一些数字不能表达为一系列连续的自然数之和,例如32好像就找不到。那么,这样的数字有什么规律呢?能否证明你的结论?问题3: 在64位正整数范围内,子序列数目最多的数是哪一个?假设自然数n可以拆分成:m, m+1, …, m+k-1 (m >= 1, k > 阅读全文
posted @ 2011-03-27 23:08 flyinghearts 阅读(3377) 评论(1) 推荐(0) 编辑
摘要:《编程之美》读书笔记24: 3.5 最短摘要的生成 当初看这道题时,看了好了几遍都没看懂。后来总算弄明白:给出的字符串是用其它程序分好词的,关键字符串也是用其它程序分好词的,而不是按用户直接输入的字符串。比如书上给的例子:“微软亚洲研究院使命”,不是按空格分成两个关键词,“微软亚洲研究院”和“使命”,而是按其它程序分成:“微软”、“亚洲”、“研究院”和“使命”四个关键词。 “最短摘要”应该是指:包含所有关键字(关键字不要求按用户输入的顺序排列)的长度最短的摘要。书上的解法,把“最短摘要”理解成包含所有关键字且词个数最少的摘要。 弄清了问题,解决起来就很简单: 1 反复读入字符串,直到碰到关键. 阅读全文
posted @ 2011-03-24 23:27 flyinghearts 阅读(3755) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记15: 4.5 磁带文件存放优化 对一个已经是最优解的排列,记第i个文件的长度为Bi,被访问概率为Ai。如果交换第i个和第i+1个文件,则平均长度一定不会变小,交换后,访问原第i个文件时,要多访问一个原第i+1文件,长度增加了Ai*Bi+1,而访问原第i+1个文件时,要少访问一个原第i个文件,长度减少了Ai+1*Bi,而访问这两个文件之前和之后的文件,长度没有改变,故有: Ai*Bi+1 - Ai+1*Bi >=0 即Ai/Bi >= Ai+1/Bi+1, 由于i可以任意取,因而A0/B0 >= A1/B1 >= A2/B2 >= … > 阅读全文
posted @ 2011-03-22 23:31 flyinghearts 阅读(548) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记13: 4.1 金刚坐飞机问题 问题: 现在有一班飞机将要起飞,乘客们正准备按机票号码(1, 2, 3, …N)依次排队登机。突然来了一只大猩猩(对,他叫金刚)。他也有飞机票,但是他插队第一个登上了飞机,然后随意地选了一个座位坐下了1。根据社会的和谐程度,其他的乘客有两种反应: 1. 乘客们都义愤填膺,“既然金刚同志不遵守规定,为什么我要遵守?”他们也随意地找位置坐下,并且坚决不让座给其他乘客。 2. 乘客们虽然感到愤怒,但还是以“和谐”为重,如果自己的位置没有被占领,就赶紧坐下,如果自己的位置已经被别人(或者金刚同志)占了,就随机地选择另一个位置坐下,并开始闭目养神,不再 阅读全文
posted @ 2011-03-22 23:30 flyinghearts 阅读(811) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记14: 4.4 是否在三角形内 对几何题目,常用到矢量。若P点在三角形内部,则矢量PA沿时钟某个方向三次旋转分别经过PB、PC再回到PA,每次旋转角度都不会超过180度。即PA×PB、PB×PC和PC×PA这三个矢量积应该都为正,或都为负。如果P在三角形边上,则这三个矢量积应该一个为0,其它两个同正或同负。若在三角形某个顶点,则三个矢量积,必有两个为0,一个不为0。若A B C三点共线,P在这直线上,则所有矢量积均为0,若P不在这直线上,则为两正一负或两负一正。 structPoint{doublex;doubley;};staticintdi 阅读全文
posted @ 2011-03-22 23:30 flyinghearts 阅读(630) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记16: 3.10 分层遍历二叉树 看到Milo写的这篇文章,又翻了下书,发现书的代码(P253)有个瑕疵,每个节点值后面都会显示一个空格,如果将间隔字符改为“-”,输出的每行最后都有一个“-”,不能达到要求。不过,只要将 cout << vec[cur] -> data << " "; 这行改为: if (cur==last-1) cout << vec[cur] -> data << "\n"; else cout << vec[cur] -> data 阅读全文
posted @ 2011-03-22 23:28 flyinghearts 阅读(504) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记19: 3.9 重建二叉树 对根节点a以及先序遍历次序P和中序遍历次序I,查找a在I中的位置,将I分为两部分,左边部分的元素都在a的左子树上,右边的元素都在a的右子树上,因而可以确定a的左子树节点数和a的右子树节点数,再结合P,可以确定a的左孩子和右孩子,以及各个孩子的先序和中序遍历次序。 由于已经知道节点数,可以事先分配好内存,可以按先序遍历次序连续存放节点。 rebuild_tree_1structNode{Node*left;Node*right;chardata;};voidrebuild(charpreorder[],charinorder[],Noderesu. 阅读全文
posted @ 2011-03-22 23:28 flyinghearts 阅读(563) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记12: 3.8 求二叉树中节点的最大距离 问题: 如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义"距离"为两节点之间边的个数。写一个程序求一棵二叉树中相距最远的两个节点之间的距离。 实际上就是求树的直径。若采用“动态规划方法”思想,会将该问题分解成“具有最大距离两点间的路径是否经过根节点”两个子问题,然后再对这两个子问题求解判断。实际上,不必这么麻烦。距离最远的两点必然在以某个节点A为根的子树上,它们间的路径必然经过该子树的根节点A。因而,以任意一个节点B为根的子树,计算出经过该子树根节点B的最大距离,则所有最大距离的最大值就是 阅读全文
posted @ 2011-03-22 23:27 flyinghearts 阅读(1997) 评论(1) 推荐(0) 编辑
摘要:《编程之美》读书笔记11: 3.3 计算字符串的相似度 很经典的可使用动态规划方法解决的题目,和计算两字符串的最长公共子序列相似。 设Ai为字符串A(a1a2a3 … am)的前i个字符(即为a1,a2,a3 … ai) 设Bj为字符串B(b1b2b3 … bn)的前j个字符(即为b1,b2,b3 … bj) 设 L(i , j)为使两个字符串和Ai和Bj相等的最小操作次数。 当ai等于bj时 显然L(i, j)=L(i-1, j-1) 当ai不等于bj时 若将它们修改为相等,则对两个字符串至少还要操作L(i-1, j-1)次 若删除ai或在Bj后添加ai,则对两个字符串至少还要操作L(i-. 阅读全文
posted @ 2011-03-22 23:26 flyinghearts 阅读(1056) 评论(2) 推荐(0) 编辑
摘要:《编程之美》读书笔记18: 3.7 队列中取最大数操作问题 若不使用C++新标准的右值引用,DeQueue的实现是低效的,因为要返回的元素只能通过赋值操作,而不能通过引用。(书上的实现代码,竟然少了对EnQueue的实现!) 思路:用一个辅助队列来记录最大元素(为节省空间,只记录其地址),当有一个元素入队,就将辅助队列尾端不大于该元素的全部出队后(注意相等的也要出队),再将该元素压入辅助队列,这样就保证,辅助队列从头到尾的元素是递减的,辅助队列头元素是当前队列的最大值。当有一个元素出队时,就与辅助队列的头部第一个元素所指的元素比较,如果是同一个元素(注意不是相等),辅助队列头部就执行出队操作. 阅读全文
posted @ 2011-03-22 23:26 flyinghearts 阅读(701) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记09: 2.17 数组循环移位 对长度为n的数组(ab)左移k位,最直接的方法,就是用stl的rotate函数(stl针对三种不同的迭代器,提供了三个版本的rotate)。但在某些情况下,用stl的rotate效率极差。 对数组循环,可以采用的方法有: ① 动态分配一个同样长度的数组,将数据复制到该数组并改变次序,再复制回原数组。 ② 利用ba=(br)r(ar)r=(arbr)r,通过三次反转字符串。 ③ 分组交换(尽可能使数组的前面连续几个数为所要结果): 若a长度大于b,将ab分成a0a1b,交换a0和b,得ba1a0,只需再交换a1 和a0。 若a长度小于b,将a. 阅读全文
posted @ 2011-03-22 23:25 flyinghearts 阅读(828) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记10: 2.18 数组分割 如果直接遍历,则至少要遍历 Cr(n-1,2*n)次(Cr(m,n)为从n个数中取m个数的组合数),为了减少遍历次数,可以先对数组排序。再将所有可能的组合大致分成几组,每个组的数组和也是升序的,通过不断的分组、查找,确定上下边界条件,最终找到所求子数组。 如果数组各个元素均不相同,可以采用下面的算法: 先将数组{ai}排序,并计算出各元素的总和的一半S(=Sum/2.0),(对数组的划分时,可以先选中a0,再取n-1个数)。 假设Ti=sum(a0+ai+an+2+an+3…+a2n-1) (0<i<=n+1) 则数组{Ti}也是升序 阅读全文
posted @ 2011-03-22 23:25 flyinghearts 阅读(1614) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记17: 2.16 求数组中最长递增子序列 思路:每处理一个数,都可以将这个数插入到已经找到的某个递增子序列(假设包含无限个长度为0的空序列)后,使其长度增加1,处理完毕后,这些长度最大值即为所求。 具有相同长度i+1的递增子序列,若这些序列的最后一个数最小值为min_v[i],其所在的序列为A,则若某个数能插入到序列A后面,必然能插入到其它相同长度的递增子序列后面,而能否插入到序列A后面,仅由min_v[i]值决定,因而只要维护min_v[i]值就够了。 当前数必然可以插入到某个长度为j(0<=j<=len, len为已找到的最长递增子序列长度)的序列后,使得旧 阅读全文
posted @ 2011-03-22 23:24 flyinghearts 阅读(987) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记08:2.9 Fibonacci序列 计算Fibonacci序列最直接的方法就是利用递推公式 F(n+2)=F(n+1)+F(n)。而用通项公式来求解是错误的,用浮点数表示无理数本来就有误差,经过n次方后,当n相当大时,误差能足够大到影响浮点数转为整数时的精度,得到的结果根本不准。 用矩阵来计算,虽然时间复杂度降到O(log n),但要用到矩阵类,相当麻烦。观察: F(n+2)=F(n)+F(n-1)=2*F(n-1)+F(n-2)=3*F(n-2)+2*F(n-4) 用归纳法很容易证明 F(n) = F(k)*F(n+1-k) + F(k-1)*F(n-k),利用该递推公 阅读全文
posted @ 2011-03-22 23:23 flyinghearts 阅读(686) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记07: 2.5 寻找最大的K个数 问题: 从n个数中找出最大的k个数。 两种思路: 1 保存目前找到的最大k个数,每访问一个数,就与这k个数中的最小值比较,决定是否更新这k个数。储存k个数的数据结构可采用:败者树、二叉查找树、最小堆。 C++ STL提供了multiset和priority_queue容器,另外还提供了make_heap,push_heap,pop_heap方便手动构建堆结构。(测试发现,手工建堆的效率最高,当n和k增大到一定值时,采用红黑树的multiset的效率极差。手动建堆的效率相比priority_queue有略微提高。) 2 修改排序方法,去除不. 阅读全文
posted @ 2011-03-22 23:23 flyinghearts 阅读(1707) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记21: 2.4 1的数目 问题: 给定一个十进制正整数N,写下从1开始,到N的所有整数, 然后数一下其中出现的所有“1”的个数。 例如: N=2,写下 1,2。这样只出现了 1 个“1”。 N=12,我们会写下 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12。这样 1 的个数是 5。 1. 写一个函数f(N),返回1到N之间出现的“1”的个数,比如f(12)=5。 2. 在32位整数范围内,满足条件“f(N)= N”的最大的N是多少? 曾在ChinaUnix论坛上看到该题,记得是google的面试题,有个网友给出了不错的解法,但他给出的证明倒是. 阅读全文
posted @ 2011-03-22 23:22 flyinghearts 阅读(695) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记22: 1.16 24点游戏(补充) 给定n个数,能否只通过加减乘除计算得到24? 书上给出的最后一种解法,通过使用集合记录中间结果来减少冗余计算。本以为,程序会占用大量的内存,用一个极端的例子(13, 773, 28, 98, 731, 1357,97357246这7个数)测试了一下实现的程序,发现程序竟然占用了1G以上的内存(无论集合的实现采用STL中的set还是unordered_set),但后来,取7个均在1到13之间的数,再重新测试了下发现,程序所占用的内存比想像的小的多,也就几兆。 对数值都在1到13之间的n个数的所有组合进行判断。在n等于4时,实现的程序约过. 阅读全文
posted @ 2011-03-22 23:21 flyinghearts 阅读(819) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记06: 1.13 NIM(3)两堆石头的游戏 问题: 假设有两堆石子,两人轮流取石子,每次可以从一堆取任意个石子,或者从两堆取相等数量的任意个石子,但不能不取。 若先把石子取光的一方为胜方,先取者有什么必胜策略? 若先把石子取光的一方为输方,先取者的策略要进行怎样调整? 记得初中时在学校门口的书店,买到一本《智力游戏中的数学方法》,当时如获至宝。书中提到一个“皇后登山”游戏,就是在空的围棋棋盘上放一个棋子,该棋子每次只能向上或向右或沿对角线向右上方向移动(和国际象棋中的皇后移动相似),可以移动任意格,但不能不移动,两人轮流移动棋子,先将棋子移动到右上角者赢,问先移棋者的必胜 阅读全文
posted @ 2011-03-22 23:19 flyinghearts 阅读(1998) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记05: 1.9 高效率的安排见面会 扩展问题一: 实际上就是求区间的最大重叠次数。书上P57的算法,比较巧妙,但要注意的是:排序时要用到双关键字比较,当两个值相等时,属于时间段开始的一定要排在属于时间段结束的后面,只有这样才能保证结果的正确性。(假设[3, 4)和[4, 5)能在同一个地方举行。书上区间段都是用闭区间,本文采用前闭后开。) 考虑到面试安排的时间一般安排在某个整点、半点或者某刻,可以采用计数的方法,如果都安排在整点,每处理一个区间[a, b),就对[a, b)间的所有整数计数一次。最后从计数结果中找出最大值即可。时间复杂度为O(n)(准确的讲,应该是O(k*. 阅读全文
posted @ 2011-03-22 23:18 flyinghearts 阅读(624) 评论(0) 推荐(0) 编辑
摘要:《编程之美》读书笔记03: 1.4 买书问题 问题: 在节假日的时候,书店一般都会做促销活动。由于《哈利波特》系列相当畅销,店长决定通过促销活动来回馈读者。在销售的《哈利波特》平装本系列中,一共有五卷,用编号0, 1, 2, 3, 4来表示。假设每一卷单独销售均需要8欧元。如果读者一次购买不同的两卷,就可以扣除5%的费用,三卷则更多。假设具体折扣的情况如下: 本数 折扣 2 5% 3 10% 4 20% 5 25% 在一份订单中,根据购买的卷数以及本书,就会出现可以应用不同折扣规则的情况。但是,一本书只会应用一个折扣规则。比如,读者一共买了两本卷一,一本卷二。那么,可以享受到5%的折扣。另外. 阅读全文
posted @ 2011-03-22 23:16 flyinghearts 阅读(1558) 评论(0) 推荐(0) 编辑