首先我的思考源于一道leetcode题目
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0
输出:[-1,-1]
提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一个非递减数组
-109 <= target <= 109
解答代码请品鉴:
public static void main(String[] args) {
int []nums = new int[]{1,2,3,5,5,8,8,8,10,13,15};
int target = 8;
int[] result = new BiSerch().searchRange(nums, target);
for (int i = 0; i < result.length; i++) {
System.out.println(result[i]);
}
}
//从这里开始----------------------------------------------------------
public int[] searchRange(int[] nums, int target) {
int leftIdx = binarySearch(nums, target, true);
int rightIdx = binarySearch(nums, target, false) - 1;
if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) {
return new int[]{leftIdx, rightIdx};
}
return new int[]{-1, -1};
}
public int binarySearch(int[] nums, int target, boolean lower) {//这里主要是将lower(leftIdx)与upper(rightIdx)的解法合并了,且看下面:
int left = 0, right = nums.length - 1, ans = nums.length;
while (left <= right) {//这里代表的是 左闭右闭([left,right]这里是数学的[]不是说数组)
int mid = (left + right) / 2;
if (nums[mid] > target || (lower && nums[mid] >= target)) {//其实这里的ums[mid] >= target可改为 ==的,它本质就是在补当 == 的空
//这里当lower == true时是相当与nums[mid] >= target;
//当lower == false时是相当于nums[mid] > target;
right = mid - 1;
ans = mid;
} else {
left = mid + 1;
}
}
return ans;
}
那么我所思考的是什么问题呢?那就是它的这个nums[mid] > target 与 nums[mid] >= target 对这个二分搜索的影响是什么?有什么区别?
如果我们不解决这个问题,那么我们不得不靠在脑海一直模拟来思考整个运作过程,显然这不利于我们去快速的思考以及抽象(一般化)它的过程?
问题一(影响是什么?):他影响的是left 与 right 这两个指针谁来移动。
问题二(有什么区别?):在这一题中,我们结合问题一可知,这个等于号落在谁的身上(left or right),那么这个指针就会在nums[mid] == target的时候向另一个指针收缩(靠近),直到left = right - 1时结束,因为这个时候,mid会落在left身上(left + ( (left+1)- left )/ 2) = left),当在nums[mid] >= target 条件下,在nums[mid] = target时,由right指针向left指针移动,当leit = mid 所指数组不等于target时left右移,mid又变成