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

题目链接:http://ac.jobdu.com/problem.php?pid=1386

思路:采用二分查找的思想。

1、我们找到数组的中间元素

2、如果中间元素大于或等于最左端的元素,中间元素就位于前面的递增子序列,最小元素位于中间元素后面,修改最左端元素的位置;

3、如果中间元素小于或等于最右端的元素,中间元素就位于后面的递增子序列,最小元素位于中间元素前面,修改最右端元素的位置。

重复上面的步骤,可知最后最左端的元素为前面递增子序列的最后一个元素,最右端的元素为后面递增子序列的第一个元素。

考虑特殊情况:最左端元素=中间元素=最右端元素,此时是无法判断最小元素与中间元素的相对位置的。

对于特殊情况,我们要遍历一遍序列,当然只需遍历到后面递增子序列。

还有一种情况,开始最左端的元素就小于最右端的元素(没有进过旋转),不知道要不要考虑!!!

其实要考虑也容易,提前预判,初始值设定为0等都可以很好解决。

code:

 1 #include <cstdio>
 2 using namespace std;
 3 const int MAXN = 1000005;
 4 int a[MAXN];
 5 int binarySearch(int n)
 6 {
 7     int lhs = 0;
 8     int rhs = n - 1;
 9     int mid = 0;    // 当数组没有经过旋转,最小元素为最左端元素
10     while (a[lhs] >= a[rhs])
11     {
12         if (lhs + 1 == rhs)    // 找到了前面递增子序列的最后一个元素,和后面递增子序列的第一个元素
13         {
14             mid = rhs;
15             break;
16         }
17 
18         mid = lhs + ((rhs - lhs) >> 1);    // 获得中间元素的位置
19     
20         if (a[mid] == a[lhs] && a[mid] == a[rhs])    // 特判
21         {
22             bool flag = false;    // 是否找到后面递增子序列的第一个元素
23             int min = a[lhs];
24             for (int i = lhs + 1; i <= rhs; ++i)
25             {
26                 if (min > a[i])
27                 {
28                     min = a[i];
29                     mid = i;
30                     flag = true;
31                 }
32                 if (flag) break;
33             }
34             break;
35         }
36 
37         if (a[mid] >= a[lhs]) lhs = mid;    // 修改最左端元素的位置,逼近前面递增子序列的最后一个元素
38         else  rhs = mid;    // 修改最右端元素的位置,逼近后面子序列的第一个元素
39     }
40     return mid;
41 }
42 
43 int main()
44 {
45     int n;
46     while (scanf("%d", &n) != EOF)
47     {
48         for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
49         int k = binarySearch(n);    // 找到最小元素的位置
50         printf("%d\n", a[k]);
51     }
52     return 0;

 

posted @ 2015-04-21 09:32  jasaiq  阅读(209)  评论(0编辑  收藏  举报