摘要: 《编程之美》读书笔记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 阅读(1613) 评论(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 阅读(986) 评论(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 阅读(685) 评论(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 阅读(1706) 评论(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 阅读(693) 评论(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 阅读(818) 评论(0) 推荐(0) 编辑
摘要: 《编程之美》读书笔记22: 1.16 24点游戏 给定4个数,能否只通过加减乘除计算得到24?由于只有4个数,弄个多重循环,就可以。如果要推广到n个数,有两种思路: ① 采用前缀/后缀表达式。相当于将n个数用n-1个括号括起来,其数目就是一个catlan数。最多可得到 f(n) = (1/n * (2*n - 2)! / (n-1)! / (n-1)!) * n! * 4^(n-1) = 4^(n-1) * (2*n-2)! / (n-1)! 种表达式,当n=4时,共可得到 7680种。 ② 从n个数中任意抽取2个,进行计算最多有6种结果,将计算结果放回去,再从剩下的n-1个任取2个,进行计. 阅读全文
posted @ 2011-03-22 23:19 flyinghearts 阅读(761) 评论(0) 推荐(0) 编辑
摘要: 《编程之美》读书笔记06: 1.13 NIM(3)两堆石头的游戏 问题: 假设有两堆石子,两人轮流取石子,每次可以从一堆取任意个石子,或者从两堆取相等数量的任意个石子,但不能不取。 若先把石子取光的一方为胜方,先取者有什么必胜策略? 若先把石子取光的一方为输方,先取者的策略要进行怎样调整? 记得初中时在学校门口的书店,买到一本《智力游戏中的数学方法》,当时如获至宝。书中提到一个“皇后登山”游戏,就是在空的围棋棋盘上放一个棋子,该棋子每次只能向上或向右或沿对角线向右上方向移动(和国际象棋中的皇后移动相似),可以移动任意格,但不能不移动,两人轮流移动棋子,先将棋子移动到右上角者赢,问先移棋者的必胜 阅读全文
posted @ 2011-03-22 23:19 flyinghearts 阅读(1995) 评论(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 阅读(623) 评论(0) 推荐(0) 编辑
摘要: 《编程之美》读书笔记04: 1.8 小飞的电梯调度算法 假设电梯有n层,上楼要消耗能量k1,下楼要消耗能量k2,用a[i]表示要在第i层下的人数,Si为到i层时已经下(包括i层)的总人数,则总人数S=Sn。若用F(i)表示电梯在i层停时要消耗的总能量,则电梯在i+1层停时,有Si人要多下一层,(S-Si)人少上一层。则: F(i+1) = F(i) + k2*Si - k1*(S-Si) = F(i) + (k2+k1)*Si – k1*S = F(i) + G(i) (定义G(i) = (k2+k1)*Si – k1*S) 由于Si是递增的,G(i)也是递增的,当G(i) <= 0,F 阅读全文
posted @ 2011-03-22 23:16 flyinghearts 阅读(620) 评论(0) 推荐(0) 编辑