读书笔记

第一章 游戏之乐

1.1CPU使用率问题

Sleep();GetTickCount(); 这两个函数的使用。

1.2中国象棋将帅问题 

1 判断在不在同一列,可以对行取余数。 按照层序编号。

2 快慢指针的思想。好好理解。

3 排除的思想使用。遍历所有情况,排除不满足的情况。

1.3烙饼排序,前缀排序

穷举法,暴力搜索。主要学习一下剪枝的一些技术。

1.4买书问题

贪心算法的优化。

1.5快速找出故障机器

异或思想的使用。以及如果有两个待求值,怎么进行划分。

列方程的思想。

1.6饮料问题

如果证明贪心的正确性。以及递归搜索的使用,使用动态规划降低复杂度。

1.7光影切割问题

问题本身不复杂,是个几何问题,很容易转化到求交点的个数。

有意思的是,直接求所有交点,时间复杂度比较高(O(N^2)*Max(Intersection))。

如果不提前预处理这么多数据,只求一段区间的交点数目,可以转化成一个数组的逆序数问题。

这样就有意思了,一个数组的逆序数目怎么求呢,最直接的是O(N^2)算法,但是如果采用分治的

思想,这儿也就是Merge排序的一个应用场景,就可以将复杂度降低到N*LogN,呵呵,挺有意思。

1.8电梯调度算法

首先提出一个最直观的解决方法。然后分析问题的实质,可以发现实质是一个利益最大化问题,

策略总是想着利益最大的集团移动,直到另一方有足够的牵制力为止。这不就是社会财富分配问题

吗?

1.9见面会问题

有点类似贪心算法,每个见面会时间都尽量提前,除非出现了矛盾,不得已才后延一个单位。(这个经过测试,发现算法是错误的)

扩展到图的最少着色问题,每次都选择周围没有用过的一个最小颜色,那么最后得到的每个节点号的

最大值,就是最小着色需要的颜色数目?

求一段区间的某个时间点的最大重叠数目,我之前用的是投影方法,后来发现问题的实质是开房间和退房间的

一个过程,设置一个变量记录过程最大值就可以得到结果。

1.10双线程高效率下载

这个主要是考察多线程怎么协调工作,如果有一些变量时敏感的,那么在改变它之前一定要保证已经完成该做的工作了。

1.11拈 游戏的玩法

这个我貌似不太擅长,游戏的关键是找出规律性,然后进行跟随。

第一个游戏,可以构造线性的左右对称性,然后进行跟随。

第二个游戏,可以构造|k+1|的模,然后进行跟随。

第三个游戏,如果是偶数可以构造左右对称性,如果是奇数,那么一定会输。

因为异或结果的规律性,当总数为奇数的时候,异或和一定不为零,

这是个安全状态,只要改变一个数,就可以让异或和为零。当异或和为零的时候,改变一个数一定让异或和非零。这样我们就可以进行异或和的跟随,每次构造成异或零,最后一步一定是自己取完石头。

第四个游戏,两堆石头的游戏,一开始难以找到规律性,但是如果具体分析一下实例,会发现一些安全状态和非安全状态,而且每个安全状态一定可以装换成非安全状态,非安全状态无论怎么取都会变成一个安全状态,这就找到了跟随规律性。 而安全状态跟非安全状态的查找,启发于观察数目小的时候状态转移规律,

类似于求所有素数的筛子算法,不过这儿是二维的。

1.14 连连看游戏

图的广度优先搜索思想应用。值的思考的是怎么设计数据结构,为了实现目标,每个节点应该存储哪一些属性?比如转弯数,祖先节点等。

1.15构造数独

首先提出一个最直接的解决办法,面向过程的算法,思想很简单,考察每个点的可能取值,如果有则取一个并移动到下一个点,如果没有则回溯到上一个点重新设定值。这个过程需要合理的设置一下数据结构,设置每个节点应该具有的属性。

