旋转数组的最小数字

面试题11:旋转数组的最小数字

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

OC形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
...
NSLog(@"%d",[self minWithArray:@[@3,@4,@5,@1,@2] lenght:5]);
NSLog(@"%d",[self minWithArray:@[@1,@0,@1,@1,@1] lenght:5]);
...

- (int)minWithArray:(NSArray *)numbers lenght:(int)length {
if (numbers == nil || length <= 0) {
return -1;
}
int index1 = 0;
int index2 = length - 1;
int indexMid = index1;//如果把排序数组的前面0个元素搬到最后面,即排序数组的本身。此时第一个数字就是最小的数字。直接返回该值即可
while ([numbers[index1] intValue] >= [numbers[index2] intValue]) {//按照旋转规则,数组开头的元素必会大于等于末尾元素
if (index2 - index1 == 1) {//如果两者相邻,则跳出循环
indexMid = index2;//把区间末尾的中间值设置为中间值,并输出
break;
}

indexMid = (index1 + index2) / 2;//取区间首尾指针的中间值
//如果下标为index1、index2和indexMid指向的三个数字相等,则只能顺序查找
if ([numbers[index1] intValue] == [numbers[index2] intValue] && [numbers[indexMid] intValue] == [numbers[index1] intValue]) {
return [self minInOrderWithArray:numbers index1:index1 index2:index2];
}

//如果区间中间的值大于等于区间开头的值,则把区间开头设置在中间值。进一步缩小范围
if ([numbers[indexMid] intValue] >= [numbers[index1] intValue]) {
index1 = indexMid;
}
//如果区间中间值小于等于区间末尾的值,则把区间末尾设置在中间值,进一步缩小范围
else if ([numbers[indexMid] intValue] <= [numbers[index2] intValue]) {
index2 = indexMid;
}
}
return [numbers[indexMid] intValue];
}
- (int)minInOrderWithArray:(NSArray *)numbers index1:(int)index1 index2:(int)index2 {
int result = [numbers[index1] intValue];
for (int i = index1 + 1; i <= index2; ++i) {
if (result > [numbers[i] intValue]) {
result = [numbers[i] intValue];
}
}
return result;
}

思路

在排序的数组中我们可以用二分查找法实现O(logn)的查找。