剑指Offer 面试题53 - I. 在排序数组中查找数字 I(Java代码)

https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/

题目描述

统计一个数字在排序数组中出现的次数。

输入输出样例

输入: nums = [5,7,7,8,8,10], target = 8
输出: 2

二分查找到目标值,再去扩大窗口

  • 使用二分法找到该数组中对应的数字
  • 让左右指针指向下标处,然后左右指针分别移动到最大范围位置
class Solution {
    public int search(int[] nums, int target) {
        if(nums.length == 0) return 0;
        // 有排序,用二分
        int 
            left = 0, 
            right = nums.length - 1;
        while(left < right){
            int mid = (right + left) >>> 1;
            if(nums[mid] == target){
                left = mid;
                break;
            }
            // target 在 mid 的右边
            else if(nums[mid] < target){
                left = mid + 1;
            }else{
                right = mid;
            }
        }
        if(nums[left] != target) 
            return 0;
        // 将当前窗口扩大
        int l = left, r = left;
        while(l >= 0 && nums[l] == target) l--;
        while(r < nums.length && nums[r] == target) r++;
        return (r-l-2+1);
    }   
}

二分法变式,查找到目标值

  • 在二分查找中,二分法的不同写法,可以让查找定位的下标自动变为该目标值在有序数组中的边界位置

代码:

class Solution {
    public int search(int[] nums, int target) {
        if(nums.length == 0) return 0;
        int
            l = 0,
            r = nums.length - 1,
            mid = 0;
        // find left
        while(l < r){
            mid = (l + r) >>> 1;
            if(nums[mid] >= target){
                r = mid;    // 右边界一直向左趋近,最后得到最左的下标
            }else{
                l = mid + 1;
            }
        }
        int left = l;
        if(nums[left] != target) return 0;

        l = 0;
        r = nums.length - 1;
        mid = 0;

        // find right
        while(l < r){
            mid = (l + r + 1) >>> 1;
            if(nums[mid] <= target){
                l = mid;    // 左边界一直向右趋近,最后得到最右的下标
            }else{
                r = mid-1;
            }
        }
        int right = r;

        return (right - left + 1);
    }
}

nice解法

这个版本的二分法,让最后返回的下标都是目标值的右边一个

class Solution {
    public int search(int[] nums, int target) {
        return helper(nums, target) - helper(nums, target - 1);
    }
    int helper(int[] nums, int tar) {
        int i = 0, j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            // 只要 <= tar 就一直向右趋近。
            if(nums[m] <= tar) i = m + 1;
            else j = m - 1;
        }
        // 最后得到的 i刚好是目标值的右面一个
        return i;
    }
}

你可能感兴趣的:(剑指Offer)