Leetcode之二分查找法

针对的是一个有序数组进行查找的情况,用二分查找法进行数据查找是一个不错的选择,时间复杂度O(log(n)),定义start和end,不断改变start和end的值来缩小查找的区域

普通二分查找法

  • 给出一个有序数组,在数组中查找数值为a的值
  • 首先定义start和end分别代表数组中查找范围的最小值和最大值的下标,start=0,end=array.length;然后找到中间值array[(start+end)/2]与a比较,若a小则表示找大了,前移缩小最大值,end=(start+end)/2-1;否则证明找小了,start前移,start=(start+end)/2+1,每操作一次缩小1/2的范围,时间复杂度O(log(n)).
  • 在这里插入图片描述在这里插入图片描述在这里插入图片描述
  • 实现
public int search(int[] array ,int a){
        int start=0;
        int end =array.length-1;
        int temp;
        while(start<end){
            temp=(start+end)/2;
            if(array[temp]>a){
                end=temp-1;
            }else if(array[temp]<a){
                start=temp+1;
            }else {
                return temp;
            }
        }
        //start==end跳出时判断是否找到
        if(array[start]!=a){
            System.out.println("没有找到!");
            return -1;
        }
        return start;
    }

进阶二分查找法

  • 题目:给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。你可以假设 nums1 和 nums2 不会同时为空。
  • 首先分析,时间复杂度为O(log(m+n)),而且是两个有序数组,无疑是用二分查找法解决。
  • 具体思路
    因为是找中位数,可以知道中位数的特点是左右两边的元素个数相等,则先将两个有序数组分为分为左右两部分,left和right,只要left和right的个数相等并且maxleft<=minright,则可以找出中位数为maxleft(m+n为奇数)或 (maxleft+minright)/2(m+n为偶数)
    在这里插入图片描述
    以第一个数组为基准,进行二分查找 ,halflen=(m+n+1)/2,j=halflen-i;直到array1[i-1]<=array2[j] && array2[j-1]<=array1[i]时,说明找到的i,j刚好符合条件
class Solution {
    public double findMedianSortedArrays(int[] A, int[] B) {
        int m = A.length;
        int n = B.length;
        //方便操作假定m<=n,否则A和B互换
        if (m > n) { // to ensure m<=n
            int[] temp = A; A = B; B = temp;
            int tmp = m; m = n; n = tmp;
        }
        //定义iMax=m而不是m-1是为了保证iMin+iMax>=0
        int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
        while (iMin <= iMax) {
            //保证i+j=m+n-i-j(偶数)或者i+j=m+n+1-i-j(奇数)
            int i = (iMin + iMax) / 2;
            int j = halfLen - i;
            //二分法查找
            //i<iMax为了让iMin=i+1不会越界
            if (i < iMax && B[j-1] > A[i]){
                iMin = i + 1; // i is too small
            }
            else if (i > iMin && A[i-1] > B[j]) {
                iMax = i - 1; // i is too big
            }
            else { // i is perfect
                //找到left中最大值
                int maxLeft = 0;
                //i==0时i-1越界,maxLeft=B[j-1]
                //同时解决了A为空的情况
                if (i == 0) { maxLeft = B[j-1]; }
                //j==0时,j-1越界
                else if (j == 0) { maxLeft = A[i-1]; }
                //其他情况,maxLeft取A[i-1],A[j-1]中的最大值
                else { maxLeft = Math.max(A[i-1], B[j-1]); }
                //如果m+n为奇数,则只有一个中间数为中位数
                if ( (m + n) % 2 == 1 ) { return maxLeft; }

                int minRight = 0;
                //i==m时,i越界
                if (i == m) { minRight = B[j]; }
                //j越界
                else if (j == n) { minRight = A[i]; }
                else { minRight = Math.min(B[j], A[i]); }
                return (maxLeft + minRight) / 2.0;
            }
        }
        return 0.0;
    }
}

总结下来就三点:1.分界线,即i,j,halflen的取值,取i,j左边的为left,i,j自身以及右边放入right,根据自己的分界情况数组角标也不同。2.对数组为空的处理,因为要考虑到数组可能为空,iMax取m,才能保证iMax+iMin大于0,因为-1/2=0,0/2=0,1/2=0结果的i都为0,不能具体判断i==0是由什么导致的,主要是方便区分数组为空的情况。3.越界问题,i=0时i-1越界,i=m时i越界,j同理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值