【剑指offer】题目38 数字在排序数组中出现的次数

思路:

应该是用二分查找分别找到该数字第一次和最后一次出现的位置,相减即可。O(logn)

int findLeft(int a[], int n, int num)
{
    int l = 0, r = n - 1;
    while(l <= r)
    {
        int m = l + (r - l) / 2;
        if(a[m] == num) //与普通二分查找的区别在等于这里
        {
            if(m == 0 || a[m - 1] != num) //如果这是第一个数字或者它前面的数字不是num那么这个位置就是第一个num出现的位置
                return m;
            else   //否则num在左半部分
                r = m - 1;
        }
        else if(a[m] < num)
        {
            l = m + 1;
        }
        else
        {
            r = m - 1;
        }
    }
    return -1; //没找到
}

int findRight(int a[], int n, int num)
{
    int l = 0, r = n - 1;
    while(l <= r)
    {
        int m = l + (r - l) / 2;
        if(a[m] == num)
        {
            if(m == n - 1 || a[m + 1] != num) ////如果这是最后一个数字或者它后面的数字不是num那么这个位置就是最后一个num出现的位置
                return m;
            else //否则 最后一个num在右半部分
                l = m + 1;
        }
        else if(a[m] < num)
        {
            l = m + 1;
        }
        else
        {
            r = m - 1;
        }
    }
    return -1; //没找到
}

int times(int a[], int n, int num)
{
    if(a == NULL) return 0;
    int l = findLeft(a, n, num);
    int r = findRight(a, n, num);
    return (l == -1 || r == -1) ? 0 : r - l + 1;
}

int main()
{
    int a[10] = {1,2,3,3,3,3,4,5};
    int ans = times(a, 8, 5);

    return 0;
}

最开始写的是用普通二分查找找到一个指定数字再左右扩展,O(N)不好。

//O(N)解法 不好
int appearTimes(int a[], int n, int num)
{
    int l = 0;
    int r = n - 1;
    int pos = -1; //找到的num的下标
    while(l <= r) //二分查找 找到一个num
    {
        int m = l + (r - l) / 2;
        if(a[m] == num)
        {
            pos = m;
            break;
        }
        else if(a[m] < num)
            l = m + 1;
        else
            r = m - 1;
    }
    if(pos == -1) //没有该数字
        return 0;
    
    l = r = pos;
    while(l >= 0 && a[l] == num) //找左边界
        l--;
    while(r < n && a[r] == num) //找右边界
        r++;

    return r - l - 1;
}
原文地址:https://www.cnblogs.com/dplearning/p/4631308.html