旋转数字的最小数字
来源:互联网 发布:linux列出所有用户 编辑:程序博客网 时间:2024/04/30 12:06
旋转数字的最小数字
题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2},为{1,2,3,4,5}的一个旋转,该数组的最小值为1
这道题目最直观的解法并不难,从头到尾遍历数组一次,我们就能找出最小的元素。这种思路的时间复杂度显然是O(n)。但是这个思路没有利用输入的旋转数组的特性,肯定达不到要求。
我们注意到旋转之后的数组实际上可以划分为两个排序的子数组,且前面的子数组的元素都大于或者等于后面子数组的元素。我们还注意到最小的元素刚好是这两个子数组的分界线。在排序的数组中我们可以用二分查找法实现O(logn)的查找。这道题目也可以用二分查找的思路来寻找这个
最小的元素。
和二分查找法一样,我们用两个指针分别指向数组的第一个元素和最ihou一个元素。按照题目中旋转的规则,第一个元素应该是大于或者等于最后一个元素的。接着我们可以找到数组中间的元素。如果该中间元素位于前面的递增子数组,那么它应该大于或者等于第一个指针指向的元素。此时数组中最小的元素应该位于该中间元素的后面。我们可以把第一个指针指向该中间元素,这样可以缩小寻找的范围。移动之后的指针仍然位于前面的递增子数组之中。
同样,如果中间元素位于后面的递增子数组中,那么它应该小于或者等于第二个指针指向的元素。此时该数组中最小的元素应该位于该中间元素的前面。我们可以把第二个指针指向该中间元素,这样也可以缩小寻找的范围。移动之后的第二个指针仍然位于后面的递增子数组中。
按照前面的思路,第一个指针总是指向前面递增数组的元素,而第二个指针总是指向后面递增数组的元素。最终第一个指针将指向前面子数组的最后一个元素,而第二个指针会指向后面子数组的第一个元素。也就是说它们最终会指向两个相邻的元素,而第二个指针指向的刚好是最小的元 素。这就是循环结束的条件。
对应的代码为:
427 #include<iostream>428 using namespace std;429430 int Min(int* numbers,int length)431 {432 if(numbers == NULL || length <= 0) //判断传入数组是否存在433 throw new std::exception();434435 int index1 = 0; //指向开头436 int index2 = length - 1; //指向结尾437 int indexMid = index1; //在出现0旋转的情况下依然正确438439 while(numbers[index1] >= numbers[index2]) //循环结束条件440 {441 if(index2 - index1 == 1) //两个指针相邻442 {443 indexMid = index2; //第二个递增数组的开头就是最小的数字444 break;445 }446447 indexMid = (index1 + index2) / 2;448 if(numbers[indexMid] >= numbers[index1]) //中间数字在第一个递增数组中449 index1 = indexMid;450 else if(numbers[indexMid] < numbers[index2]) //中间数字在第二个递增数组中451 index2 = indexMid;452 }453 return numbers[indexMid];454 }455456 int main()457 {458 int numbers[5] = {3,4,5,1,2};459 int min = Min(numbers,5);460 cout<<"min = "<<min<<endl;461 return 0;462 }但是上述代码依然存在着缺陷,就是当index1和index2下标所对应的数相同时,并且它们所对应的中间数字也相同时。数组{1,0,1,1,1}和{1,1,1,0,1}可以看成是递增数组的情况。因为第一个指针和第二个指针以及中间指针所指向的数字都相同的情况下,上面的方法就不再适合,所以只有采用顺序查找的方法才行。
472 #include<iostream>473 using namespace std;474475 int MinInorder(int* numbers,int index1,int index2);476477 int Min(int numbers[],int length)478 {479 if(numbers == NULL || length <= 0)480 throw new std::exception();481482 int index1 = 0;483 int index2 = length - 1;484 int indexMid = index1;485 while(numbers[index1] >= numbers[index2])486 {487 if(index2 - index1 == 1)488 {489 indexMid = index2;490 break;491 }492493 indexMid = (index1 + index2) / 2;494495 //如果下标index1和index2和indexMid所指向的下标对应的数字都相等496 //则只能顺序查找497 if(numbers[index1] == numbers[index2] && numbers[indexMid] == numbers[index1])498 return MinInorder(numbers,index1,index2);499500 if(numbers[indexMid] >= numbers[index1])501 index1 = indexMid;502 else if(numbers[indexMid] <= numbers[index2])503 index2 = indexMid;504505 }506 return numbers[indexMid];507 }
509 //顺序查找510 int MinInorder(int* numbers,int index1,int index2)511 {512 int result = numbers[index1];513 for(int i = index1 + 1; i <= index2; ++i)514 {515 if(result > numbers[i])516 result = numbers[i];517 }518 return result;519 }520521 int main()522 {523 int numbers[] = {1,0,1,1,1};524 int min = Min(numbers,sizeof(numbers)/sizeof(numbers[0]));525 cout<<"Min = "<<min<<endl;526 return 0;527 }
- 旋转数字的最小数字
- 【剑指offer】旋转数字的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 旋转数组的最小数字
- 栈的压入、弹出序列
- java 获取指定目录下所有文件的名称
- java分页实现
- 算法题目-二叉树的深度
- mybatis 动态sql和参数
- 旋转数字的最小数字
- 【社会我毅哥,人好话不多】
- 洛谷Oj-最大子段和-动态规划
- クラウドアプリのベスト設計とは? タイプが異なる「PaaS」組み合わせ事例
- hdoj1086 You can Solve a Geometry Problem too(数学几何题)
- QT中的信号和槽机制
- 文本和字体
- 缤特力m165连接ThinkPad-X250
- 【机器学习】特征工程概述