2014-03-21 20:55

题目:给定一个旋转过的升序排序好的数组,不知道旋转了几位。找出其中是否存在某一个值。

解法1:如果数组的元素都不重复,那么我的解法是先找出旋转的偏移量,然后进行带偏移量的二分搜索。两个过程都是对数级的。

代码:

 1 // 11.3 Given a sorted array rotated by a few positions, find out if a value exists in the array.
 2 // Suppose all elements in the array are unique.
 3 #include <algorithm>
 4 #include <vector>
 5 #include <cstdio>
 6 using namespace std;
 7 
 8 int rotatedBinarySearch(vector<int> &v, int n, int key)
 9 {
10     int offset;
11     
12     if ((int)v.size() < n || n <= 0) {
13         return -1;
14     }
15     
16     int ll, rr, mm;
17 
18     if (v[0] < v[n - 1]) {
19         offset = 0;
20     } else {
21         ll = 0;
22         rr = n - 1;
23         while (rr - ll > 1) {
24             mm = (ll + rr) / 2;
25             if (v[mm] > v[ll]) {
26                 ll = mm;
27             } else {
28                 rr = mm;
29             }
30         }
31         offset = rr;
32     }
33     
34     ll = 0;
35     rr = n - 1;
36     while (ll <= rr) {
37         mm = (ll + rr) / 2;
38         if (key < v[(mm + offset) % n]) {
39             rr = mm - 1;
40         } else if (key > v[(mm + offset) % n]) {
41             ll = mm + 1;
42         } else {
43             return (mm + offset) % n;
44         }
45     }
46     return -1;
47 }
48 
49 int main()
50 {
51     int n;
52     int i;
53     vector<int> v;
54     
55     while (scanf("%d", &n) == 1 && n > 0) {
56         v.resize(n);
57         for (i = 0; i < n; ++i) {
58             scanf("%d", &v[i]);
59         }
60         scanf("%d", &i);
61         printf("%d\n", rotatedBinarySearch(v, n, i));
62     }
63     
64     return 0;
65 }

解法2:如果数组的元素可能存在重复,那么我的思路仍然是先二分查找找出偏移量,然后执行带偏移量的二分搜索。不过,在找偏移量的过程中可能会出现无法决定向左还是向右的情况,比如这两个例子{1, 3, 1, 1, 1}{1, 1, 1, 3, 1},在第一次二分时,左中右的元素都是‘1’,无法确定应该往哪边走。这时就得扫描整段,{1, 1, 1}全部是同一元素,{1, 3, 1}存在不同元素,所以应该选择{1, 3, 1}进行二分,因为在首尾相同的情况下,中间如果有不同元素的话,表示旋转的偏移量应该会落在这个区间里。找到偏移量以后,之后的查找就是严格二分的了。

代码:

  1 // 11.3 Given a sorted array rotated by a few positions, find out if a value exists in the array.
  2 // Suppose the array may contain duplicates, what's it gonna be then?
  3 #include <algorithm>
  4 #include <vector>
  5 #include <cstdio>
  6 using namespace std;
  7 
  8 int rotatedBinarySearch(vector<int> &v, int n, int key)
  9 {
 10     int offset;
 11     
 12     if ((int)v.size() < n || n <= 0) {
 13         return -1;
 14     }
 15     
 16     int ll, rr, mm;
 17     int i;
 18     
 19     ll = 0;
 20     rr = n - 1;
 21     while (rr - ll > 1 && v[ll] == v[rr]) {
 22         mm = (ll + rr) / 2;
 23         if (v[mm] > v[ll]) {
 24             ll = mm;
 25             break;
 26         } else if (v[mm] < v[ll]) {
 27             rr = mm;
 28             break;
 29         } else {
 30             for (i = ll; i < mm - 1; ++i) {
 31                 if (v[i] != v[i + 1]) {
 32                     break;
 33                 }
 34             }
 35             if (i < mm - 1) {
 36                 rr = mm;
 37                 break;
 38             }
 39             for (i = mm; i < rr - 1; ++i) {
 40                 if (v[i] != v[i + 1]) {
 41                     break;
 42                 }
 43             }
 44             if (i < rr - 1) {
 45                 break;
 46             }
 47             
 48             // if all elements are the same, it ends here
 49             return (v[0] == key) ? 0 : -1;
 50         }
 51     }
 52     
 53     if (v[ll] < v[rr]) {
 54         offset = 0;
 55     } else {
 56         // here it is guaranteed v[ll] != v[rr]
 57         while (rr - ll > 1) {
 58             mm = (ll + rr) / 2;
 59             if (v[mm] >= v[ll]) {
 60                 ll = mm;
 61             } else {
 62                 rr = mm;
 63             }
 64         }
 65         offset = rr;
 66     }
 67     
 68     // the binary search part remains the same, difference lies in how we find the 'offset'.
 69     ll = 0;
 70     rr = n - 1;
 71     while (ll <= rr) {
 72         mm = (ll + rr) / 2;
 73         if (key < v[(mm + offset) % n]) {
 74             rr = mm - 1;
 75         } else if (key > v[(mm + offset) % n]) {
 76             ll = mm + 1;
 77         } else {
 78             return (mm + offset) % n;
 79         }
 80     }
 81 
 82     return -1;
 83 }
 84 
 85 int main()
 86 {
 87     int n;
 88     int i;
 89     vector<int> v;
 90     
 91     while (scanf("%d", &n) == 1 && n > 0) {
 92         v.resize(n);
 93         for (i = 0; i < n; ++i) {
 94             scanf("%d", &v[i]);
 95         }
 96         scanf("%d", &i);
 97         printf("%d\n", rotatedBinarySearch(v, n, i));
 98     }
 99     
100     return 0;
101 }

 

 posted on 2014-03-21 21:26  zhuli19901106  阅读(223)  评论(0编辑  收藏  举报