[leetCode]剑指 Offer 53 - I. 在排序数组中查找数字 I
解法 二分查找
直观解法是从前开始遍历,找到目标第一次出现的位置和最后一次出现的位置,通过两次位置相减得到目标值出现的次数。时间复杂度为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);
}
}