Leetcode: Search for a Range

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所停的位置正好是目标数的后面和前面。

 1 public class Solution {

 2     public int[] searchRange(int[] A, int target) {

 3         int start = 0, end = A.length - 1;

 4         int[] result = new int[2];

 5         result[0] = -1;

 6         result[1] = -1;

 7         if(A==null || A.length==0)

 8         {

 9             return result;

10         }

11         int middle = search(A, start, end, target, result);

12         if (middle == -1) return result;

13         result[0] = searchleft(A, 0, middle, target);

14         result[1] = searchright(A, middle, A.length-1, target);

15         return result;

16     }

17     

18     public int search(int[] A, int start, int end, int target, int[] result) {

19         int mid = -1;

20         if (start <= end) {

21             mid = (start + end) / 2;

22             if (A[mid] == target) {

23                 result[0] = mid;

24                 result[1] = mid;

25                 return mid;

26             }

27             else if (A[mid] < target) {

28                 start = mid + 1;

29                 return search(A, start, end, target, result);

30             }

31             else {

32                 end = mid - 1;

33                 return search(A, start, end, target, result);

34             }

35         }

36         else {

37             result[0] = -1;

38             result[1] = -1;

39             return mid;

40         }

41         

42     }

43     

44     public int searchleft(int[] A, int start, int end, int target) {

45         if (start > end) return start;

46         int mid = (start + end) / 2;

47         if (A[mid] < target) {

48             start = mid + 1;

49             return searchleft(A, start, end, target);

50         }

51         else {

52             end = mid - 1;

53             return searchleft(A, start, end, target);

54         }

55     }

56     

57     public int searchright(int[] A, int start, int end, int target) {

58         if (start > end) return end;

59         int mid = (start + end) / 2;

60         if (A[mid] <= target) {

61             start = mid + 1;

62             return searchright(A, start, end, target);

63         }

64         else {

65             end = mid - 1;

66             return searchright(A, start, end, target);

67         }

68     }

69 }

上述两个子函数searchLeft和searchRight其实都可以不用递归,用迭代来写:(这是本题的精髓和难点所在), 跟Search Insert Position这个问题的方法一样,这道题可以认为是在找一个比target略小的目标数(因为等于target的时候移动的是右边缘),这个目标数在A中不存在,所以当循环结束时候,l, r分别处在目标数的后面和前面。如果我们找的是左边缘,那么这个左边缘应该是在目标数右边,所以就是l所处的位置

 1     public int findLeft(int[] A, int target, int right) {

 2         int l = 0;

 3         int r = right;

 4         while (l <= r) {

 5             int m = (l + r) / 2;

 6             if (A[m] == target) {

 7                 r = m - 1;

 8             }

 9             else {

10                 l = m + 1;

11             }

12         }

13         return l;

14     }

15     

16     public int findRight(int[] A, int target, int left) {

17         int l = left;

18         int r = A.length - 1;

19         while (l <= r) {

20             int m = (l + r) / 2;

21             if (A[m] == target) {

22                 l = m + 1;

23             }

24             else {

25                 r = m - 1;

26             }

27         }

28         return r;

29     }

整体如果想用iterative的方法来写:

 1 public class Solution {

 2     public int[] searchRange(int[] A, int target) {

 3         int[] res = new int[2];

 4         res[0] = -1;

 5         res[1] = -1;

 6         if(A==null || A.length==0)

 7         {

 8             return res;

 9         }

10         int l=0;

11         int r=A.length-1;

12         int m=(l+r)/2;

13         while(l<=r)

14         {

15             m=(l+r)/2;

16             if(A[m]==target)

17             {

18                 res[0]=m;

19                 res[1]=m;

20                 break;

21             }

22             else if(A[m]>target)

23             {

24                 r = m-1;

25             }

26             else

27             {

28                 l = m+1;

29             }

30         }

31         if(A[m]!=target)

32             return res;

33         int newL = m;

34         int newR = A.length-1;

35         while(newL<=newR)

36         {

37             int newM=(newL+newR)/2;

38             if(A[newM]==target)

39             {

40                 newL = newM+1;

41             }

42             else

43             {

44                 newR = newM-1;

45             }            

46         }

47         res[1]=newR;

48         newL = 0;

49         newR = m;

50         while(newL<=newR)

51         {

52             int newM=(newL+newR)/2;

53             if(A[newM]==target)

54             {

55                 newR = newM-1;

56             }

57             else

58             {

59                 newL = newM+1;

60             }            

61         }

62         res[0]=newL;        

63         

64         return res;

65         

66     }

67 }

 

你可能感兴趣的:(LeetCode)