8 - 旋转数组的最小数字
2015-08-05 14:49
148 查看
题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个排好序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。
看到排序相关的查找问题,想到二分查找。
举例分析:
{1, 2, 3, 4, 5}
{5, 1, 2, 3, 4};
{4, 5, 1, 2, 3};
{3, 4, 5, 1, 2};
{2, 3, 4, 5, 1}
观察发现,除了未旋转的情况,数组时2段递增序列,且后半段小于前半段,
nums[left] >= nums[right]
选取中间元素,
如果nums[mid] <= nums[right],则mid位于后半部分的递增序列,最小元素出现在mid之前,查找[left, mid],right = mid,
如果nums[mid] >= nums[left],则mid位于前半部分的递增序列,最小元素出现在mid之后,查找[mid, right ],left = mid;
当最后左右相邻时,右指针所指即为最小元素。(后半段小)
上述过程是一个二分查找的演化版本。时间复杂度O(logn)
对于未旋转情况,第一个值即为最小;
还应考虑存在重复情况:{1,1,1,0,1} {1,0,1,1,1}
对于最左,中间,最右相等时,不能判断最小值位于哪一部分,只能逐个查找O(n),找到最小值。
看到排序相关的查找问题,想到二分查找。
举例分析:
{1, 2, 3, 4, 5}
{5, 1, 2, 3, 4};
{4, 5, 1, 2, 3};
{3, 4, 5, 1, 2};
{2, 3, 4, 5, 1}
观察发现,除了未旋转的情况,数组时2段递增序列,且后半段小于前半段,
nums[left] >= nums[right]
选取中间元素,
如果nums[mid] <= nums[right],则mid位于后半部分的递增序列,最小元素出现在mid之前,查找[left, mid],right = mid,
如果nums[mid] >= nums[left],则mid位于前半部分的递增序列,最小元素出现在mid之后,查找[mid, right ],left = mid;
当最后左右相邻时,右指针所指即为最小元素。(后半段小)
上述过程是一个二分查找的演化版本。时间复杂度O(logn)
对于未旋转情况,第一个值即为最小;
还应考虑存在重复情况:{1,1,1,0,1} {1,0,1,1,1}
对于最左,中间,最右相等时,不能判断最小值位于哪一部分,只能逐个查找O(n),找到最小值。
#include <iostream> using namespace std; int MinTravel(int* nums, int left, int right); int MinmumInRotate(int* nums, int len) { if (nums == NULL || len < 1) return 0; int left = 0, right = len-1; int mid = left; // 未旋转时,第一个就是最小元素 while (nums[left] >= nums[right]) { if (right - left == 1) { mid = right; //2指针相邻时,右边指针指向最小 break; } mid = left + (right-left)/2; if (nums[left] == nums[mid] && nums[right] == nums[mid]) { return MinTravel(nums, left, right); // 左中右三值相等,只能逐个遍历查找 } if (nums[mid] >= nums[left]) { left = mid; } else if (nums[mid] <= nums[right]) { right = mid; } } return nums[mid]; } int MinTravel(int* nums, int left, int right) { int min = nums[left]; for (int i = left+1; i <= right; i++) { if (nums[i] < min) min = nums[i]; } return min; } int main() { int nums1[] = {4,5,1,2,3}; int nums2[] = {3,4,5,1,2,3}; int nums3[] = {1,2,3,4,5,}; int nums4[] = {1,0,1,1,1,}; int nums5[] = {1}; int len = sizeof(nums1)/sizeof(nums1[0]); cout << MinmumInRotate(nums1, sizeof(nums1)/sizeof(nums1[0])) << endl; //1 cout << MinmumInRotate(nums2, sizeof(nums2)/sizeof(nums2[0])) << endl; //1 cout << MinmumInRotate(nums3, sizeof(nums3)/sizeof(nums3[0])) << endl; //1 cout << MinmumInRotate(nums4, sizeof(nums4)/sizeof(nums4[0])) << endl; //0 cout << MinmumInRotate(nums5, sizeof(nums5)/sizeof(nums5[0])) << endl; //1 }
相关文章推荐
- Android动画之translate(位移动画)
- A - Decoding Baby Boos---(2015 NEUQ_ACM summer training #1)
- 判断TextBox输入的内容是否含有字母,若含有其他内容则抛出自定义异常
- BZOJ 3781 小B的询问 序列莫队算法
- hdu 1285 拓扑排序
- crontab命令
- 抽象类,接口,类的区别以及使用
- 满足大部分时间项目开发要求
- HDU 2899 Strange fuction
- Hadoop文件放置策略及数据倾斜的balance方法
- C#中变量与对象、类型与类之间的区别
- 如何给jquery添加方法
- POJ 1330 Nearest Common Ancestors
- 论程序员的社会地位
- ARM汇编中的:比较指令--CMN / CMP / TEQ / TST
- Mac下 jdk1.6时 maven 控制台乱码
- UITableView中关于cell里的按钮被点击时如何确定是哪一个cell
- Leetcode编程题解
- oracle恢复某个时间点的数据快照
- 杭电1181变形课