Skip to content

二分查找


35. 搜索插入位置

java
// 二分即可,考虑最后边界情况l, r重叠也是返回l即可
class Solution {
    public int searchInsert(int[] nums, int target) {
        int l = 0, r = nums.length - 1, mid;
        while (l <= r) {
            mid = (l + r) / 2;
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] < target) {
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
        return l;
    }
}

74. 搜索二维矩阵

java
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int n = matrix[0].length;
        int i = 0, j = matrix.length * n - 1, mid;
        while (i <= j) {
            mid = (i + j) / 2;
            if (matrix[mid / n][mid % n] < target) {
                i = mid + 1;
            } else if (matrix[mid / n][mid % n] > target) {
                j = mid - 1;
            } else {
                return true;
            }
        }
        return false;
    }
}

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

java
// 题解来自宫水三叶
// 压缩边界到某一边而不是在相等时返回
// 因此对于开区间那边,由于取不到mid,赋值为mid,还在范围内不会丢失,被开区间括号保护着
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] ans = new int[] { -1, -1 };
        if (nums.length == 0) {
            return ans;
        }
        ans[0] = findLeftIdx(nums, target);
        ans[1] = findRightIdx(nums, target);
        return ans;
    }

    public int findLeftIdx(int[] nums, int target) {
        int l = 0, r = nums.length - 1, mid;
        while (l < r) {
            mid = l + r >> 1; // mid靠近左边
            if (nums[mid] < target) {
                l = mid + 1;
            } else {
                r = mid;
            }
        }
        return nums[l] == target ? l : -1;
    }

    public int findRightIdx(int[] nums, int target) {
        int l = 0, r = nums.length - 1, mid;
        while (l < r) {
            mid = l + r + 1 >> 1; // 通过加1使得mid靠近右边
            if (nums[mid] > target) {
                r = mid - 1;
            } else {
                l = mid;
            }
        }
        return nums[l] == target ? l : -1;
    }
}

33. 搜索旋转排序数组

java
// 直接官解,不太好想出来,根据中间值与nums[0]确定mid处于第一段还是第二段,只与nums[0]比较
// 如果在第一段,表示第一段升序,第一段从[0-mid)判断target是否在其中,缩小范围
// 如果在第二段,表示第二段升序,第二段从[mid,n)判断target是否在其中,缩小范围
class Solution {
    public int search(int[] nums, int target) {
        int l = 0, r = nums.length - 1, mid;
        while (l <= r) {
            mid = (l + r) / 2;
            if (target == nums[mid]) {
                return mid;
            }
            if (nums[0] <= nums[mid]) {
                if (nums[0] <= target && target < nums[mid]) {
                    r = mid - 1;
                } else {
                    l = mid + 1;
                }
            } else {
                if (nums[mid] < target && target <= nums[nums.length - 1]) {
                    l = mid + 1;
                } else {
                    r = mid - 1;
                }
            }
        }
        return -1;
    }
}

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

java
// 二分查找其中的最小值,如果mid的值比右边界的大,说明mid在第一段
// 如果小于有边界,由于右边开区间,可以令r = mid进行保护,最后还是移动l
class Solution {
    public int findMin(int[] nums) {
        int l = 0, r = nums.length - 1, mid;
        if (nums[0] < nums[r]) {
            return nums[0];
        }
        while (l < r) {
            mid = l + r >> 1;
            if (nums[mid] > nums[r]) {
                l = mid + 1;
            } else {
                r = mid;
            }
        }
        return nums[l];
    }
}