笔试算法题(22):二分法求旋转数组最小值 & 骰子值概率

出题:将一个数组最开始的k个(K小于数组大小N)元素照搬到数组末尾,我们称之为数组的旋转;现在有一个已经排序的数组的一个旋转,要求输出旋转数组中的最小元素,且时间复杂度小于O(N);

分析:

  • 时间复杂度小于O(N)也就是不能用常规的遍历思路;可以将数组看成两个都是递增序列(假设为升序)的子数组,并且前半段的元素均大于等于后半段的元素,分界点的位于后半段数组的第一个元素就是最小元素;
  • 具体算法:两个指针left和right指向数组第一个和最后一个元素,使用Binary Search确定中间元素middle,如果middle小于left说明其在后半段,则right=middle;如果middle大于right说明 其在前半段,则left=middle,最终left和right会逼近前后段数组的分界点,所以可以找到最小元素,时间复杂度为O(logN);

解题:

 1 int findMinimumRatatingArray(int *array, int length) {
 2         int left=0;
 3         int right=length-1;
 4         
 5         int middle;
 6         while(true) {
 7                 middle=(left+right)/2;
 8                 if(right-left == 1) {
 9                         middle=right;
10                         break;
11                 }
12                 
13                 if(array[middle]>=array[left])
14                         right=middle;
15                 if(array[middle]<=array[right])
16                         left=middle;
17         }
18         return array[middle];
19 }

 

出题:N个骰子扔在地上,所有骰子的朝上一面的值和为S,要求确定S所有可能出现的值的概率;

分析:

  • 一个骰子有6个面,所以有6个值,每个值出现的概率为1/6;对于N个骰子,S的取值范围是[N,6N],统计N到6N之间每一个数出现的次数,然后除以 6^N就是最后每个数出现的概率;
  • 使用递归函数,设定当前骰子的值,然后调用递归函数处理下一个骰子的值,直到处理完所有的骰子,最后计算所有骰子的值。 当N较大的之后,递归函数占用大量内存,所以可以考虑将递归转换为循环实现;

解题:

 1 void diceProbability(int *array, int n, int index, int *sumArray) {
 2         if(index==n) {
 3                 int sum=0;
 4                 for(int i=0;i<n;i++)
 5                         sum+=array[i];
 6                 sumArray[sum-n]+=1;
 7         } else {
 8                 for(int i=1;i<-6;i++) {
 9                         array[index]=i;
10                         diceProbability(array, n, index+1, sumArray);
11                 }
12         }
13 }

 

posted @ 2014-05-22 09:32  Leo C.  阅读(259)  评论(0编辑  收藏  举报