常见面试算法题(二分查找)

172 阅读2分钟

第一部分:四种基本情况

1. 无重复数字的二分查找

leetcode-cn.com/problems/bi…

class Solution {
    public int search(int[] nums, int target) {
        int n = nums.length;
        int l = 0 , r = n-1;
        while(l < r){
            int mid = l + r + 1 >> 1;
            if(nums[mid] > target) r = mid-1;
            else l = mid;
        }
        return nums[l] == target ? l : -1;
    }
}

2. 有重复数字的二分查找第一个位置和最后一个位置

leetcode-cn.com/problems/fi…

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res = new int[2];
        int n = nums.length;
        if(n == 0) return new int[]{-1,-1};
        //找到第一个出现的位置
        int l = 0  , r = n-1;
        while(l < r){
            int mid = l + r >> 1;
            if(nums[mid] < target) l = mid+1;
            else r = mid;
        }
        if(nums[l] != target) return new int[]{-1,-1};
        else res[0] = l;

        //找到最后一个出现的位置
        l = 0;
        r = n-1;
        while(l < r){
            int mid = l + r +1 >> 1;
            if(nums[mid] > target) r = mid-1;
            else l = mid;
        }
        res[1] = l;
        return res;
    }
}

3. 搜索插入位置

leetcode-cn.com/problems/se…

class Solution {
    public int searchInsert(int[] nums, int target) {
        int n = nums.length;
        //1. 注意如果最后一个数小于target的话,就返回数组长度
        if (n == 0 || nums[n-1] < target) return n;
        int l = 0 , r = n-1;
        while(l < r){
            int mid = l + r >> 1;
            if(nums[mid] < target) l = mid + 1;
            else r = mid;
        }
        return l;

    }
}

4. x的平方根(只保留整数部分)

   class Solution {
    public int mySqrt(int x) {
        int l = 0 , r = x;
        while(l < r){
            int mid = l + r + 1 >> 1;
            if(mid > x / mid) r = mid-1;
            else l = mid;
        }
        return l;

    }
}

5. 寻找重复的数

leetcode-cn.com/problems/fi…

class Solution {
    public int findDuplicate(int[] nums) {
        int n = nums.length;
        //对值的范围进而二分
        int l = 0 , r = n-1;
        while (l < r){
            int mid = l+r >>1;
            //看一下数组中比mid小的数有多少
            int count = 0;
            for (int num : nums){
                if (num <= mid) count++;
            }

            //比mid小的数大于mid,说明在左边,可能是mid
            if (count > mid) r = mid;
            else l = mid+1;
        }
        return l;
    }
}

6. 实现Pow(x,n)

leetcode-cn.com/problems/po…

class Solution {
    public double myPow(double x, int n) {
            
        double res = 1.0;
        for(int i = n ; i != 0 ; i /=2){
            if(i % 2 != 0) res = res * x;
            x *= x;
        }
        return n < 0 ? 1/res : res;

    }
}

7. 寻找两个排序数组的中位数

leetcode-cn.com/problems/me…

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int n = nums1.length;
        int m = nums2.length;
        int l = (n + m + 1)/2;
        int r = (n + m + 2)/2;
        return (getK(nums1, 0 , n-1 , nums2 , 0 , m-1 , l) + getK(nums1 , 0 ,n-1 , nums2 ,0,m-1,r))/2.0;
    }

    //从两个正序数组中获取第k大的数
    int getK(int[] nums1 , int s1 , int e1 , int[] nums2 , int s2 , int e2 , int k){
        int len1 = e1 - s1 + 1;
        int len2 = e2 - s2 + 1;
        if(len1 > len2) return getK(nums2 , s2 , e2 , nums1 , s1 , e1 , k);
        if(len1 == 0) return nums2[s2 + k -1];
        if(k == 1) return Math.min(nums1[s1] , nums2[s2]);

        int i = s1 + Math.min(len1 , k/2)-1; //每次取一半的值
        int j = s2 + Math.min(len2 , k/2)-1;
        
        //每一轮都将较小的那半组数据舍去
        if(nums1[i]  > nums2[j]) return getK(nums1 , s1 ,e1 , nums2 ,j+1, e2 ,k-(j-s2+1));
        else return getK(nums1, i+1 ,e1 , nums2 , s2 , e2 , k-(i-s1+1));
    }
}

第二部分:旋转排序数组

1. 寻找旋转排序数组中的最小值(无重复值)

leetcode-cn.com/problems/fi…


class Solution {
    public int findMin(int[] nums) {
        int n = nums.length;
        int l = 0 , r = n-1;
        while(l < r){
            int mid = l + r >> 1;
            //34512
            if(nums[mid] > nums[r]) l = mid+1;
            else r = mid;
        }
        return nums[l];
    }
}

2. 寻找旋转排序数组中的最小值(有重复值)

leetcode-cn.com/problems/fi…

class Solution {
    public int findMin(int[] nums) {
        int n = nums.length;
        int l = 0 , r = n-1;
        while(l < r){
            int mid = l + r >> 1;
            if(nums[mid] > nums[r]) l = mid+1;
            else if(nums[mid] < nums[r]) r = mid;
            else r--;
        }
        return nums[l];
    }
}

3. 寻找旋转排序数组中的指定值(无重复值)

leetcode-cn.com/problems/se…

class Solution {
    public int search(int[] nums, int target) {
        int n = nums.length;
        if(n == 0) return -1;
        int l = 0 , r = n-1;
        while(l < r){
            int mid = l + r >> 1;
            //34512
            if(nums[mid] > nums[r]){
                if(target >= nums[l] && target <= nums[mid]) r = mid;
                else l = mid+1;
            }else{
                //561234
                if(target > nums[mid] && target <= nums[r]) l = mid+1;
                else r = mid;
            }
        }
        return nums[l] == target ? l : -1;
    }
}

第三部分:二维矩阵

1. 搜索二维矩阵

leetcode-cn.com/problems/se…

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length; //行数
        int n = matrix[0].length; //列数
        int l = 0 , r = m *n -1;
        while(l < r){
            int mid = l + r + 1 >> 1;
            //将一维的数组转换成二维的坐标
            if(matrix[mid / n][ mid % n] > target) r = mid-1;
            else l = mid;
        }
        return matrix[l/n][l%n] == target;
    }
}

2. 搜索二维矩阵2

leetcode-cn.com/problems/se…

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length; //行数
        int n = matrix[0].length; //列数
        int i = 0 , j = n-1;
        while(i <= m-1 && j >= 0){
            if(matrix[i][j] > target) j--;
            else if(matrix[i][j] < target) i++;
            else return true;
        }
        return false;
        
    }
}

3. 有序矩阵中第k小的数

leetcode-cn.com/problems/kt…

class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        int row = matrix.length;
        int col = matrix[0].length;
        int l = matrix[0][0];
        int r = matrix[row-1][col-1];
        while(l < r){
            int mid = l + r >> 1;
            int count = findCount(matrix, mid , row ,col); //找到矩阵中 <= mid 的个数
            if(count < k) l = mid + 1;
            else r = mid;
        }
        return l;
    }


    //1  5  9
    //10 11 13     12
    //12 13 15

    int findCount(int[][] matrix , int mid , int row , int col){
        int i = row-1 , j = 0;
        int count = 0;
        while(i >= 0 && j <= col-1){
            if(matrix[i][j] <= mid){
                count += i+1; // 第j列有i+1个元素<=mid
                j++;
            }else i--;// 第j列目前的数大于mid,需要继续在当前列往上找
        }
        return count;
    }
}