zsh二分算法总结

本文详细介绍了二分查找算法的基本概念和应用场景,包括标准二分查找和二分查找边界,适用于有序或部分有序数组。通过左边界和右边界查找,可以解决查找特定元素、重复元素边界等多种问题。同时,文章提供了模板代码和LeetCode题目以供实践。
摘要由CSDN通过智能技术生成

        二分查找作为程序员的一项基本技能,是面试官最常使用来考察程序员基本素质的算法之一,也是解决很多查找类题目的常用方法,它可以达到O(log n)的时间复杂度。

        一般而言,当一个题目出现以下特性时,你就应该立即联想到它可能需要使用二分查找:

  1. 待查找的数组有序或者部分有序
  2. 要求时间复杂度低于O(n),或者直接要求时间复杂度为O(log n)

        下面我们介绍两种基本的二分框架:

  1. 标准的二分查找
  2. 二分查找边界

1.标准的二分查找

class BinarySearch {
    public int bs(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            int mid = left + ((right - left) >> 1);
            if (nums[mid] == target) return mid;
            else if (nums[mid] > target) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return -1;
    }
}

        这种二分算法一般是针对无重复的有序数组进行一个指定数据的查找,是最简单的二分模板。

ps 计算mid有多种方式

      mid=(left+right)/2; 这种方式在left和right非常大的时候很可能会出现溢出,不推荐使用。

      mid=left+(right-left)/2; 这种格式避免了溢出的可能性。当然我们可以使用位运算优化。

      mid=(left+right)>>1;

      mid=left+((right-left )>>1);

2.二分查找边界

        这种二分算法可以细分为查左边界和查右边界。

1、查找左边界

public class BS {
    public int bs(int[] nums,int target){
        int l=nums.length;
        int left=0,right=l-1;
        while(left<right){
            int mid=left+((right-left)>>1);
            if(nums[mid]<target){
                left=mid+1;
            }else{
                right=mid;
            }
        }
        return left;
    }
}

        这种二分算法用来查找左边界,想象一种场景,在一个有序,不连续,且可以重复的数组中,这种算法可以找到第一个大于等于target的数的位置。

         如上图,在{1,2,3,4,4,4,6,6,7,8,9}中找6。

        成功返回下标第一个6的所在下标6,即左边界。

        同样也可以查找到数组中不存在的target,这种情况会返回第一个大于target的下标。

        我们在{1,2,3,4,4,4,6,6,7,8,9}数组中查找5,返回的同样是下标6,即第一个大于5的数字。

 2、查找右边界

public class BS {
    public int bs(int[] nums,int target){
        int l=nums.length;
        int left=0,right=l-1;
        while(left<right){
            int mid=left+((right-left)>>1)+1;
            if(nums[mid]>target){
                right=mid-1;
            }else{
                left=mid;
            }
        }
        return left;
    }
}

        这种二分算法和查找左边界的不同是,他可以找到最后一个小于或者等于target的下标。

        要注意他的mid,相较于查找左边界,mid要加1;

这里我们同样用{1,2,3,4,4,4,6,6,7,8,9}进行一个查找。

         查找数组第一个小于或等于target的下标。

         返回最后一个6下标7。

        这里查找5会返回5,即最后一个小于target的数4所在的下标。

利用查找左边界和右边界的二分算法,可以解决以下四种问题。

        1、查找某个有重复数字的有序数组中的第一个target所在位置     用左边界查找返回left。

        2、查找某个有重复数字的有序数组中的最后一个target所在位置          用右边界查找返回left。

        3、查找某个有重复数字的有序数组中的最后一个小于target的数所在位置         用左边界查找返回left-1。

        4、查找某个有重复数字的有序数组中的第一个大于target的数所在位置        用右边界查找返回left+1。

        可以写leetcode 第34题练练手。

力扣

以上的二分算法都是基于题目直接给到的数组进行二分查找。除此之外还有一种二分查找的题目,是根据题目给到的数据确定最大值和最小值,然后在最大值和最小值中确定正确的值。

        leetcode 875 爱吃香蕉的珂珂力扣

就需要确定他每小时吃香蕉的数量,而这个数组的left和right就需要我们自己确定,这是一种二分变种题。

class Solution {
    public int minEatingSpeed(int[] piles, int h) {
        int left=1,right=1000000000;
        while(left<right){
            int mid=left+((right-left)>>1);
            if(getTime(piles,mid)>h){
                left=mid+1;
            }
            else{
                right=mid;
            }
        }
        return left;
    }
    public int getTime(int[] piles,int k){
        int t=0;
        for(int i=0;i<piles.length;i++){
            if(piles[i]%k==0)
                t+=piles[i]/k;
            else
                t+=piles[i]/k+1;
        }
        return t;
    }
}

                引用:二分查找、二分边界查找算法的模板代码总结 - SegmentFault 思否

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KYLO_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值