另外一个方法是观察规律,设计一个构造规则,从中心小矩形,想四周扩展,同理可以扩展四个角上的小矩形,而中心矩形有9!个排列组合。这样就可以生成足够多的初始化数独了。程序非常简单。

1.16 24点游戏

怎么遍历所有的可能表达式组合?首先分析可能的组合数量,然后提出一个算法。在实现的时候辅助数组的技巧,好好体会。

所谓的所有可能的实现过程,无非是任取两个数进行可能的运算,然后替换回原来的数组,直到数组长度变为1,这就是可以得到的结果。

源程序有两个技巧要体会,更新数组的更新技巧,表达式数组的跟随技巧。

求一个集合的所有子集的技巧。用二进制位来表示。划分可以用按照位与计算来判断是否为某个划分的子集。

1.17 俄罗斯方块游戏

学习如何设计数据结构来存储状态,如何设计游戏过程,如何判断哪个状态更好。

1.18挖雷游戏

无。

第二章 数字之魅

2.1 求二进制中1的个数

首先有个直接的方法,就是位右移操作,然后与0x01与来判断。

其次有个改进的算法,每次x&=(x-1),这样可以增加效率,至于1的个数有关。

2.2 阶乘算法

如何查找乘数含有的分解因子。

2.3 需找发帖水王

抵消方法,逐一两两淘汰,实力最强的剩下。

2.4 1的数目

这个题目当初第一次就会做,注意观察数字的渐变规律就可以了。

2.5 寻找最大的K个数

1.使用快排寻找第K+1大的位置,左边的数组就是要找的数据。

2.或者使用优胜劣汰的思想,但是k个临时优胜者可以建成堆,这样可以降低复杂度。

3.这个问题不喜欢用二分查找来查找,不过也是一个很不错的方法。

2.6 精确表达浮点数

循环小数如何化成分数(加倍然后相减)

2.7最大公约数

经典的辗转取余算法。

如果不用除法,怎么改进算法。(也是问题的转化,只不过通过除2来实现)

2.8找符合条件的整数

输入N,求M,使N*M的结果是只含01的自然数。

问题转化成求01组成的自然数,使其对N取余为零。

对于这个问题可以通过构造一个大小为N的取余数组,然后逐步递推求解。

问题可以扩展为012组成的自然数,使其对N取余为零。

我很喜欢这个题目。好好理解这种解题方法。

2.9斐波那契数列

用二进制表示一个整数有很强的实用价值,每个位置都是下一个位置的两倍,应用在矩阵的乘法运算中,可以用来快速计算矩阵的高次方幂问题。

 M可以把n拆分成二进制的幂级数表达,这样可以把时间复杂度降低到logN。

2.10 寻找数组中的最大值与最小值

维持一个辅助数组就可以了,可以类比寻找前k大的数,那个还可以用快排。

另外这儿也可以用分治的思想,不过没有什么优越性。

2.11 寻找最近点对

可以考虑分而治之的思想,可以降低复杂度提高效率。

一个扩展问题是求一个数组中相邻(指的是如果a,b相邻,则在数组中无其他数的大小输入(a,b))数的最大值。

如果排序后查找复杂度为N*logN,如果采用桶排序的思想和抽屉思想,我们可以建立N个桶,每段的取值下限为[Min]+k*[Max-Min]/N,k∈[0,N-1],长度为[Max-Min]/N,这样遍历一遍可以放到相应的桶里,然后求出每个桶内部的最大最小值,从而通过相邻桶的最大最小值只差,可以寻找出最大的相邻数之差。

2.12寻找数组中和为某个值的一对数

这个可以扩展到求三个数的和为一个定值。本身没有什么难度,只要排序后,设置前后两个工作编号从两端相向移动即可。

联想到求的组合问题,写了个小程序:

#include <iostream>

#include <assert.h>

using namespace std;

int arr[10]={0};int top=-1;

void show()

{

for(int i=0;i<=top;++i)

cout<<arr[i]<<" ";

cout<<endl;

}

void search(int n,int m,int start=1)

