力扣:二分查找简单题集解

二分查找


二分查找是在一个有序数组里,进行查找的一种算法

先来一题简单题看看二分查找是长什么样的

374.猜数字大小

List item

374. 猜数字大小 链接

猜数字游戏的规则如下:

  • 每轮游戏,我都会从 1n 随机选择一个数字。 请你猜选出的是哪个数字。
  • 如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。

你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况(-110):

  • -1:我选出的数字比你猜的数字小 pick < num
  • 1:我选出的数字比你猜的数字大 pick > num
  • 0:我选出的数字和你猜的数字一样。恭喜!你猜对了!pick == num

返回我选出的数字。

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        int left=1;
        int right=n;
        while(left<right)
        {
            int mid=left+(right-left)/2;
            if(guess(mid)==-1)
            {
                right=mid;
            }else if(guess(mid)==1)
            {
                left=mid+1;
            }else{
                return mid;
            }
        }
        return left;
    }
}

35.搜索插入位置

35. 搜索插入位置 链接

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

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

69. x 的平方根

给你一个非负整数 x ,计算并返回 x算术平方根

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

**注意:**不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5

class Solution {
    public int mySqrt(int x) {
        if(x==0) return 0;
        long left=1;
        long right=x;
        while(left<right)
        {
            //为了防止溢出
            long mid=left+(right-left)/2;
            long s=mid*mid;

            if(s>=x)
            {
                right=mid;
            }else{
                left=mid+1;
            }
        }
        if(left*left>x)
        {
            return (int)(left-1);
        }else{
            return (int)left;
        }
    }
}

441. 排列硬币

441. 排列硬币

你总共有 n 枚硬币,并计划将它们按阶梯状排列。对于一个由 k 行组成的阶梯,其第 i 行必须正好有 i 枚硬币。阶梯的最后一行 可能 是不完整的。

给你一个数字 n ,计算并返回可形成 完整阶梯行 的总行数。

输入:n = 5
输出:2
解释:因为第三行不完整,所以返回 2 。
class Solution {
    public int arrangeCoins(int n) {


        int left = 1;
        int right = n;

        while (left <= right) {
            int mid = left + (right - left) / 2;
            long sum = (long) mid * (mid + 1) / 2;

            if (sum == n) {
                return mid;
            } else if (sum < n) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return right;
    }
}

744. 寻找比目标字母大的最小字母

744. 寻找比目标字母大的最小字母

给你一个字符数组 letters,该数组按非递减顺序排序,以及一个字符 targetletters至少有两个不同的字符。

返回 letters 中大于 target 的最小的字符。如果不存在这样的字符,则返回 letters 的第一个字符。

class Solution {
    public char nextGreatestLetter(char[] letters, char target) {
        int left=0,right=letters.length-1;
        if(letters[right]<=target || letters[left]>target)
        {
            return letters[0];
        }
        while(left<right)
        {
            int mid=left+(right-left)/2;
            char c=letters[mid];
            if(c>target)
            {
                right=mid;
            }else if(c<=target)
            {
                left=mid+1;
            }
        }
        return letters[left];
    }
}

278. 第一个错误的版本

278. 第一个错误的版本

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        boolean f=isBadVersion(1);

        int left=1,right=n;
        while(left<right)
        {
            int mid=left+(right-left)/2;
            f=isBadVersion(mid);
            if(f)
            {
                right=mid;
            }else{
                left=mid+1;
            }
        }
        return left;
    }
}

1346. 检查整数及其两倍数是否存在

1346. 检查整数及其两倍数是否存在 链接

给你一个整数数组 arr,请你检查是否存在两个整数 NM,满足 NM 的两倍(即,N = 2 * M)。

更正式地,检查是否存在两个下标 ij 满足:

  • i != j
  • 0 <= i, j < arr.length
  • arr[i] == 2 * arr[j]

解题思路

​ 检查是否存在两个数满足2倍关系,一眼二分

​ 二分固定步骤:先进行排序

​ 然后再把每个数取出来,放进while二分查找里循环查找,在这里需要注意一个特殊值0因为0*2==0,当时下标又不能为自己

所以进行了判断mid!=i

class Solution {
    public boolean checkIfExist(int[] arr) {
        int n = arr.length;
        Arrays.sort(arr);
        for (int i = 0; i < n; i++) {
            int x = arr[i] * 2;
            int left = 0;
            int right = n;
            while (left < right) {
                int mid = left + (right - left) / 2;
                if (arr[mid] == x && mid!=i) {
                    return true;
                }else if (arr[mid] > x) {
                    right = mid;
                }else{
                    left = mid + 1;
                }
            }
        }
        return false;
    }
}

1351. 统计有序矩阵中的负数

1351. 统计有序矩阵中的负数 链接

给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。 请你统计并返回 grid负数 的数目。

解题思路

​ 题目说明以非递增顺序排列,就这个条件,一眼二分

​ 二分查找循环每行,二分常规写法,找到left是正数和负数的交界位置,用长度减去left就是负数的个数

class Solution {
    public int countNegatives(int[][] grid) {
        int n=grid.length;
        int m=grid[0].length;
        int ans=0;
        for(int i=0;i<n;i++)
        {
            int left=0;
            int right=m;
            while(left<right)
            {
                int mid=left+(right-left)/2;
                if(grid[i][mid]>=0)
                {
                    left=mid+1;
                }else{
                    right=mid;
                }
            }
            ans+=m-left;
        }
        return ans;
    }
}

2529. 正整数和负整数的最大计数

2529. 正整数和负整数的最大计数

给你一个按 非递减顺序 排列的数组 nums ,返回正整数数目和负整数数目中的最大值。

  • 换句话讲,如果 nums 中正整数的数目是 pos ,而负整数的数目是 neg ,返回 posneg二者中的最大值。

注意:0 既不是正整数也不是负整数。

解题思路

​ 老规矩,看到非递减顺序,一眼看出二分,然后按二分的标准套路走即可

class Solution {
    public int maximumCount(int[] nums) {
        int left=0;
        int right=nums.length;
        int sum=0;
        //判断边界条件
        if(nums[0]>0 || nums[nums.length-1]<0) {//全为正数或全为负数
            return nums.length;
        }else if(nums[0]==0 && nums[nums.length-1]==0)//全部都是0
        {
            return 0;
        }
        while(left<right)
        {
            int mid=left+(right-left)/2;
            if (nums[mid]<=0){
                if(nums[mid]==0)
                    sum++;//计算0有多少个
                left=mid+1;
            }else{
                right=mid;
            }
        }
        if(nums[nums.length-1]==0)sum++;//最后这个0再判断一下,太边界了判断不到
        right=nums.length-left;
        left=left-sum; //因为left碰到0也要往右走
        return Math.max(right,left);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值