面试题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;

 

你可能感兴趣的:(面试题)