{

assert(m>=0&&m<n);

if(m==0)

{

show();

return;

}

if(m==n-start+1)

{

for(int i=start;i<=n;++i)

arr[++top]=i;

show();return;

}

arr[++top]=start;

int temp=top-1;

search(n,m-1,start+1);

top=temp;

search(n,m,start+1);

}

void main()

{

int a,b;

cin>>a>>b;

search(a,b);

::system("pause");

}

可以输出所有的组合选择。

2.13子数组的最大乘积

方法一使用的是常用的编程技巧,通过两个辅助数组来求所有的N-1个数的乘积。方法二采用的是面向问题的直接分析法,通过分析数组的构成,(0的个数,正数的个数,负数的个数)来推断出最大的乘积应该是什么情况。

2.14 求数组的子数组之和的最大值

编程之美上给出的ON)算法是一个递推式子,因为start[N]可以由start[N+1]推导出来,只需要后序遍历一次就能填满start数组,然后遍历start数组找到最大值即可。

当初我想到的方法是从前向后遍历,一旦和为负值则重新设置求和起点,到目前位置还没看到别人使用这个方法。其实这两个方法是思维的两个对立面,都应该好好体会。

关于扩展问题数组首尾相连的问题,可以使用求补的思想,先分类为原问题+跨越尾部的一个问题,第二个问题可以转化成求数组中子数组的和为负值且最小的问题,这样跟原问题就一个解决方法了。

2.15 子数组之和的最大值(二维)

首先提出一个穷举的方法来实现。注意一些重复计算的优化方法。(通过预处理一个辅助数组来达到目的)

第二个方法是利用已有的一维情况下的高效算法提高效率。转化的方法是通过合理的分类,转化成一维问题。留下的启发就是可以减小问题规模从而发现小规模下问题的高效方法。

关于扩展问题,二维左右相连(圆筒),二维左右上下相连(游泳圈),这主要考察的是分类的思想,在每种类型下该怎么转化问题。

2.16 数组中最长递增子数列

这个问题是我永远的痛,微软面试挂在这个题目上了。

直接面向问题本质,在已有的递增数列中查找可以使用的,从而产生分类规则为尾节点分类。

问题可以进一步优化到N*logN,方法跟之前求余数的递推过程原理类似。

2.17 数组循环右移k

只需要逆转即可。

2.18 数组分割

有一个多项式算法的近似解算法。如果要求出最优解,要穷举所有n种组合或者穷举所有N个数之和的取值。然后再这个前提下提出解决方法。

编程之美上的两个方法都不可行,但是可以拿来做参考。

2.19 区间重合判断

启发:所有有序序列的查找,都可以使用二分查找。

注意灵活变通。

2.20 程序理解和时间分析

呵呵。

2.21只考加法的面试题

只是发现奇数一定可以拆分。如果查找一个数的组合可以在它的1/N处查找连续N个数的和能不能组成这个数字。

第三章 结构之法

3.1 字符串移位包含的问题

首先联想到之前的字符串移位算法,这儿判断的是移位后包含某个子字符串的问题,问题可以转化为2个原字符串连续连接,然后再判断,体会问题转化的方法。

3.2电话号码对应英语单词

这个主要是学习数据结构的设计,以及对于多重for循环怎么转化为一个合理的while循环。多多体会程序设计的精妙方法。

3.3 计算字符串的相似度

这个问题给的启发:如果找不到一个特别优化的解决方法,那么就考虑使用穷举法。对原来的问题进行分析归类,可以使用递归的思想把所有的情况都找出来,然后取一个相似度最大的选择。

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

呵呵,这个问题就是要学会灵活变通,通过逻辑上的删除来实现,而不一定非要物理地址上删除。

3.5最短摘要的生成

这个问题还是学习算法的执行过程,合理设计程序执行流程。

3.6判断两个链表是否相交

判断最后一个节点即可。

3.7队列中取最大值操作问题

这个是经典问题,用栈来实现队列,栈取最大值可以O1)时间复杂度。

