剑指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 }

 

 posted on 2013-11-22 22:15  zhuli19901106  阅读(327)  评论(0编辑  收藏  举报