二分搜索的变形
总结一下:
1、数组中的数不重复,最简单的情况
1、最普通的二分查找:leetcode704 /** * 二分查找:nums 中的所有元素是不重复的 */ class Solution { public int search(int[] nums, int target) { int left = 0, right = nums.length - 1; // 左闭右闭 while (left < right) { int mid = left + ((right - left) >> 1); if (nums[mid] == target) return mid; else if (nums[mid] > target) { right = mid - 1; } else { left = mid + 1; } } // 终止条件left == right,后面就不用混淆ans究竟用left还是right了 // nums[left]还未判断 return nums[left] == target? left: -1; } }
2、二分查找:寻找第一个等于target和最后一个等于target的元素 leetcode34(数组中的元素有重复)
class Solution { public int[] searchRange(int[] nums, int target) { if (nums == null || nums.length == 0) return new int[]{-1, -1}; return new int[]{firstEquals(nums, target), lastEquals(nums, target)}; } // 寻找第一个等于target的元素 public int firstEquals(int[] nums, int target) { int left = 0, right = nums.length - 1; // 左闭右闭 while (left < right) { int mid = left + ((right - left) >> 1); // 向下取整 if (nums[mid] == target) { right = mid; // [target target] } else if (nums[mid] > target) { right = mid; // [2 2] target = 1 宁可少缩放一点,也不能越界,不能写成mid-1 } else { left = mid + 1; } } // 特判 nums[left] if (nums[left] == target && (left == 0 || nums[left-1] < target)) return left; return -1; // 没找到 } // 寻找最后一个等于target的元素 public int lastEquals(int[] nums, int target) { int left = 0, right = nums.length - 1; // 左闭右闭 while (left < right) { int mid = left + ((right - left + 1) >> 1); // 向上取整 if (nums[mid] == target) { // [target target] left = mid; } else if (nums[mid] > target) { right = mid - 1; } else if (nums[mid] < target) { left = mid; // // [2 2] target = 3 宁可少缩放一点,也不能越界,不能写成mid+1 } } if (nums[left] == target && (left == nums.length - 1 || nums[left+1] > target)) return left; return -1; // 没找到 } }
3、查找第一个大于等于给定值的元素 leetcode35
class Solution { public int firstLargeOrEquals(int[] nums, int target) { int left = 0, right = nums.length - 1; // 左闭右闭 while (left < right) { int mid = left + ((right - left) >> 1); // 向下取整 if (nums[mid] < target) { left = mid + 1; } else { right = mid; // 查找大于等于给定元素 mid属于解空间 } } if (nums[left] >= target && (left == 0 || nums[left-1] < target)) return left; // 大于等于给定元素 return -1; // 没找到说明都比target小 (有的题目会让 放到最后即可) } }
4、查找最后一个小于等于给定值的元素
private int lastLessOrEquals(int[] arr, int target) { int l = 0, r = arr.length - 1; while (l < r) { int mid = l + ((r - l + 1) >> 1); // 向上取整 if (arr[mid] > target) r = mid - 1; else l = mid; // 查找小于等于target的位置, } if (arr[l] <= target && (l == arr.length - 1 || arr[l + 1] > target)) return l; // <= return -1; // 没找到说明都比target大 (有的题目会让 放到第一个位置) }