leetcode二分查找

用排除法解二分查找:
在这里插入图片描述

1、循环条件:l<r
2、用排除法,考虑什么情况下mid一定不满足条件,然后考虑r或者l的取值,判断依据是左边区间有没有可能出现目标元素,右边条件有没有可能出现目标元素。
3、mid=l+(r-l)/2,但是出现left=mid的情况,为了避免死循话,要写成mid=l+(r-l+1)/2
4、如果数组中不一定会出现目标元素,还应该再判断一次。

在这里插入图片描述

1、找一个准确值

  • 循环条件:l<=r
  • 缩减搜索空间:l=mid+1,r=mid-1

2、找一个数第一次出现的位置,最后一次出现的位置

第一次出现的位置:12223

  • 循环条件:l<r。为了防止出现死循环。
  • 缩减搜索空间:l=mid+1,r=mid。找到了2,但是并不知道它是不是最左边的元素,所以要保留这个数r=mid,并且把搜索区间向左移动。如果nums[mid]<k,那么就说明一定在右边的区间,所以l=mid+1。

最后一次出现的位置:12223

  • 循环条件:l<r。为了防止出现死循环。
  • 缩减搜索空间:l=mid,r=mid-1。找到了2,但是并不知道它是不是最右边的元素,所以要保留这个数l=mid,并且把搜索区间向右移动。如果nums[mid]>k,那么就说明一定在左边的区间,所以r=mid-1。
  • mid=l+(r-l+1)/2,为了让还剩最后两个数的时候,mid不等于l,不会进入死循环。

3、找一个最接近2的数

  • 循环条件:l<r-1
  • 缩减搜索空间:l=mid,r=mid
  • l和r代表左右两个区间,最后还要判断:nums[l]比2大,说明数组中的数字都大于2。nums[r]比2小,说明数组中的数字都小于2。最后再判断l和r,哪一个离2近一点,返回哪个。

todo:https://leetcode-cn.com/problems/search-insert-position/solution/te-bie-hao-yong-de-er-fen-cha-fa-fa-mo-ban-python-/

69. x 的平方根

实现 int sqrt(int x) 函数。计算并返回 x 的平方根,其中 x 是非负整数。由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。

1062.最长重复有序区间

给定一个字符串s,找出里面长的重复子区间
  • 用到了第二个模版:找最右边的满足条件的位置。
  • 但是判断条件是f(s,mid),判断在s当中是否存在长度为mid的重复子序列。
    在这里插入图片描述

在这里插入图片描述

33. 搜索旋转排序数组

假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。你可以假设数组中不存在重复的元素。
思路:排除二分法,根据mid的值可以把区间分为两部分,一个有序,一个无序。再用排除法。
class Solution {
    public int search(int[] nums, int target) {
        if(nums.length==0)
        {
            return -1;
        }
        int left=0,right=nums.length-1;
        while(left<right)
        {
            //因为出现了left=mid,为了避免出现死循环,所以是right-left+1
            int mid=left+(right-left+1)/2;
            if(nums[mid]<nums[right])
            {
                if(nums[mid]<=target&&target<=nums[right])
                {
                    left=mid;
                }
                else
                {
                    right=mid-1;
                }
            }
            //为了跟上面的统一,上面算mid的加了1,认为left,mid-1是有序的,所以后面都减了1
            else{
                if(nums[left]<=target&&target<=nums[mid-1])
                {
                    right=mid-1;
                }
                else{
                    left=mid;
                }
            }
        }
        //为了避免出现数组中不存在target的情况,所以还要再判断一次
        if(nums[left]==target)
        {
            return left;
        }
        return -1;

    }
}

81. 搜索旋转排序数组 II

假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,0,1,2,2,5,6] 可能变为 [2,5,6,0,0,1,2] )。编写一个函数来判断给定的目标值是否存在于数组中。若存在返回 true,否则返回 false。

思路:向前遍历找到第一个出现的mid值是错误的,也不用这样做,因为如果mid小于right,前后有重复的数,也不影响,这样会造成死循环。
如果mid和right相等,那么不知道左右区间哪一个是严格单调的,所以缩减right的值,再次判断

 public boolean search(int[] nums, int target) {
        int len = nums.length;
        if (len == 0) {
            return false;
        }
        int left = 0;
        int right = len - 1;

        while (left < right) {
            int mid = (left + right + 1 ) >>> 1;
            if (nums[mid] < nums[right]) {
                // 10 11 4 5 6 7 8 9
                // 右边的一定是顺序数组,包括中间数
                if (nums[mid] <= target && target <= nums[right]) {
                    left = mid;
                } else {
                    right = mid - 1;
                }
            } else if (nums[mid] > nums[right]) {
                // 4 5 9  2
                // 左边是一定是顺序数组,包括中间数
                if (nums[left] <= target && target < nums[mid]) {
                    right = mid - 1;
                } else {
                    left = mid;
                }
            }else {
            //如果mid和right相等的情况,不知道前后区间哪个是严格递增递减的,缩减区间,right=right-1。要先判断right是否是target
                if(nums[right] == target){
                    return true;
                }
                right = right -1;
            }
        }
        return nums[left] == target;
    }

153. 寻找旋转排序数组中的最小值

假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。请找出其中最小的元素。你可以假设数组中不存在重复元素。

思路:普普通通排除二分法

154. 寻找旋转排序数组中的最小值 II

假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。请找出其中最小的元素。

注意数组中可能存在重复的元素
思路:mid和right相等时缩减right的大小

public int findMin(int[] nums) {
        if(nums.length==0)
        {
            return -1;
        }
        int l=0,r=nums.length-1;
        while(l<r)
        {
            int mid=l+(r-l)/2;
            if(nums[mid]>nums[r])
            {
                l=mid+1;
            }
            else if(nums[mid]<nums[r])
            {
                r=mid;
            }
            //当nums[mid]=nums[r]时,缩小r的值继续判断
            else{
                r=r-1;
            }
        }
        return nums[l];

    }

300. 最长上升子序列

给定一个无序的整数数组,找到其中最长上升子序列的长度。

思路:
1)动态规划
2)二分法??????

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值