• 《Cracking the Coding Interview》——第11章:排序和搜索——题目3


    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
    ", 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
    ", rotatedBinarySearch(v, n, i));
     98     }
     99     
    100     return 0;
    101 }
  • 相关阅读:
    编程基础——c 选择结构程序设计个人总结实例
    编程基础C——常量,变量,运算符个人总结
    编程基础C——格式化输入函数scanf的应用
    编程基础C——基本数据类型个人总结:
    django-base
    django-mvc
    OSI七层与TCP/IP五层网络架构详解
    tcp/ip三次握手及四次挥手
    网页浏览过程
    http协议
  • 原文地址:https://www.cnblogs.com/zhuli19901106/p/3616768.html
Copyright © 2020-2023  润新知