熟记这个问题。

3.8求二叉树中节点的最大距离

呵呵,使用递归思想,设计好每层的逻辑即可。

熟记这个问题。

3.9重建二叉树

这个问题我在csdn博客上写过,并且还能判断输入是否合理。

熟记这个问题。

3.10分层遍历二叉树

这个是队列的典型应用,只需要在队列节点中设置一个层序号即可。

熟记这个问题。

3.11程序改错

这个主要是考察二分查找,在各种情况下的合理使用。

熟记二分查找的各种使用,主要是在左右查找的逻辑判断上,一般都是以minmax终止,然后min max都要判断一下,看看哪一个符合要求。

第四章 数学之趣

4.1 金刚坐飞机问题

分类讨论,全概率公式,以及递推关系式的建立。

4.2 瓷砖覆盖地板

扩展问题还是有点意思的,就是问题转化,递归程序设计。

4.3 买票找零

卡特兰数    Catalan数   中文:卡特兰数   原理:    令h(1)1catalan数满足递归式:    h(n)= h(1)*h(n-1) + h(2)*h(n-2) + ... + h(n-1)h(1) (其中n>=2)   另类递归式:    h(n)=((4*n-2)/(n+1))*h(n-1);   该递推关系的解为:  h(n)=C(2n,n)/(n+1) (n=1,2,3,...) f[n]=(2*n)!/(n!*(n+1)!)     我并不关心其解是怎么求出来的,我只想知道怎么用catalan数分析问题。   我总结了一下,最典型的四类应用:(实质上却都一样,无非是递归等式的应用,就看你能不能分解问题写出递归式了)   1.括号化问题。    矩阵链乘: P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?(h(n))   2.出栈次序问题。    一个栈(无穷大)的进栈序列为1,2,3,..n,有多少个不同的出栈序列?    类似:有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票,剧院无其它钞票,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票找零?(将持5元者到达视作将5元入栈,持10元者到达视作使栈中某5元出栈)   3.将多边行划分为三角形问题。    将一个凸多边形区域分成三角形区域的方法数?    类似:一位大城市的律师在她住所以北n个街区和以东n个街区处工作。每天她走2n个街区去上班。如果她    从不穿越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路?   类似:在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?     4.给顶节点组成二叉树的问题。    给定N个节点,能构成多少种不同的二叉树?   (能构成hN)个) 

4.4 是否在三角形以内

三角形面积公式:令 P=a+b+c/2 , =P(P-a)(P-b)(P-c)。

内积公式:·=

叉乘公式为

叉乘可以用来判断是否是在向量的左边。(叉乘结果为正)

4.5 磁带文件存放优化

概率公式

4.6 桶中取黑白球

典型的异或操作,结合异或操作的可结合性质,可以得出结果。

4.7 蚂蚁爬杆

问题很经典,但是扩展问题更有意思一点。

问题是第i个蚂蚁的走出时间,还有一个问题是总共碰头多少次。

可以把杆子上的蚂蚁分为两类,向右的标志为1,向左的标志为0,那么上面两个问题都变为一个排列问题,如果把初始排列转化为左边全0,右边全1,在交换排序过程中,交换的次数就是碰头次数。

i个蚂蚁在逻辑上等效于它所在位置对应的排列后的那个蚂蚁的走出时间,比如一个初始排列 1001011100  1向右走,0向左走),那么最后一个蚂蚁在逻辑上对应的是排列后这个位置上的蚂蚁,也就是倒数第三个蚂蚁的逻辑走出时间。

4.8 三角形测试用例

测试分类: 正常输入,非法输入,正常跟非法的临界输入。

正常输入又分为: 每种类型的输入,每种类型分界点的临界输入。

4.9 数独知多少

块行解,块列解,块解,然后假设独立取近似值。

没什么意思。

4.10 数字哑谜和回文

程序设计还是有点意思的。

辅助数组的设计。

你可能感兴趣的:(读书笔记)