更多剑指offer面试习题请点击: 《剑指offer》(第二版)题集目录索引
题目:把一个数组最开始的若干元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组{ 3, 4, 5, 1, 2 }为{ 1, 2, 3, 4, 5 }的一个旋转,该数组的最小值为1。
解题思路:
这题很明显是要利用旋转数组的特性,一个递增排序的数组旋转后可以把它分成两部分,这两部分又可以看作两个递增排序的数组,并且前面的子数组的元素一定会大于等于后面的子数组的元素。这里我们可以利用二分查找的思想。
用start和end表示首尾元素下标,mid表示中间元素下标。
①如果中间元素大于等于首元素,那么中间元素一定在前面那个子数组里面,那就意味着最小的元素一定在mid的后面,所以此时我们把 mid 赋值给start;
②如果中间元素小于等于尾元素,那么中间元素一定在后面那个子数组里面,那就意味着最小的元素一定在mid前面或者就是mid,此时就把mid赋值给end;
③如果start和end相邻了,那此时下标end所指向的元素就是最小元素。
注意: 这里一种特殊情况,数组{ 1, 0, 1, 1, 1 }的numbers[start] = numbers[mid] = numbers[end] = 1,此时程序判断numbers[mid] >= numbers[start] 成立,就会把mid赋值给start,最后程序返回的最终结果是1而不是0,所以如果程序遇到start、mid、end三个位置的值都相等情况下,只能采用顺序查找。
< code >
int Min(int* numbers, int length)
{
if (NULL == numbers || length <= 0)
return;
int start = 0;
int end = length - 1;
int mid = start;
//如果输入的数组是{1, 2, 3, 4, 5}那就直接返回numbers[start]。
while (numbers[start] >= numbers[end])
{
if (end - start == 1) //此时最小的数就是numbers[end]
{
mid = end;
break;
}
mid = start + ((end - start) >> 1);
/*start、mid、end三个位置的数值相等,只能采用顺序查找*/
if (numbers[start] == numbers[end]
&& numbers[mid] == numbers[start])
{
int ret = numbers[start];
int i = start + 1;
while (i <= end)
{
if (ret > numbers[i])
{
ret = numbers[i];
}
i++;
}
return ret;
}
/*缩小范围*/
if (numbers[mid] >= numbers[start])
start = mid;
else if (numbers[mid] <= numbers[end])
end = mid;
}
return numbers[mid];
}