您的位置:首页 > 职场人生

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

2017-08-22 10:55 531 查看

题目描述:

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转。输出旋转数组的最小元素。例如数组{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;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息