[leetCode]剑指 Offer 53 解法 二分查找

 直观解法是从前开始遍历,找到目标第一次出现的位置和最后一次出现的位置,通过两次位置相减得到目标值出现的次数。时间复杂度为O(n)。
 可以通过改进二分查找,通过二分查找找到目标值第一次出现的位置和最后一次出现的位置,这样时间复杂度为O(logn)。
 通常二分查找是将目标值k与数组中间位置的元素m进行比较。如果m>k,则在数组前半部分继续查找;如果m < k则在数组后半部分查找。那么如果m = k,由于需要找到目标值第一次出现的位置就需要判断m之前的元素是否等于k如果等于k则继续在之前部分查找,如果不等于k则返回当前m的下标。
 同理获取k最后出现的位置也是相同的分析,代码如下:

class Solution {
    public int search(int[] nums, int target) {
        if (nums == null || nums.length == 0)
            return 0;
        int number = 0;
        int first = getFirstTarget(nums, target, 0, nums.length - 1);
        int last = getLastTarget(nums, target, 0, nums.length - 1);
        if(first > -1 && last > -1)
            number = last - first + 1;
        return number;
    }

    private int getFirstTarget(int[] nums, int k, int start, int end) {
        if (start > end)
            return -1;
        int middle = (start + end) / 2;
        int middleData = nums[middle];
        if (middleData == k) {
            if (middle > 0 && nums[middle - 1] != k || middle == 0) 
                return middle;
            else
                end = middle - 1;
        } else if (middleData < k) {
            start = middle + 1;
        } else {
            end = middle - 1;
        }
        return getFirstTarget(nums, k, start, end);
    }

    private int getLastTarget (int[] nums, int k, int start, int end) {
        if(start > end)
            return -1;
        int middle = (start + end) / 2;
        int middleData = nums[middle];
        if (middleData == k) {
            if (middle < nums.length - 1 && nums[middle + 1] != k || middle == nums.length -1) 
                return middle;
            else
                start = middle + 1;
        } else if (middleData < k) {
            start = middle + 1;
        } else {
            end = middle - 1;
        }
        return getLastTarget(nums, k, start, end);
    }
}