LeetCode – Search for a Range (Java)

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

Based on the requirement of O(log n), this is a binary search problem apparently.

Java Solution

public int[] searchRange(int[] nums, int target) {
    if(nums == null || nums.length == 0){
        return null;
    }
 
    int[] arr= new int[2];
    arr[0]=-1;
    arr[1]=-1;
 
    binarySearch(nums, 0, nums.length-1, target, arr);
 
    return arr;
}
 
public void binarySearch(int[] nums, int left, int right, int target, int[] arr){
    if(right<left) 
        return;
 
    if(nums[left]==nums[right] && nums[left]==target){
        arr[0]=left;
        arr[1]=right;
        return;
    }
 
    int mid = left+(right-left)/2;
 
 
    if(nums[mid]<target){
        binarySearch(nums, mid+1, right, target, arr);
    }else if(nums[mid]>target){
        binarySearch(nums, left, mid-1, target, arr);
    }else{
        arr[0]=mid;
        arr[1]=mid;
 
        //handle duplicates - left
        int t1 = mid;
        while(t1 >left && nums[t1]==nums[t1-1]){
            t1--;
            arr[0]=t1;
        }
 
        //handle duplicates - right
        int t2 = mid;
        while(t2 < right&& nums[t2]==nums[t2+1]){
            t2++;
            arr[1]=t2;
        }
        return;
    }
}
Category >> Algorithms >> Interview  
If you want someone to read your code, please put the code inside <pre><code> and </code></pre> tags. For example:
<pre><code> 
String foo = "bar";
</code></pre>

  1. Mark Law on 2015-4-26

    this solution above time complexity is not log N, it clearly is N, which does not match the requirements.

  2. Vijaya on 2015-4-28

    We can use below code which has O(log N) complexity. This is initial structure, we can even modify further to clean it. (This is C# code)

    public int[] searchRange(int[] nums, int target)
    {
    int[] result = new int[2];
    int startIndex = 0;
    int endIndex = nums.Length – 1;
    int mid = -1;
    bool foundTarget = false;

    if (nums.Length > 0)
    {
    while (startIndex < endIndex)
    {
    mid = (startIndex + endIndex)/2;

    if (target == nums[mid])
    {
    foundTarget = true;
    break;
    }

    if (target nums[mid])
    startIndex = mid+1;
    }

    if (foundTarget)
    {
    startIndex = mid;
    endIndex = mid;

    while ((startIndex – 1) >= 0 && (nums[startIndex – 1] == target))
    startIndex–;

    while ((endIndex + 1) <= nums.Length && (nums[endIndex + 1] == target))
    endIndex++;

    result[0] = startIndex;
    result[1] = endIndex;
    }
    }

    return result;
    }

  3. Jason Zhu on 2015-6-21

    What’s wrong with the above examplary solution? The question has explicitly required the time complexity to be O(logN), which obviously is not the correct answer.


    public static int[] solution(int[] arr, int target, int left, int right) {
    //parameter check
    if(arr == null || arr.length == 0) return new int[]{-1, -1};

    //boundary check
    if(left > right) return new int[]{-1, -1};

    int mid = (left+right)/2;
    if(arr[mid] target) return solution(arr, target, left, right-1);
    else {
    int[] leftRange = solution(arr, target, left, mid-1);
    int[] rightRange = solution(arr, target, mid+1, right);
    int leftEnd = (leftRange[0] == -1 ? mid : leftRange[0]);
    int rightEnd = (rightRange[1] == -1 ? mid : rightRange[1]);
    return new int[]{leftEnd, rightEnd};
    }
    }

    public static void main(String[] args) {
    System.out.println(Arrays.toString(solution(new int[]{1,8,8,8,9}, 8, 0, 4)));
    System.out.println(Arrays.toString(solution(new int[]{1,2,8,8,8,9}, 8, 0, 5)));
    System.out.println(Arrays.toString(solution(new int[]{1,2,3,8,8,8,9}, 8, 0, 6)));
    System.out.println(Arrays.toString(solution(new int[]{1,2,3,4,8,8,8,9}, 8, 0, 7)));
    System.out.println(Arrays.toString(solution(new int[]{1,2,3,4,5,8,8,9}, 8, 0, 7)));
    System.out.println(Arrays.toString(solution(new int[]{1,2,3,4,5,6,8,9}, 8, 0, 7)));
    System.out.println(Arrays.toString(solution(new int[]{1,2,3,4,8,8,8,9}, 7, 0, 7)));
    }

  4. Gdragon on 2015-10-30

    Great answer! But you should make the change from right – 1 to mid – 1 in:

    else if(arr[mid] > target) return solution(arr, target, left, mid-1);

  5. Suresh on 2016-8-12

    True… I got the same doubt when I saw those two loops.

  6. lekzeey on 2016-10-9

    I think the solution is fine, because the number of work required to find the left and right border using binary search is just the same as finding the element itself and scanning for the left and right borders.

  7. Sumit on 2017-1-26

    The solution given is O(N) and not O(logN). Consider the example {1,6,6,6,6,6,6,6,6,6,6,8}. It will have to do operations N times here.
    In order to find the left and the right indices you would need to do the binary search again one for left side and other for right side of the mid if the value at mid equals the target. Below is my iterative code solution:


    public class Solution {
    public int[] searchRange(int[] nums, int target) {
    int out[]=new int[2];
    int l=0,r=nums.length-1;
    while(l<=r){
    int mid=(l+r)/2;
    if(nums[mid]==target){
    if(mid-1<0 || nums[mid-1]=nums.length || nums[mid+1]>target){
    out[1]=mid;
    }
    else{
    out[1]=rBSearch(nums,mid+1,target);
    }
    return out;
    }
    else if(nums[mid]>target){
    r=mid-1;
    }
    else{
    l=mid+1;
    }
    }
    out[0]=-1;
    out[1]=-1;
    return out;
    }

    private int lBSearch(int nums[],int end,int target){
    int l=0,r=end;
    while(l<=r){
    int mid=(l+r)/2;
    if(nums[mid]==target){
    if(mid-1<0 || nums[mid-1]<target){
    return mid;
    }
    else{
    r=mid-1;
    }
    }
    else{
    l=mid+1;
    }
    }
    return end;
    }

    private int rBSearch(int nums[],int start,int target){
    int l=start,r=nums.length-1;
    while(l=nums.length || nums[mid+1]>target){
    return mid;
    }
    else{
    l=mid+1;
    }
    }
    else{
    r=mid-1;
    }
    }
    return start;
    }
    }

Leave a comment

*