Given a sorted array of integers, find the starting and ending position of a given target value. Your algorithm's runtime complexity must be in the order of O(log n). If the target is not found in the array, return [-1, -1]. For example, Given [5, 7, 7, 8, 8, 10] and target value 8, return [3, 4].
Analysis: 这道题是二分查找Search Insert Position的变体,思路并不复杂,就是先用二分查找找到其中一个target,然后再往左右找到target的边缘。找边缘的方法跟二分查找仍然是一样的,只是相等的情况依然要往左找(找左边缘)或往右找(找右边缘)。这样下来总共进行了三次二分查找,所以算法的时间复杂度仍是O(logn),空间复杂度是O(1)。
Notice: 对停止的边界条件极不熟悉,需要总结,参见Binary Search的Summary
本题的精髓和难点在于寻找左右边沿,方法是Binary Search的变体,只不过这次是要左右相遇。以找左边缘为例,while循环里要么A[m] < target, l 跳到m+1, 要么A[m]==target, r 跳到m-1, 直到l > r为止,这时候l所在的位置就是要求的左边缘。而如果是找右边缘,l > r之后,r所在位置就是要求的右边缘。l和r所停的位置正好是目标数的后面和前面。
找左边沿可以认为是在找一个比target略小的目标数(因为等于target的时候移动的是右边缘),这个目标数在A中不存在,所以当循环结束时候,l, r分别处在目标数的后面和前面。如果我们找的是左边缘,那么这个左边缘应该是在目标数右边,所以就是l所处的位置
整体如果想用iterative的方法来写:
两次binary search, 一次找左边缘,一次找右边缘, be carefule of line 12, r有可能<0
1 public class Solution { 2 public int[] searchRange(int[] nums, int target) { 3 int[] res = new int[]{-1, -1}; 4 if (nums==null || nums.length==0) return res; 5 int l=0, r=nums.length-1; 6 int m = l + (r-l)/2; 7 while (l <= r) { // find right edge 8 m = l + (r-l)/2; 9 if (nums[m] <= target) l = m + 1; 10 else r = m - 1; 11 } 12 if (r<0 || nums[r] != target) return res; 13 else res[1] = r; 14 15 l = 0; 16 //no need to set r = nums.length - 1, because r is already at right place 17 while (l <= r) { 18 m = l + (r-l)/2; 19 if (nums[m] < target) l = m + 1; 20 else r = m - 1; 21 } 22 res[0] = l; 23 return res; 24 } 25 }