《编程之美》

1.7 光线切割

转换为逆序数问题

1.8停电梯问题

自己想的:重心法
书上:类记录表法,停的位置每往上一层,需要多走的人次
进阶:电梯在k个楼层停
或者说,并不是所有的人都需要坐电梯的,实在很低的楼层就直接走上去了,因此初始问题实际上也是一个双层的问题

1.9 见面会

思路:转化为染色问题,针对染色问题思路,尝试用K种颜色进行染色,逐渐增大K的值。查询邻接顶点颜色表
进阶:集中安排

1.11 排石头游戏

思路:类似于小时候玩的三五七
进阶:动态规划+记录表还可以解决
(1)先取完者失败的问题
(2)每次可以取1-k块问题
实际上是拈游戏(NIM)的一种,可以推广为n行,每次取k个

1.13两堆石头

思路:求质数所用的筛选法
记录表法是从一个合理的基础推导出所有合理的可能解
而筛选法则是从排除项的基础推导出所有排除项
进阶:NIM4
(1)第一个玩家不能拿光所有
(2)每次最多只能拿前一个所拿的两倍
过程并不是独立的,受到上一次情况的影响
条件(2)限制的是每次向前搜索的范围,所以才会出现斐波那契数列的情况

综合1.11-1.13

对于这些双人博弈的问题,向前推理的过程中存在先手和后手转化的情况

1.15 数独

快速构造数独的方法
貌似我还有一个没写完的解数独程序

1.16 24点

分治法在于子问题的求解与顺序无关
因此可以用二分法将速度加快到log级别

2.1 二级制中1的个数

1、原数减一相与可以减少一个1的数量
2、查表法,以空间换时间
3、对于32位数,可以拆成4个8位二进制再查表,这就是子问题与顺序无关的一个代表

2.2 阶乘

N!中含有2的质因数的个数,还等于N减去N的二进制中表示1的个数,转化为2.1

2.3 水王

问题:发帖数超过总帖子数的一半
1、先排序,无论如何N/2的帖子必为水王的
2、同时删除两个不同的ID
推广:3个人超过1/4,同时删除4个不同的ID

2.4 1的个数

个十百位分别计算1的个数

2.5寻找最大的K个数

关键:不需要管找出来的K个数内部顺序,是排序算法的一个退化算法
1. 参考快排
2. 根据比K大的个数二分
3. 要求最大的K个数,先随机营造这样一个集合,再不断淘汰小数(可以借助堆的数据结构)
4. 计数排序(记录表法实乃空间换时间的典范,但如果数的范围很大,则空间浪费了,时间也没有省)
http://www.cnblogs.com/kaituorensheng/archive/2013/02/23/2923877.html
5. 基数排序
排序算法稳定性的意义:分级排序

2.6 精确的浮点数

关键:循环小数的处理
乘以10^m,m为循环小数的位数

2.7 最大公约数

  1. 最大公约数:辗转相除法(递归)
  2. 针对大整数取模运算的开销,可以采用辗转相减法。
  3. 移位运算可以低开销代替以2为除数的除法运算。
    具体运算过程:x,y能/2就/2,不能/2再用辗转相除法。

2.8 找到NM乘积只含01的最小M

两者对接问题,搜索M运算量太大,但是乘积是由明显特征的,可以减小搜索量
同余的只保留一个
直观理解:

        1
    10     11
 100 101  110 111

假设10与11同余,则11下面的所有子树都可以不考虑。

证明:
10s10s+(ts)10s+2(ts)...10s+(N1)(ts)(modN)
10s+10s+(ts)+...+10s+(N1)(ts)0(modN)
扩展问题2:在原问题的基础上继续向下迭代

2.9斐波那契数列

  1. xn+1=xn+xn1
    可以由特征方程 x2=x+1
    解得 x1,x2
    则通项公式为 Fn=Axn1+Bxn2 待定系数即可

  2. 矩阵递推,方便表示2的幂次结果,采用二进制分解
    (Fn,Fn1)=(Fn1,Fn2)A
    其中: A=[1110]

2.11寻找最近点对

分治法没毛病,但是在left与right之间最小值时充分利用左右部分已经求得的最小值,化简问题。
两个正方形内部才是可能有效解出现的位置。

扩展问题:
1. 求相邻最近数对最大差值
普通思维:先排序再相减 O(nlog2n)+O(n)
利用抽屉原理,减少桶排序所需要的空间,求桶最大值与下一个桶最小值之间差值最大值,对于部分数据较为集中的数据较好
2. 求最大距离点对
(1) 求凸包:
卷包裹法(每次遍历所有剩余点求得一个有效点)
Graham Scan(先排序,时间复杂度 O(nlog2n)+O(n)
(2) 求最大距离:3点到直线的最大距离,点与直线都是逆时针旋转的
参考:http://blog.csdn.net/hackbuteer1/article/details/7484746

2.12 给定一个数N与数组S,求S中最接近N的子集

  1. 递归
list1.push_front(n);      //典型的01背包问题  
find_factor(sum-n, n-1);   //放n,n-1个数填满sum-n  
list1.pop_front();  
find_factor(sum, n-1);     //不放n,n-1个数填满sum  

这里因为是从1~n取,所以用了n直接传入n-1即可,对于任意数组应该传递剩余数组。

参考:http://blog.csdn.net/v_JULY_v/article/details/6419466

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值