二分查找数组中指定数的个数 二分进阶

使用二分查找统计数组中与目标数相同的数的个数

该算法思想是基于二分查找数基础上进行改进,目的是统计数组中有多少个数与目标数相等。

注:

  • 当直接使用for循环去遍历数组,每次遍历都比对一次,时间复杂度将会是O(n)
  • 如果使用一次二分查找,首先找到一个与目标数相等数的下标后,使用while以这个下标为中心,向左或向右去比较。如果相同的数只有2个的话,那么向左向右搜寻一次就可以得出结果,但如果一个数组中的所有数都相同,那么还是需要比对n次,按这个思想查找的时间复杂度也是O(n)。
  • 这里我采用的思想是 先使用一次二分查找找到这个数的左边界,然后在找到左边界的情况下再使用一次二分查找找到数的右边界,右边界与左边界之差就是数组中这个数的个数。 该算法的时间复杂度和普通二分算法的时间复杂度是一样的。都是O(lgN)。
import java.util.Scanner;

public class BinarySearch_findSameNum {
    public static void main(String[] args) {
        int arr[] = {1, 1, 5, 5, 5, 8, 8, 9, 10, 15, 15};        //定义一个有序的二分数组
        int target = new Scanner(System.in).nextInt();           //输入查找数
        left(arr, 0, arr.length, target);                   //第一次二分 查找左边界
    }

    //查找左边界的函数left
    private static void left(int[] arr, int low, int high, int target) {
        while (low <= high) {    //定义while循环的结束条件  当下标low>high时跳出while循环
            int middle = (low + high) / 2;//注意 这里的middle计算方式会有很大的影响  我还是采用的相加取中值
            if (arr[middle] >= target) {
                //这里要找左边界,因此当arr[middle]大于或者等于target时,则证明左边界在low~middle-1之间
                //注意 二分查找数时,当arr[middle]==target时就找到要查找的结果了,但这里还不能结束。
                // 因为目标数在数组中有2个或2个以上时,找到的这个索引很大可能不是最左边的,还需要进行循环,直到找到左边界
                high = middle - 1;  //改变上标,继续遍历
            } else {
                low = middle + 1;
            }
        }//当不断在while循环中遍历时,low的值一定会大于high

        //判断最后一次循环结束的下标low对应的数组值是否与target相等
        if (arr[low] == target && low < arr.length) {
            System.out.println("left search success:" + low);

            //相等,则左边界存在。先获得目标数的左边界low
            int right = right(arr, low+1, arr.length - 1, target);  //在调用寻找有边界的函数right
            //注意  这里传给右边界函数的下标和上标与找左边界时有所变化  因为我们已经找到了左边界,所有可以直接将数组左边界右边的数传给函数
            //下标可以取low+1
            //这里的上标为arr.length - 1  数组的长度减1  !!!!这个-1非常重要,对应着middle的计算方式。
            //因为我是直接上下标相加除2的 就拿本题为列。找到查找右边界的函数。如要查找15  当找到左边界是9时 再将上标11传过去 middle计算得10
            // arr[10]=15确实等于target,这时会将下标low加1。low=11后就直接会数组越界  所以将arr.length-1传过去 上标为10,就不会出现下标+1后越界
            System.out.println("数组中与" + target + "相同的有:" + (right - low + 1) + "个");
        } else {
            System.out.println("error");
        }
    }

    //查找右边界的函数right
    private static int right(int[] arr, int low, int high, int target) {
        //查找右边界时就很简单了,思想与查找左边界一致
        while (low <= high) {
            int middle = (high + low) / 2;
            if (arr[middle] <= target) {
                //如果arr[middle] <= target 就一直改变下标的值,直到low>high跳出while循环
                low = middle + 1;
            } else {
                high = middle - 1;
            }
        }
        if (arr[high] == target && high < arr.length) {
            System.out.println("right search find:" + high);
            return high;  //返回右边界的索引
        } 
    }
}

闲来无聊写的,若有错误的地方还请各位大佬指正

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值