剑指Offer 53-I. 在排序数组中查找数字I
方法一:二分法
排序数组 nums 中的所有数字 target 形成一个窗口,记窗口的 左 / 右边界 索引分别为 left 和 right ,分别对应窗口左边 / 右边的首个元素。
本题要求统计数字 target 的出现次数,可转化为:使用二分法分别找到 左边界 left 和 右边界 right ,易得数字 targettarget 的数量为 right - left - 1 。
对于左边界,实际上是要找第一个大于等于target的数;对于右边界则是要找第一个大于target的数。
左边界,因为是左,所以当找到target时并不会停下来,而是让right继续等于mid - 1.
1 /** 2 * @param {number[]} nums 3 * @param {number} target 4 * @return {number} 5 */ 6 var search = function(nums, target) { 7 let ans = 0; 8 const leftIndex = binarySearch(nums, target, true); 9 const rightIndex = binarySearch(nums, target, false) - 1; 10 if(leftIndex <= rightIndex && rightIndex < nums.length && nums[leftIndex] == target && nums[rightIndex] == target) { 11 ans = rightIndex - leftIndex + 1; 12 } 13 return ans; 14 }; 15 16 /** 17 * @param {number[]} nums 18 * @param {number} target 19 * @param {boolean} lower 20 * @return {number} 21 */ 22 var binarySearch = function(nums, target, lower) { 23 let left = 0, right = nums.length - 1, ans = nums.length;//可能是针对数组长度为1时的情况 24 while(left <= right) { 25 const mid = Math.floor((left + right) / 2); 26 if(nums[mid] > target || (lower && nums[mid] >= target)) { 27 right = mid - 1; 28 ans = mid; 29 }else { 30 left = mid + 1; 31 } 32 } 33 return ans; 34 }
或者
1 class Solution { 2 public int search(int[] nums, int target) { 3 // 搜索右边界 right 4 int i = 0, j = nums.length - 1; 5 while(i <= j) { 6 int m = (i + j) / 2; 7 if(nums[m] <= target) i = m + 1; 8 else j = m - 1; 9 } 10 int right = i; 11 // 若数组中无 target ,则提前返回 12 if(j >= 0 && nums[j] != target) return 0; 13 // 搜索左边界 right 14 i = 0; j = nums.length - 1; 15 while(i <= j) { 16 int m = (i + j) / 2; 17 if(nums[m] < target) i = m + 1; 18 else j = m - 1; 19 } 20 int left = j; 21 return right - left - 1; 22 } 23 }

浙公网安备 33010602011771号