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

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;
}
  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
使用二分法统计数组出现次数最多的数字可以按照以下步骤: 1. 对数组进行排序,以便使用二分法查找数字。 2. 遍历数组,用一个计数器记录每个数字出现次数。 3. 用二分法查找数组出现次数最多的数字。 4. 返回出现次数最多的数字。 下面是具体的代码实现: ```c #include <stdio.h> #include <stdlib.h> int binary_search(int arr[], int n, int x) { int left = 0, right = n - 1; while (left <= right) { int mid = (left + right) / 2; if (arr[mid] == x) { return mid; } else if (arr[mid] < x) { left = mid + 1; } else { right = mid - 1; } } return -1; } int main() { int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9}; int n = sizeof(arr) / sizeof(arr[0]); int count[100] = {0}; // 数字最大值为100 int max_count = 0, max_num; // 统计每个数字出现次数 for (int i = 0; i < n; i++) { count[arr[i]]++; if (count[arr[i]] > max_count) { max_count = count[arr[i]]; max_num = arr[i]; } } // 用二分法查找出现次数最多的数字 int idx = binary_search(arr, n, max_num); printf("数字 %d 出现次数最多,共出现 %d 次,第一次出现的位置为 %d\n", max_num, max_count, idx); return 0; } ``` 在上面的代码,我们首先创建了一个计数器数组 `count`,用来记录每个数字出现次数。然后遍历原数组 `arr`,将每个数字出现次数加一,并同时记录出现次数最多的数字和它的出现次数。最后,我们使用二分法查找出现次数最多的数字在原数组的位置,并输出相关信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值