模板
int binary_search(int[] nums, int target) { int left = 0, right = nums.length - 1; while(left <= right) { int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid + 1; } else if (nums[mid] > target) { right = mid - 1; } else if(nums[mid] == target) { // 直接返回 return mid; } } // 直接返回 return -1;}int left_bound(int[] nums, int target) { int left = 0, right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid + 1; } else if (nums[mid] > target) { right = mid - 1; } else if (nums[mid] == target) { // 别返回,锁定左侧边界 right = mid - 1; } } // 最后要检查 left 越界的情况 if (left >= nums.length || nums[left] != target) return -1; return left;}int right_bound(int[] nums, int target) { int left = 0, right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid + 1; } else if (nums[mid] > target) { right = mid - 1; } else if (nums[mid] == target) { // 别返回,锁定右侧边界 left = mid + 1; } } // 最后要检查 right 越界的情况 if (right < 0 || nums[right] != target) return -1; return right;}
- 其中int mid = left + (right - left) / 2; 等价于(left + right) / 2,但防止了left + right过大产生溢出。
- 以上是[left, right]搜索区间,right初始化为nums.length - 1,缩小范围时,left = mid +1 或 right = mid - 1; while的判断条件为left <= right,否则会漏掉一个。
- 倘若是[left, right)搜索区间,right初始化为nums.length,缩小范围时,left = mid - 1 或 right = mid; while的判断条件是left < right,因为左闭右开,此时只夹着一个元素,等于的时候搜索区间就为空了。
- 如果是搜索左右边界,则判断nums[mid] == target后,不直接返回,而是继续缩小搜索区间。当退出循环时,搜索下标越界或最终没找到(夹到的位置不是target)返回-1。
例题
class Solution { public int[] searchRange(int[] nums, int target) { if (nums == null || nums.length == 0) return new int[]{-1, -1}; int leftBound = 0, rightBound = 0; // Find left bound int left = 0, right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; // 等于的时候,right继续向左缩小搜索范围 if (nums[mid] >= target) right = mid - 1; else if (nums[mid] < target) left = mid + 1; } if (left > nums.length - 1 || nums[left] != target) return new int[]{-1, -1}; leftBound = left; // Find right bound left = 0; right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] <= target) left = mid + 1; else if (nums[mid] > target) right = mid - 1; } if (right < 0 || nums[right] != target) return new int[]{-1, -1}; rightBound = right; return new int[]{leftBound, rightBound}; }}
基本就是按照上面的模板分别算出左右边界然后返回。