二分法相关题目

一般用法:
public int binarySearch(int[] nums, int key) {
    int l = 0, h = nums.length - 1;
    while (l <= h) {
        int m = l + (h - l) / 2; // 防止l+h越界
        if (nums[m] == key) {
            return m;
        } else if (nums[m] > key) {
            h = m - 1;
        } else {
            l = m + 1;
        }
    }
    return -1;
}

二分法的时间复杂度为O(logN)

变种

例如在一个有重复元素的数组中查找 key 的最左位置的实现如下:

public int binarySearch(int[] nums, int key) {
    int l = 0, h = nums.length - 1;
    while (l < h) {
        int m = l + (h - l) / 2;
        if (nums[m] >= key) {
            h = m;
        } else {
            l = m + 1;
        }
    }
    return nums[l] == key ? l : -1;
}

注意:
l < h 而不是 l <= h,如果写成 l <= h 会出现死循环。对 mid 的计算是偏左的,如 (3, 4)的 mid 是 3,右边界不断向左靠近,当 l 等于 右边界 h 时,代表右边界向左移动到极限。

LeetCode 69. Sqrt(x)
    public int mySqrt(int x) {
        if(x <= 1) return x;
        int l = 1, h = x;
        while(l <= h) {
            int mid = l+(h-l)/2;
            int sqrt = x/mid; // mid*mid 可能越界
            if(sqrt == mid) return mid;
            else if (sqrt > mid) l = mid+1;
            else h = mid - 1;
        }
        return h;
    }
744. Find Smallest Letter Greater Than Target

大于给定元素的最小元素

    public char nextGreatestLetter(char[] letters, char target) {
        int l = 0, h = letters.length;
        while(l < h) {
            int mid = l+(h-l)/2;
            if(letters[mid] > target) h = mid;
            else l = mid+1;
        }
        return l == letters.length ? letters[0] : letters[l];
    }
540. Single Element in a Sorted Array

有序数组的 Single Element
第一个版本:

    public int singleNonDuplicate(int[] nums) {
        if(nums.length == 1) return nums[0];
        int l = 0, h = nums.length-1;
        while(l <= h) {
            int mid = l+(h-l)/2;
            if(mid == 0 || mid == nums.length-1) return nums[mid];
            else if(nums[mid] != nums[mid-1]) {
                if(nums[mid]!=nums[mid+1]) return nums[mid];
                else {
                    if((mid & 1) == 1) {
                        h = mid-1;
                    }else {
                        l = mid+2;
                    }
                }
            }else {
                if((mid & 1) == 1) {
                    l = mid+1;
                }else{
                    h = mid-2;
                }
            }
        }
        return -1;
    }

解题思路:求得 mid 与所有比较,若都不相同则返回nums[mid],否则根据mid的位置来判断单个元素在左侧还是右侧。注意边界值,当mid == 0 或 mid == length-1时直接返回nums[mid]。

我们来对上面代码进行优化:

    // 优化:利用数组的特点:通过主动选择mid,确保其为偶数,这样其左侧的元素个数就是偶数
    public int singleNonDuplicate2(int[] nums) {
        int l = 0, h = nums.length-1;
        while(l < h) {
            int mid = l+(h-l)/2;
            if((mid & 1) == 1) mid--;
            if(nums[mid] == nums[mid+1]) l = mid+2;
            else h = mid;
        }
        return nums[h];
    }
153. Find Minimum in Rotated Sorted Array

旋转数组的最小数字

    public int findMin(int[] nums) {
        int l = 0, h = nums.length-1;
        while(l < h) {
            int mid = l+(h-l)/2;
            if(nums[mid] < nums[h]) h = mid;
            else l = mid+1;
        }
        return nums[h];
    }
34. Find First and Last Position of Element in Sorted Array

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

    public int[] searchRange(int[] nums, int target) {
        int[] res = {-1, -1};
        if(nums == null || nums.length == 0) return res;
        int l = 0, h = nums.length-1;
        while(l < h) {
            int mid = l+(h-l)/2;
            if(nums[mid] >= target) h = mid;
            else l = mid+1;
        }
        if(nums[h] == target) res[0] = h;
        
        l = h;
        h = nums.length-1;
        while(l < h) {
            int mid = l+(h-l)/2+1;
            if(nums[mid] > target) h = mid-1;
            else l = mid;
        }
        if(nums[l] == target) res[1] = l;
        return res;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值