剑指 Offer 53 - I. 在排序数组中查找数字 I(两次二分查找)

本文探讨了如何通过两次二分查找算法,提高查找目标元素并在数组中统计其出现次数的效率。个人初始解法结合了二分查找与线性搜索,而官方解法则简化为确定目标元素的精确边界。这两种方法的时间复杂度和空间复杂度对比,以及C语言实现,对于理解高效搜索算法具有重要意义。

在这里插入图片描述

个人初始解法:二分查找+线性搜索

思路:通过二分查找定位到target位置,以此为起点,向两边线性搜索target并统计次数。

int binarySearch(int *nums, int left, int right, int target)
{
    while(left <= right)
    {
        int mid = left + (right-left)/2;
        if(nums[mid] == target) return mid;
        else if(nums[mid] < target) left = mid + 1;
        else right = mid - 1;
    }
    return -1;//查找失败
}

int search(int* nums, int numsSize, int target){
    int index = binarySearch(nums, 0, numsSize-1, target);
    // 没找到,次数为0
    if( index == -1) return 0;

    // 找到了,则向两边线性搜索,统计次数
    int ret = 1;
    // 向左线性搜索
    int p = index - 1;
    while(p >= 0)
    {
        if(nums[p] != target) break;
        ret++, p--;
    }
    //向右线性搜索
    int q = index + 1;
    while(q<numsSize)
    {
        if(nums[q] != target) break;
        ret++, q++;
    }
    return ret;
}

时间复杂度分析:当数组中全是相同元素时,该算法退化为线性查找,最坏时间复杂度O(n)O(n)O(n);
空间复杂度O(1)O(1)O(1)

官方解法:两次二分查找
思路:通过两次二分查找确定target的左、右边界位置,记为left和right,则target的个数为right-left+1。

怎么做?在原来的二分法基础上进行简单修改。
当查找左边界时,如果找到目标值,此时nums[mid]==target,还不能确定mid位置就是左边界。
先将现在的target位置用temp记录下来,然后继续在其左区间进行查找是否还有target。如果找到了新的target,就更新temp的值;如果没找到,则temp记录的位置就是左边界。
同理,当查找右边界时,用temp记录target的位置,但是接下来在其右区间进行查找,找到了就更新temp的值;没找到,则temp记录的位置就是右边界。
个人C版本,比官方更易理解:
bool从C99开始可以使用。

int binarySearch(int *nums, int numsSize, int target, bool lower)
{
    int left = 0, right = numsSize - 1;
    int temp  = -1;
    while(left <= right)
    {
        int mid = left + (right-left)/2;
        if(nums[mid] == target)
        {
            temp = mid;
            if(lower) right = mid - 1;
            else left = mid + 1;
        }
        else if(nums[mid] < target) left = mid + 1;
        else right = mid - 1;
    }
    return temp;//查找失败返回-1;查找成功返回索引值
}

int search(int* nums, int numsSize, int target){
    int left = binarySearch(nums, numsSize, target, true);
    int right = binarySearch(nums, numsSize, target, false);
    return left == -1 ? 0 : right - left + 1;
}

时间复杂度O(logn)O(logn)O(logn):进行了两次二分查找
空间复杂度O(1)O(1)O(1)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值