【C语言】二分法: 数字在升序数组中出现的次数

文章介绍了如何利用二分查找算法在O(logn)的时间复杂度内找到数组中特定元素首次出现和最后一次出现的位置,从而计算出该元素的重复次数。首先寻找元素的左边界,然后寻找右边界,两者相减即得重复次数。

1.题目

在这里插入图片描述

2.分析

此题通过非常简单,可以直接遍历数组,用计数器统计k出现次数即可。但是效率低,也不满足时间复杂度O(logn).

使用二分法效率更高,并且满足时间复杂度O(logn).

3.复习二分法

二分法的右起点有两种,size-1size,分别对应区间[left,right][left,right),主要用前一种,即右起点right=size-1,对应区间[left,right],循环条件(left <= right),因为是闭区间所以,端点更新均跳过原端点,即中间值不参与下一次查找,即right = middle - 1left = middle + 1.

int search(int nums[], int size, int target) //nums是数组,size是数组的大小,target是需要查找的值
{
    int left = 0;
    int right = size - 1;	// 定义了target在左闭右闭的区间内,[left, right]
    while (left <= right) {	//当left == right时,区间[left, right]仍然有效
        int middle = left + ((right - left) / 2);//等同于 (left + right) / 2,防止溢出
        if (nums[middle] > target) {
            right = middle - 1;	//target在左区间,所以[left, middle - 1]
        } else if (nums[middle] < target) {
            left = middle + 1;	//target在右区间,所以[middle + 1, right]
        } else {	//既不在左边,也不在右边,那就是找到答案了
            return middle;
        }
    }
    //没有找到目标值
    return -1;
}

4.解题

若查找目标数组[1,2,3,3,4,5]中的3,先使用二分查找分别找到首次出现3的位置,为左边界;再找到3出现结束后一位的位置,即4的位置,为右边界。两边界相减即得到重复出现的次数。

首先查找左边界
  • 因为最终查找到的位置落在循环后left的位置,所以判断条件为data[mid] < k,满足则更新左端点,不满足则更新右端点
  • 最终left>right,跳出循环,此时left即为首次出现k的位置,int first_occur=left将其记录下来
	int left=0;
    int right=dataLen-1;
    while(left<=right)
    {
        int mid=left+(right-left)/2;
        if(data[mid]<k)
        {
            left=mid+1;
        }
        else
        {
            right=mid-1;
        }
    }
    int first_occur=left;
再查找右边界
  • 进入二分查找前先重置左右端点
  • 查找右边界时循环体内判断条件为data[mid]<=k,满足即更新左端点,即左端点会跳过出现的所有k值,停在k停止出现的后一位
  • 不满足判断条件时,即更新右端点,缩减查找区间
  • 最终循环结束时的left的位置即为所需的右边界。
	left=0;
    right=dataLen-1;
    while(left<=right)
    {
        int mid=left+(right-left)/2;
        if(data[mid]<=k)
        {
            left=mid+1;
        }
        else
        {
            right=mid-1;
        }
    }
    return left-first_occur;
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值