LeetCode——二分查找(Java)

简介

记录一下自己刷题的历程以及代码,会尽量把在本地测试包含main函数的完整代码贴上。写题过程中参考了 代码随想录。会附上一些个人的思路,如果有错误,可以在评论区提醒一下。

704.二分查找

原题链接

right = nums.length - 1;是一种闭区间的写法,左右下标都在数组范围内,此时while循环中需要加上=,否则会在nums = [5],target = 5的情况下报错。

class Solution {
    public int search(int[] nums, int target){
        if(target<nums[0] || target>nums[nums.length-1]){
            return -1;
        }
        int left = 0;
        int right = nums.length - 1;
        int mid = 0;
        while(left <= right){
            //System.out.println("left:" + left + "  mid:" + mid + "  right:" + right);
            mid = (left + right) / 2;
            if(target > nums[mid]) {
                left = mid + 1;
            }else if(target < nums[mid]){
                right = mid - 1;
            }else{
                return mid;
            }
        }
        return -1;
    }
}

public class main {
    public static void main(String[] args) {
        Solution solution = new Solution();
        int[] nums = new int[]{-1,0,3,5,9,12};
        int target = 9;
        System.out.println(solution.search(nums,target));
    }
}

35. 搜索插入位置

原题链接

总共四种情况
①找到元素,返回middle
找不到元素,循环正常退出,此时有right = left-1
②在所有元素之前,此时left = 0;right = -1 target需要插入0,即left的位置
③在两个元素中间,此时nums[left]>target;nums[right]<targettarget需要插入left的位置
④在所有元素之后,此时right=nums.length()-1;left=nums.length()target需要插入left的位置

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

public class main {
    public static void main(String[] args) {
        Solution solution = new Solution();
        int[] nums = new int[]{1,3};
        int target = 0;
        System.out.println(solution.searchInsert(nums,target));
    }
}

34. 在排序数组中查找元素的第一个和最后一个位置

原题链接

方法①:找到nums[mid] == target时在mid左右继续查找相等的值,在二分查找的代码上增加一些功能即可,但是当连续的数字过多时容易将复杂度退到O(n),相当于遍历的复杂度。可以通过这道题,但是时间复杂度较高。

方法②:分别寻找左右边界,左边界指向 该元素第一个位置之前的元素,右边界指向最后一个位置之后的元素。

例如找左边界:nums[mid] == target时也要把范围划到mid左边,因为我们需要找的是target的边界,考虑下面的代码:

int left = 0;
int right = nums.length - 1;
int leftBorder = -2;
while(left <= right){
    if(target > nums[mid]) {
        left = mid + 1;
    }else if(target < nums[mid]){
        right = mid - 1;
        leftBorder = right;
    }else if(target == nums[mid]){
        right = mid - 1;
        leftBorder = right;
    }
}

查找左右边界的函数内部的判断语句是由上面的判断语句三种情况合并而成,结果如下:

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int leftBorder = searchLeft(nums, target);
        int rightBorder = searchRight(nums, target);
        if(leftBorder == -2 || rightBorder == -2) return new int[]{-1 ,-1};
        if(rightBorder - leftBorder > 1) return new int[]{leftBorder + 1,rightBorder - 1};
        return new int[]{-1 ,-1};
    }

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

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


}

public class main {
    public static void main(String[] args) {
        Solution solution = new Solution();
        int[] nums = new int[]{2, 2};
        int target = 3;
        int[] array = solution.searchRange(nums,target);
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + " ");
        }
    }
}

69. x 的平方根

原题链接

一上来会想到遍历,但是时间效率显然是比较低的。
在二分的基础上做改进:题目给定0 <= x <= 2^31 - 1。用 mid * midx 做比较时,int型的mid做平方运算很容易超出int的数据显示范围。

方法①:改成长整形long进行比较,输出时做类型转换。

方法②:用x / mid > mid来做判断,注意该方法需要避免mid == 0的情况,除数为0会报错(x<2时,mid的初值为0,索性在开头将return 0return 1 的方法都判断输出)。

class Solution {
    public int mySqrt(int x) {
        if(x < 1) return 0;
        else if(x < 4) return 1;
        int left = 0;
        int right = x;
        while(left <= right){
            int mid = (left + right) / 2;
            System.out.println("left:" + left + "  mid:" + mid + "  right:" + right);
            if(x / mid > mid) {
                left = mid + 1;
            }else if(x / mid < mid){
                right = mid - 1;
            }else{
                return mid;
            }
        }
        return right;
    }
}

public class main {
    public static void main(String[] args) {
        Solution solution = new Solution();
        int x = 2147395599;
        System.out.print(solution.mySqrt(x));
    }
}

367. 有效的完全平方数

原题链接

用二分法的思想,跟69. x 的平方根思路差不多,使用二分法在java中能打败100%的用户。边界上,因为这道题num≥1,就不用担心num从0开始时mid可能为0,不像上一题一样需要在开头排除这种情况。一直到循环结束,除了num%mid == 0的情况下,都返回false

class Solution {
    public boolean isPerfectSquare(int num) {
        int left = 1;
        int right = num;
        while(left <= right){
            int mid = (left + right) / 2;
            //System.out.println("left:" + left + "  mid:" + mid + "  right:" + right);
            if(num / mid > mid) {
                left = mid + 1;
            }else if(num / mid < mid){
                right = mid - 1;
            }else if(num % mid == 0){
                return true;
            }else{
                return false;
            }
        }
        return false;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值