算法(一)
2015-08-15 22:32
190 查看
这将是一个持续更新的文章,算法题大多数会来自于算法导论
不知道有没有其他的算法,感觉应该会有更简单的…
首先我们有三个观察结论:
(1) 1号助理总是会被雇用;
(2) 最佳助理(即rank为n的助理)总是会被雇用;
(3) 最佳助理不可能是1号助理,因为那样将只能刚好雇用一次。
在使HIRE-ASSISTANT刚好雇用两次的序列中,一号助理必然有rank=i<=n-1,所有rank在[i+1..n-1]区间内的助理必然在rank为n的助理被面试之后被面试。
设Ei表示1号助理被雇用的情况,则对于任意给定的i,有Pr{Ei}=1/n。
设j指向最佳助理在面试序列中的位置,让F表示2、3、…、j-1号助理的rank比1号助理低的情况。假设Ei成立,则当最佳助理在rank为i+1、i+2、…、n的n-i个助理之前被面试时F成立。于是,Pr{F|Ei}=1/(n-i)。
设A表示HIRE-ASSISTANT刚好雇用两次的情况。于是我们有:
A=F∩(E1∪E2∪…∪En-1)
=(F∩E1)∪(F∩E2)∪…∪(F∩En-1)
Pr{A}=∑Pr{F∩Ei} (i<-1 to n-1)
Pr{F∩Ei}=Pr{F|Ei}Pr{Ei}
=1/(n-i)*(1/n)
所以
Pr{A}=∑1/(n-i)*(1/n) (i<-1 to n-1)
=1/n*∑1/(n-i) (i<-1 to n-1)
=1/n*(1/(n-1)+1/(n-2)+…+1/1)
【方法二】
面试顺序第i位的应聘者被雇用的概率为1i,不被雇用的概率为i−1i(在算法导论正文部分有证明),那么仅有两人被雇用的概率为Σk(∏ki=2i−1i)⋅1k+1⋅∏ni=k+2i−1i.(注意各项表示的是第k+1位被聘用)
化简之后得到Σk1nk,考虑k的取值,可以为1,2,…,n-1,因此最终结果为1/n*(1/(n-1)+1/(n-2)+…+1/1).
[b]这个算法达到目的了吗?[/b]
这个算法是错误的,一个例子如下:
对于{1,2,3}采用以上算法,可以得到以下结果
解释:根据题述算法,一共将进行nn次操作,如果画树状图,最后将得到nn个最终分支,但这些分支只能分配到n!中排列中去,由于n!不一定整除nn,每种排列得到的概率不一定相等。
[b]b) 说明如何在O(m+n)的时间内,将一个新元素插入到一个未满的m×n的Young氏矩阵中。[/b]
[b]c) 在不使用其他排序算法的情况下,试说明如何利用一个n×n的Young氏矩阵在O(n3)的时间内对n2个数进行排序。[/b]
[b]d) 设计一个O(m+n)的算法,来判断一个给定的数是否储存在Young氏矩阵中。[/b]
a)
Note: 假设Array.size为Array中存在元素的总数。
b)
c)
非常类似于堆排序。
就得到了倒序排列的数组Array。运行时间的计算:
O(n⋅Σn1i)=O(n3)
d)
运行时间分析:
最坏情况下,T(m,n)=T(m−1,n)+O(1)或T(m,n)=T(m,n−1)+O(1),易知运行时间为O(m+n)。
1. 描述一个运行时间为Θ(nlogn)的算法,给定n个整数的集合S和另一个整数x,该算法能够确定S中是否存在两个其和刚好为x的元素。
先将S中元素用Θ(nlogn)的排序算法排序,得到sorted array A,然后从A[n]开始,依次对A[0,...,n−i]进行二分查找,需要Θ(logn)的运行时间,因此总共需要Σn1log i的运行时间,易知Σn1log i=Θ(nlogn)。因此该算法符合条件。不知道有没有其他的算法,感觉应该会有更简单的…
2. (习题5.2-2)在HIRE-ASSISTANT中,假设应聘者以随机的顺序出现,正好雇用两次的概率是多少?
【方法一】(摘自国境之南Fantasy的博客)首先我们有三个观察结论:
(1) 1号助理总是会被雇用;
(2) 最佳助理(即rank为n的助理)总是会被雇用;
(3) 最佳助理不可能是1号助理,因为那样将只能刚好雇用一次。
在使HIRE-ASSISTANT刚好雇用两次的序列中,一号助理必然有rank=i<=n-1,所有rank在[i+1..n-1]区间内的助理必然在rank为n的助理被面试之后被面试。
设Ei表示1号助理被雇用的情况,则对于任意给定的i,有Pr{Ei}=1/n。
设j指向最佳助理在面试序列中的位置,让F表示2、3、…、j-1号助理的rank比1号助理低的情况。假设Ei成立,则当最佳助理在rank为i+1、i+2、…、n的n-i个助理之前被面试时F成立。于是,Pr{F|Ei}=1/(n-i)。
设A表示HIRE-ASSISTANT刚好雇用两次的情况。于是我们有:
A=F∩(E1∪E2∪…∪En-1)
=(F∩E1)∪(F∩E2)∪…∪(F∩En-1)
Pr{A}=∑Pr{F∩Ei} (i<-1 to n-1)
Pr{F∩Ei}=Pr{F|Ei}Pr{Ei}
=1/(n-i)*(1/n)
所以
Pr{A}=∑1/(n-i)*(1/n) (i<-1 to n-1)
=1/n*∑1/(n-i) (i<-1 to n-1)
=1/n*(1/(n-1)+1/(n-2)+…+1/1)
【方法二】
面试顺序第i位的应聘者被雇用的概率为1i,不被雇用的概率为i−1i(在算法导论正文部分有证明),那么仅有两人被雇用的概率为Σk(∏ki=2i−1i)⋅1k+1⋅∏ni=k+2i−1i.(注意各项表示的是第k+1位被聘用)
化简之后得到Σk1nk,考虑k的取值,可以为1,2,…,n-1,因此最终结果为1/n*(1/(n-1)+1/(n-2)+…+1/1).
3. (习题5.3-3)为生成均匀随机排列。给定1,2, … ,n的一个排列A,采用以下算法
n = A.length for i = 1 to n swap A[i] with A{RANDOM(1, n)]
[b]这个算法达到目的了吗?[/b]
这个算法是错误的,一个例子如下:
对于{1,2,3}采用以上算法,可以得到以下结果
permutation | probability |
---|---|
1, 2, 3 | 4/27 |
1, 3, 2 | 5/27 |
2, 1, 3 | 5/27 |
2, 3, 1 | 5/27 |
3, 1, 2 | 4/27 |
3, 2, 1 | 4/27 |
4. (思考题6-3在)一个Young氏矩阵中,每一行的数据都是从左到右排序的,每一列的数据都是从上到下排序的。不存在的元素可以表示为∞。
[b]a) 请给出一个在m×nYoung氏矩阵上时间复杂度为O(m+n)de EXTRACT-MIN的算法实现。[/b][b]b) 说明如何在O(m+n)的时间内,将一个新元素插入到一个未满的m×n的Young氏矩阵中。[/b]
[b]c) 在不使用其他排序算法的情况下,试说明如何利用一个n×n的Young氏矩阵在O(n3)的时间内对n2个数进行排序。[/b]
[b]d) 设计一个O(m+n)的算法,来判断一个给定的数是否储存在Young氏矩阵中。[/b]
a)
Note: 假设Array.size为Array中存在元素的总数。
\\EXTRACT-MIN(Array)的伪代码 count_x = count_y = 0; min = Array[count_x][count_y]; Array[0][0] = (type *)Array[size]; size--; while((count_x+1)*(count_y+1) < Array.size) if ((count_x+1)*count_y <= Array.size && Array[count_x+1][count_y] > current) large_x = count_x+1; large_y = count_y; else large_x = count_x; large_y = count_y; if ((count_y+1)*count_x <= Array.size && Array[count_x][count_y+1] > current) large_x = count_x; large_y = count_y+1; if (large_x == count_x && large_y == count_y) break; else swap A[large_x][large_y] with A[count_x][count_y]; count_x = large_x; count_y = large_y; return min;
b)
//INSERT-ELEMENT(a, Array)的伪代码 if (Array.size == m * n) return; else Array.add(a); Array.size++; current_x = (size-1)/n; current_y = (size%n; while(current_x!=0 && current_y !=0) if (current_x ==0) if (Array[0][current_y-1] <= A[0][current_y]) break; else swap Array[0][current_y-1] with A[0][current_y]; current_y--; else if (current_y == 0) if (Array[current_x - 1][0] <= A[current_x][0]) break; else swap Array[current_x - 1][0] with A[current_x][0]; current_x--; else if (Array[current_x-1][current_y] > Array[current_x][current_y]) large_x = current_x - 1; large_y = current_y; else large_x = current_x; large_y = current_y; if (Array[current_x][current_y-1] > Array[current_x][current_y]) large_x = current_x; large_y = current_y - 1; if (large_x == current_x && large_y == current_y) break;
c)
非常类似于堆排序。
//YOUNG-MATRIX-SORT(Array) while (Array.size>2) min = EXTRACT-MIN(Array); Array[0][0] = (type *)Array[size]; (type *)Array[size] = min; size--;
就得到了倒序排列的数组Array。运行时间的计算:
O(n⋅Σn1i)=O(n3)
d)
//FIND(a, Array, x, y),x为搜寻范围的行数,y为列数。使用时x=m, y=n。 FIND(a, Array, x, y) { if (x==1 && y==1) return (Array[0][n-1] == a); if (a == Array[x-1][n-y]) return true; if (a < Array[x-1][n-y] && a >= Array[0][n-y]) FIND(a, Array, x-1, y); else if (a > Array[x-1][n-y] && a <= Array[x-1][n-1]) FIND(a, Array, x, y-1); else return false; }
运行时间分析:
最坏情况下,T(m,n)=T(m−1,n)+O(1)或T(m,n)=T(m,n−1)+O(1),易知运行时间为O(m+n)。
相关文章推荐
- JavaScript演示排序算法
- 算法之排序算法的算法思想和使用场景总结
- php 地区分类排序算法
- js三种排序算法分享
- Javascript中的常见排序算法
- java 合并排序算法、冒泡排序算法、选择排序算法、插入排序算法、快速排序算法的描述
- 排序算法的javascript实现与讲解(99js手记)
- C++中十种内部排序算法的比较分析
- Java实现几种常见排序算法代码
- 浅谈javascript实现八大排序
- PHP常用的排序和查找算法
- JavaScript中九种常用排序算法
- STl中的排序算法详细解析
- PHP四种基本排序算法示例
- 排序算法之PHP版快速排序、冒泡排序
- JavaScript排序算法之希尔排序的2个实例
- Java常用排序算法及性能测试集合
- Java中常用的6种排序算法详细分解
- Javascript排序算法之合并排序(归并排序)的2个例子
- java算法导论之FloydWarshall算法实现代码