《算法设计手册》杂题3道

简介:

最近找工作的事告一段落,发一些之前整理但未发表的文章。鉴于各个公司一般要求将所做笔试题和面试题保密,并要求在试卷上签署了相关协议,因此本人不会在后续博文中提及并分析,见谅。

 

1.归纳法找递归函数的输出(原书P16~17,1.3.4节)

归纳并证明下面函数的输出:

复制代码
int increment(int y) {

  if (y==0)

    return 1;
  if(y%2 == 1)

    return 2*increment(y/2);
  else

    return y+1;
}
复制代码

解答:

  事实上increment(y)=y+1。

  证明:

(1)(归纳法)y=0时输出1。

(2)

y为偶数时,输出y+1;

y为奇数时,不妨令y=2m+1,那么2*increment((2m+1)/2) = 2*increment(m)。由于m<y且increment(m)=m+1 (归纳假设),那么输出为2*(m+1) = y+1。

得证。

 

2.动态数组的时间复杂度(原书P67,3.1.1节)

用下面的方式实现动态数组:首先分配大小为1的连续空间,当需要填入第2个元素时,分配大小为2个连续空间,把原来的1个元素复制进新空间,再把新元素填入,销毁原空间;依次类推,动态数组的容量变化过程为1->2->4->8->...。当数组中一共有n个元素时,一共被复制了几次?

解答:

为简化分析,n此时是2的幂且刚好把数组填满。可以看出,其中1/2的元素没有被复制过,另外1/2在上次扩展时复制了一次。即,上次扩展时复制了n*(1/2)个元素。一共扩展了logn次,因此复制的总次数为:


n*(\frac{1}{2}+\frac{1}{4}+...+\frac{1}{2^{logn}})

其中2^logn = n。由极限知识可知,当n→∞时,和为2n。因此n个元素的复制次数不超过2n次,保持了O(n)的时间复杂度。

附注:

  Nginx封装的数据结构ngx_array_t就是一种动态数组,采用了类似的内存分配策略。

 

3.最小堆第k小的元素与给定x的大小关系:kth>=x是否成立?(原书P116~117,4.3.2节)

对一个数组实现的n个元素的最小堆和给定的实数x,判断堆中第k小元素是否大于等于x?(0<k<n)要求算法最坏时间复杂度为O(k)。(提示:没必要找出第k小元素的具体值)

解答:

  最直接的两种解法:从堆中选取最小元素k次,时间复杂度O(klogn);检查堆中前k层所有元素,时间复杂度O(n,2^k)。这两种解法都不符合时间复杂度的要求。

  实际上是从根开始遍历所有值小于x的结点:

复制代码
//第一次调用时,i=1,count=k
int heap_compare(heap *h,int i,int count,int x)
{
    if((count<=0)||(i>h->size))
        return count;
    if(h->h[i]<x) {
        count = heap_compare(h,LEFT(i),count-1,x);
        count = heap_compare(h,RIGHT(i),count,x);
    }
    return count;
}
复制代码

  如果根大于等于x,那么其余所有元素都不可能小于x,第k小的元素必然大于等于x。这时返回值为k>0。(若k=1,那么第1小的元素就是根,结果不变)

  如果根小于x,需要对根的两个后继进行遍历。如果你没有看明白这段程序的含义,下面以几个例子来帮助理解这个函数在递归调用时发生了什么。假定k=3,x=3,即判断第3小的元素是否大于等于3。简单起见,结点以下标代替,根为1(与原书一致)。

  实例1:第k小的元素大于等于x。

  实例2:第k小的元素大于等于x。原图交换顺序。

  实例3:第k小的元素小于x。

 

  从上面三个例子可以看出:

  每找到一个小于x的元素都会消耗一个count,如果消耗完了k个,表示至少前k个都小于x。那么第k个必然小于x,后面不必再进行查找,返回值为0。

  反之,如果遍历所有小于k的元素时未消耗完k个count,表示小于x的元素不足k个,那么第k个必然大于等于x,返回值为正值。

  原代码中令人迷惑的地方在于count的使用,理清上面的两个关系就好理解了。虽然看上去这个函数对于一个结点的两个后继的处理地位不同,但实际上没有影响。

  至于时间复杂度,由于我们只遍历了所有小于x的结点以及它们的后继,而且遍历时不超过k个(用完k个就return 0),因此大约是3k个结点,时间复杂度只有O(k),符合要求。

  这道题曾在Amazon的面试中出现。

  stackoverflow上有一个变形:判断n元最大堆中第k大的元素是否大于给定的数x,处理方法类似。




本文转自五岳博客园博客,原文链接:http://www.cnblogs.com/wuyuegb2312/p/3257408.html,如需转载请自行联系原作者

目录
相关文章
|
算法
算法设计与分析/数据结构与算法实验1:棋盘覆盖问题
算法设计与分析/数据结构与算法实验1:棋盘覆盖问题
199 0
算法设计与分析/数据结构与算法实验1:棋盘覆盖问题
|
算法
《算法技术手册》一1.3.2 分治算法
本节书摘来华章计算机《算法技术手册》一书中的第1章 ,第1.3.2节, George T.Heineman Gary Pollice Stanley Selkow 著 杨晨 曹如进 译 译更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1171 0
|
算法
《算法技术手册》一3.5.5 算法分析
本节书摘来华章计算机《算法技术手册》一书中的第3章 ,第3.5.5节, George T.Heineman Gary Pollice Stanley Selkow 著 杨晨 曹如进 译 译更多章节内容可以访问云栖社区“华章计算机”公众号查看。
829 0
|
算法
《算法技术手册》一3.6.2 分治
本节书摘来华章计算机《算法技术手册》一书中的第3章 ,第3.6.2节, George T.Heineman Gary Pollice Stanley Selkow 著 杨晨 曹如进 译 译更多章节内容可以访问云栖社区“华章计算机”公众号查看。
962 0
|
算法 Java Python
《算法技术手册》一导读
Fortune算法,它用于计算点集的Voronoi图。 归并排序,既包括针对内存数据的内部排序,也包括外部文件的外部排序。
1729 0
|
存储 算法
《算法技术手册》一3.4.2 舍入误差
本节书摘来华章计算机《算法技术手册》一书中的第3章 ,第3.4.2节, George T.Heineman Gary Pollice Stanley Selkow 著 杨晨 曹如进 译 译更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1552 0
|
算法
《算法技术手册》一1.3.1 贪心算法
本节书摘来华章计算机《算法技术手册》一书中的第1章 ,第1.3.1节, George T.Heineman Gary Pollice Stanley Selkow 著 杨晨 曹如进 译 译更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1076 0
|
算法
《算法技术手册》一2.3.3最好情况
本节书摘来华章计算机《算法技术手册》一书中的第2章 ,第2.3.3节, George T.Heineman Gary Pollice Stanley Selkow 著 杨晨 曹如进 译 译更多章节内容可以访问云栖社区“华章计算机”公众号查看。
751 0
|
算法
《算法技术手册》一1.3.3 并行算法
本节书摘来华章计算机《算法技术手册》一书中的第1章 ,第1.3.3节, George T.Heineman Gary Pollice Stanley Selkow 著 杨晨 曹如进 译 译更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1206 0

相关实验场景

更多