剑指Offer - 九度1349 - 数字在排序数组中出现的次数

剑指Offer - 九度1349 - 数字在排序数组中出现的次数
2013-11-23 00:47
题目描述:
统计一个数字在排序数组中出现的次数。
输入:

每个测试案例包括两行:

第一行有1个整数n,表示数组的大小。1<=n <= 10^6。

第二行有n个整数,表示数组元素,每个元素均为int。

第三行有1个整数m,表示接下来有m次查询。1<=m<=10^3。

下面有m行,每行有一个整数k,表示要查询的数。 

输出:
对应每个测试案例,有m行输出,每行1整数,表示数组中该数字出现的次数。
样例输入:
8

1 2 3 3 3 3 4 5

1

3

样例输出:
4
题意分析:
  题目要求在一个数组中找出一个数出现的次数,
    第一种想法,当然是一次性全部数一遍,用map之类的结构保存统计结果,之后每次就可以log n复杂度查询了。时间复杂度为O(n) + m * O(log k),k是数组中不同元素的个数,空间复杂度O(k)。问题是——数组已经排序,这个特性没用到。
    第二种想法,因为数组有序,所以每次都用二分查找找出一个数的左界和右界,然后right - left + 1即为结果。对于不存在的元素,二分当然返回-1之类的NOT_FOUND值,统计结果则为0。时间复杂度为m * O(log n),空间复杂度O(1)。
  观察题目数据范围,数组长度n最大可以到10^6,查询次数m最大才10^3,如果采取上面方法一,O(n)则占了大头,不划算。所以选方法二。
  其中bsearch_left求出target在数组a[]中的左下标,bsearch_right为右下标。这俩函数写法要小心,检查好数组指针,数据范围,左右端后才能开始二分查找。
  查找到左右下标后,rr - ll + 1即为结果;查不到左右下标的话,结果为0。
  1 // 652724    zhuli19901106    1349    Accepted    点击此处查看所有case的执行结果    4932KB    1913B    720MS

  2 // 201311171831

  3 #include <cstdio>

  4 using namespace std;

  5 

  6 int bsearch_left(const int a[], int n, int target)

  7 {

  8     int ll, rr, mm;

  9     

 10     if(a == NULL || n <= 0){

 11         return -1;

 12     }

 13     

 14     if(target < a[0] || target > a[n - 1]){

 15         return -1;

 16     }

 17     

 18     // guarantee that a[left] < target && a[right] >= target

 19     if(target == a[0]){

 20         return 0;

 21     }

 22     

 23     ll = 0;

 24     rr = n - 1;

 25     while(rr - ll > 1){

 26         mm = (ll + rr) / 2;

 27         if(target > a[mm]){

 28             ll = mm;

 29         }else{

 30             rr = mm;

 31         }

 32     }

 33     

 34     if(a[rr] == target){

 35         return rr;

 36     }else{

 37         return -1;

 38     }

 39 }

 40 

 41 int bsearch_right(const int a[], int n, int target)

 42 {

 43     int ll, rr, mm;

 44     

 45     if(a == NULL || n <= 0){

 46         return -1;

 47     }

 48     

 49     if(target < a[0] || target > a[n - 1]){

 50         return -1;

 51     }

 52     

 53     // guarantee that a[left] <= target && a[right] > target

 54     if(target == a[n - 1]){

 55         return n - 1;

 56     }

 57     

 58     ll = 0;

 59     rr = n - 1;

 60     while(rr - ll > 1){

 61         mm = (ll + rr) / 2;

 62         if(target >= a[mm]){

 63             ll = mm;

 64         }else{

 65             rr = mm;

 66         }

 67     }

 68     

 69     if(a[ll] == target){

 70         return ll;

 71     }else{

 72         return -1;

 73     }

 74 }

 75 

 76 int main()

 77 {

 78     int *a = NULL;

 79     int i, n, m;

 80     int target;

 81     int ll, rr;

 82     

 83     while(scanf("%d", &n) == 1){

 84         if(n <= 0){

 85             continue;

 86         }

 87         a = new int[n];

 88         for(i = 0; i < n; ++i){

 89             scanf("%d", &a[i]);

 90         }

 91         scanf("%d", &m);

 92         for(i = 0; i < m; ++i){

 93             scanf("%d", &target);

 94             ll = bsearch_left(a, n, target);

 95             if(ll < 0){

 96                 printf("0\n");

 97                 continue;

 98             }

 99             rr = bsearch_right(a, n, target);

100             if(rr < 0){

101                 printf("0\n");

102                 continue;

103             }

104             if(rr >= ll){

105                 printf("%d\n", rr - ll + 1);

106             }else{

107                 printf("0\n");

108             }

109         }

110         delete[] a;

111         a = NULL;

112     }

113     

114     return 0;

115 }

 

你可能感兴趣的:(排序)