出题:将一个数组最开始的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 }