leetcode 二分专题——java实现

35. 搜索插入位置

经典二分

class Solution {
    int sear(int[] a,int l,int r,int x){  //二分查找(以上两种差不多)
        int mid=0;
        while(l<=r){
            mid=(l+r)/2;
            if(a[mid]==x) return mid;
            if(x<a[mid]) r=mid-1;
            else if(x>a[mid]) l=mid+1;
        }
        if(a[mid]>x) return mid;
        else  return mid+1;

    }

    public int searchInsert(int[] nums, int target) {
        int n=nums.length;
        return sear(nums,0,n-1,target);
    }
}

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

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

关键在于:找到target的第一个和最后一个。

class Solution {
    int bsFirst(int[] a,int l,int r,int x){
        int mid=l,first=-1;
        while(l<=r){
            mid=(l+r)/2;
            if(a[mid]==x){//找第一个,往左继续找
                r=mid-1;
                first=mid;
            }
            else if(x<a[mid]){
                r=mid-1;
            }
            else l=mid+1;
        }
        return first;
    }
    int bsEnd(int[] a,int l,int r,int x){
        int mid=l,end=-1;
        while(l<=r){
            mid=(l+r)/2;
            if(a[mid]==x){
                l=mid+1;//找最后一个,往右继续找
                end=mid;
            }
            else if(x<a[mid]){
                r=mid-1;
            }
            else l=mid+1;
        }
        return end;
    }

    public int[] searchRange(int[] nums, int target) {
        //分别找target第一个和最后一个
        return new int[]{bsFirst(nums,0,nums.length-1,target),bsEnd(nums,0,nums.length-1,target)};

    }
}

33. 搜索旋转排序数组

整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
几个易错样例:
input:[1] 0 output:-1
input:[3,1] 0 output:-1
input:[1,3] 0 output:-1

本题的关键是:旋转数组导致nums[0]与nums[mid]没有绝对的大小关系了,正好利用这点找到分割点。

class Solution {
    
    public int search(int[] nums, int target) {
        //先找分割点nums[0]<nums[mid]即正确顺序,那就往后找
        //假装将分割点前面的移到后面去,超出部分的下标用%就能从前面定位了,与基本二分查找一样步骤
        int n=nums.length;
        int l=0,r=n-1;
        int mid=0,min=0;
        System.out.println(mid);
        while(l<=r){
            mid=(l+r)/2;
            
            if(nums[0]>nums[mid]){//不正常现象,说明mid或mid左边出现最小值
                r=mid-1;min=mid;
            }
            else {
                l=mid+1;
            }
        }
        l=min;r=n+min-1;
        while(l<=r){
            int m=(l+r)/2;
            mid=m%n;
            if(nums[mid]==target)return mid;
            if(nums[mid]<target)l=m+1;
            else r=m-1;
        }
        return -1;
    }
}

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

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的最小元素 。你必须设计一个时间复杂度为 O(log n) 的算法解决此问题.

就是上题的前半部分

class Solution {
    public int findMin(int[] nums) {
        //就算经过旋转,前后两端也是有序的
        int n=nums.length;
        int l=0,r=n-1;
        int mid=0,min=nums[0];
        while(l<=r){
            mid=(l+r)/2;
            if(nums[mid]>=nums[0]){
                l=mid+1;
            }
            else{
                r=mid-1;
                min=nums[mid];
            }
           
        }
        return min;

    }
}

74. 搜索二维矩阵

在矩阵那章出现过
主打的就是从右上角往左下角看是类似二叉树结构
给你一个满足下述两条属性的 m x n 整数矩阵:
每行中的整数从左到右按非严格递增顺序排列。
每行的第一个整数大于前一行的最后一个整数。
给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        //非严格递增就是可以相等
         int n=matrix.length,m=matrix[0].length;
        int i=0,j=m-1;
        //从右上角开始
        while(i<n&&j>=0){
            if(matrix[i][j]==target) return true;
            if(target>matrix[i][j])i++;
            else j--;
        }
        return false;
    }
}
  • 11
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值