变化形式
插入排序
理解
伪代码
for i<-1 to n-1 do
v<-A[i]
j<-i-1
while j>=0 and A[j]>v do
A[j+1]<-A[j]
j<-j-1
A[j+1]<-v
拓扑排序
使用有向无环图来指明事件的优先次序。也就是将图的所有节点在一条水平线上排开,形成拓扑序列。
减治(减一)法
理解
深度搜索
生成全排列
减治法
茶托方法
伪代码
将第一个排列初始化为
生成子集
减治法
扩展
生成二进制反射格雷码
根据规律一层一层处理
n位Gray码={(n-1)位Gray码,在第n位填0或1;0或1}
伪代码
假币问题
有n个外观完全相同的硬币,其中1个是假币,其他n-1个的重量完全一样,假币较轻。求用一个天平,称几次可以找出假币
折半查找
伪代码
//输出K对应值的下标
l<-0;r<-n-1;
while l<=r do
m<-[(l+r)/2]
if K=A[m] return m
else if K<A[m] r<-m-1
else l<-m+1
return -1
约瑟夫斯问题
n个人围成一圈,编号从1~n;从第一个人开始喊口号,只喊1和2,喊2的人淘汰直到只有1个人为止。求编号。
不考虑编号时:奇数:f(n)=f(2n+1) 偶数:f(n)=f(2n)
减治法
以喊到2则淘汰为例:
格式:人数(n) 获胜者编号(0-n-1)
1 0
2 0
3 2
4 0
5 2
6 4
7 6
8 0
总结出规律:n个人的获胜者编号=(n-1个人的获胜者编号+2)mod n
那么递归函数:f[n]=(f[n-1]+2) mod n; f[1]=0
程序代码
int win(int n,int f)
{
if (n == 1)
return 0;
return (win(n - 1, f) + f) % n;
}
减可变规模算法
计算中值和选择问题
Lomuto划分
伪代码
//用第一个元素作为中轴对子数组进行划分
//input:数组A[0...n-1]的一个子数组A[l...r]
//output:A[l..r]的划分和中轴的新位置
p<-A[l]
s<-l
for i<-l+1 to r do
if A[i]<p
s<-s+1;swap(A[s],A[i])
swap(A[l],A[s])
return s
插值查找
二叉查找树的查找和插入
NIM博弈
n堆物品,第i堆物品有Ai个。两名玩家轮流行动,每次可以任选一堆,取走任意多个物品,可把一堆取光,但不能不取。取走最后意见物品着获胜。
以3 4 5为例:
将每堆的堆数分解为二进制数:011 100 101;
一位位分析:第一位有2个1,第二位有1个1,第三位有2个1(异或后就会只剩下第二位的1)
先手可以在后手选择时,保持剩余的1的数量为偶数
那么此时不论后手怎么拿,都不会是最后拿走的人。
然而异或操作可以看做是:判断单个位中1的个数,偶数个为0,奇数个为1
那么问题就变为:一些二进制数,异或后,为0先手输,为1先手赢。