二分刷题讲解

二分刷题讲解

一.模板

y总的两个模板:
(下面两个模板只适用于在区间内存在要寻找的值时才适用,当然不存在也可以用只是要对模板修改)

模板1

//更新方式为l=mid+1,r=mid
int binarySearch(int l,int r)
{
	int mid;
	while(l<r)
	{
		mid = (l+r)/2;//写成l+(r-l)/2可以防止越界,这在数据量比较大的时候就更加适用
		if(check(mid))
			r=mid;
		else
			l=mid+1;
	}
	return l;
}

模板2

//更新方式为l=mid,r=mid-1
int binarySearch(int l,int r)
{
	int mid;
	while(l<r)
	{
		mid = (l+r+1)/2;//防止死循环,可以拿1,2,3数组,寻找3试一下不+1,这时会死循环
		if(check(mid))
			l=mid;
		else
			r=mid+1;
	}
	return l;
}

二.题目y总的讲解笔记

1.求平方根Leedcode–69

注意要用long最后强转一下,因为用int尤其在mid*mid那个地方绝对会越界
下面套用两个模板,其中第一个成功通过,第二个失败,具体原因分析如注释:

模板2

class Solution {
	//该种写法最后返回的要么是mid-1,要么是mid,而条件是mid*mid>x,假如mid*mid>x,返回mid-1,为正确值,如果mid*mid<=x,返回mid也为正确值
    public int mySqrt(int x) {
        long l=0,r=x;
        long mid;
        while(l<r)
        {
            mid=l+(r-l+1)/2;
            if(mid*mid>x)
                r=mid-1;
            else
                l=mid;
        }
        return (int)l;
    }
}

题目描述:

实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4
输出: 2
示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842…,
由于返回类型是整数,小数部分将被舍去。

模板1

class Solution {
//该种写法最后返回的要么是mid+1,要么是mid,而条件是mid*mid<=x,假如mid*mid<=x,返回mid+1,为比正确值大一,如果mid*mid>x,返回mid也为比正确值大一
    public int mySqrt(int x) {
        long l=0,r=x;
        long mid;
        while(l<r)
        {
            mid=l+(r-l)/2;
            if(mid*mid<=x)
                l=mid+1;
            else
                r=mid;
        }
        return (int)l;
    }
}

下面对模板1进行改进(提交通过)

class Solution{
public int mySqrt(int x) {
        long l=0,r=x;
		//0与1要单独讨论
        if(r==0)
            return 0;
        if(r==1)
            return 1;
        long mid;
        while(l<r)
        {
            mid=l+(r-l)/2;
            if(mid*mid<=x)
                l=mid+1;
            else
                r=mid;
        }
        return (int)l-1;
    }
}

总结:千万不要为了用哪一个模板而改模板,而应该选择适用的的那一个

2.Leedcode—39

题目描述:

给定一个按照升序排列的整数数组 nums,和一个目标值 target。
找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。

如果数组中不存在目标值,返回 [-1, -1]。

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]
示例 2:

输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] a=new int[2];
        a[0]=a[1]=-1;
        if(nums.length==0)
            return a;
        int l=0,r=nums.length-1;
        int mid;
        while(l<r)
        {
            mid = (l+r+1)/2;
            //注意等于号不可以掉,因为如果去掉当nums[mid]==target时,那么此时r=mid-1就直接将最后一个target淘汰掉了,下同
            if(nums[mid]<=target)//小于等于那么此时最后一个target必然在mid右边或就是mid
                l=mid;
            else
                r=mid-1;
        }
        //防止target不存在
        if(nums[l]!=target)
        {
            return a;
        }
        a[1]=l;
        l=0;
        r=nums.length-1;
        while(l<r)
        {
            mid = (l+r)/2;
            if(nums[mid]>=target)//大于等于那么此时第一个target必然在mid左边或等于mid
                r=mid;
            else
                l=mid+1;
        }
        a[0]=l;
        return a;
    }
}

3.Leedcode–74

题目描述:

编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:

每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。
示例 1:

输入:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 3
输出: true
示例 2:

输入:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 13
输出: false
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int row=matrix.length;
        if(row==0)
            return false;
        int col=matrix[0].length;
        if(col==0)
            return false;
        int i,j;
        if(row==0)
        {
            return false;
        }
        int l=0,r =row*col-1;
        int mid ;
        while(l<r)
        {
            mid = (l+r)/2;
            if(((l+r)/2+1)%col==0){
                 i=((l+r)/2+1)/col-1;
                 j=col-1;
            }
            else
            {
                i=((l+r)/2+1)/col;
                j=((l+r)/2+1)%col-1;
            }
            if(matrix[i][j]>=target)
                r=mid;
            else
                l=mid+1;
        }
            if(((l+r)/2+1)%col==0){
                 i=((l+r)/2+1)/col-1;
                 j=col-1;
            }
            else
            {
                i=((l+r)/2+1)/col;
                j=((l+r)/2+1)%col-1;
            }
        if(matrix[i][j]!=target)
            return false;
        else
            return true;
    }
}

升级版:搜索二维矩阵 II

4.Leedcode-153

题目描述:

假设按照升序排序的数组在预先未知的某个点上进行了旋转。

( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

请找出其中最小的元素。

你可以假设数组中不存在重复元素。

示例 1:

输入: [3,4,5,1,2]
输出: 1
示例 2:

输入: [4,5,6,7,0,1,2]
输出: 0
class Solution {
    //使用二分的思想来解决问题
    public int findMin(int[] nums) {
        int mid;
        int left = 0;
        int right = nums.length-1;
        if(nums[0]<nums[nums.length-1])
            return nums[0];
        else{
        //左半部分在nums[0]上面,右半部分在nums[0]下面
            while(left<right){
                mid = left+right>>1;
                if(nums[mid]<nums[0])
                    right = mid;
                else
                    left = mid+1;
            }
        }
        return nums[left];
    }
}

5.Leedcode-162

题目描述:

峰值元素是指其值大于左右相邻值的元素。
给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。
数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞。
示例 1:
输入: nums = [1,2,3,1]
输出: 2
解释: 3 是峰值元素,你的函数应该返回其索引 2。

示例 2:
输入: nums = [1,2,1,3,5,6,4]
输出: 1 或 5 
解释: 你的函数可以返回索引 1,其峰值元素为 2;
     或者返回索引 5, 其峰值元素为 6。
     
说明:
你的解法应该是 O(logN) 时间复杂度的。
class Solution {
    public int findPeakElement(int[] nums) {
        if(nums.length==1)
            return 0;
        if(nums[nums.length-1]>nums[nums.length-2])
            return nums.length-1;
        int left = 0;
        int right = nums.length-1;
        int mid;
        while(left<right){
            mid = left+right>>1;
            if(mid<=nums.length-2&&nums[mid]>nums[mid+1])
                right=mid;
            else 
                left = mid+1;
        }
        return left;
    }
}

这个问题的升级版为二维矩阵峰值的查找,如果你觉得本问题难度不大,可以参考这篇文章提升自己:二维峰值查找

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值