剑指offer面试题8:旋转数组的最小数字

来源:互联网 发布:p2p网络借贷融资过程 编辑:程序博客网 时间:2024/05/30 20:09

题目描述:

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转。输出旋转数组的最小元素。例如数组{3,4,5,1,2}是{1,2,3,4,5}的一个旋转,该数组的最小元素为1。

思路分析:

1、旋转数组的特点:

1)旋转数组可以划分为两个排序的递增子数组,且前面的子数组的元素都大于或者等于后面子数组的元素;

2)最小的元素刚好是两个子数组的分界线。

2、分析:

这个题目最直观的方法是从头到尾遍历数组一次,时间复杂度为O(n),但是这个思路没有利用旋转数组的特性。考虑旋转数组的两个特性,我们可以思考一下排好序的数组的查找算法,可以使用二分查找。

假设数组为a[],用两个指针low, high分别指向数组的第一个元素和最后一个元素,mid指向数组的中间元素。

1)如果 a[mid] > a[low],数组中最小元素应位于 a[mid] 的后面,把low指针指向mid处,缩小寻找范围;

2)如果a[mid] < a[high],数组中最小元素应位于 a[mid]的前面,把high指针指向mid处,缩小寻找范围;

3)最终low指针将指向前面子数组的最后一个元素,high指针将指向后面子数组的第一个元素。此时low和high相邻,high指针刚好指向最小元素。

特例:

1)如果把排序数组前面0个元素搬到最后面,即排序数组本身仍然是数组的一个旋转,此时,数组中第一个元素就是最小元素,可以直接返回。所以代码中一开始把indexMid初始化为index1。

2)数组{1,0,1,1,1}和{1,1,1,0,1}都是{0,1,1,1,1}的旋转数组,它们的中间元素都为1,此时无法判断中间元素是位于前面的子数组还是后面的子数组,只能使用顺序查找。

时间复杂度:

最坏O(n),平均O(log2 n)

代码及测试:

#include <iostream>#include <assert.h>using namespace std;int MinUseOrder(int num[], int low, int high);//求旋转数组的最小数字int Min(int * num, int n) {if(num == NULL || n <= 0) {cout << "Invalid parameters" << endl;return -1;}int low = 0, high = n - 1;int mid = low;//mid初始化为0,确保了当数组旋转了0个元素时算法的正确性while(num[low] >= num[high]) {if(high - low == 1) {mid = high;break;}mid = (low + high) / 2;if(num[low] == num[mid] && num[mid] == num[high])return MinUseOrder(num, low, high); //使用顺序查找if(num[mid] >= num[low]){low = mid;}else if(num[mid] <= num[high]){high = mid;}}return num[mid];}int MinUseOrder(int num[], int low, int high) {int res = num[low];for(int i = low + 1; i < high; i ++) {if(res > num[i])res = num[i];}return res;}void test1() { int num[5] = { 3, 4, 5, 1, 2};int min = Min(num,5);cout << min << endl;}void test2() {int num[8] = {3, 3, 4, 5, 1, 1, 2, 2};int min = Min(num, 8);cout << min << endl;}void test3() { //边界值测试:输入为升序数组int num[5] = {1, 2, 3, 4, 5};int min = Min(num, 5);cout << min << endl;}void test4() { //边界值测试:输入为只包含一个数字的数组int num[1] = {1};int min = Min(num, 1);cout << min << endl;}void test5() {//边界值测试:输入为只包含一个数字的数组int * num = NULL;int min = Min(num, 1);cout << min << endl;}int main() {test1();test2();test3();test4();test5();return 0;}


原创粉丝点击