您的位置:首页 > 其它

算法(一)

2015-08-15 22:32 190 查看
这将是一个持续更新的文章,算法题大多数会来自于算法导论

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}采用以上算法,可以得到以下结果

permutationprobability
1, 2, 34/27
1, 3, 25/27
2, 1, 35/27
2, 3, 15/27
3, 1, 24/27
3, 2, 14/27
解释:根据题述算法,一共将进行nn次操作,如果画树状图,最后将得到nn个最终分支,但这些分支只能分配到n!中排列中去,由于n!不一定整除nn,每种排列得到的概率不一定相等。

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)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息