LeetCode finds the first and last position of an element in a sorted array (34 questions)

LeetCode finds the first and last position of an element in a sorted array

@author:Jingdai
@date:2020.11.09

Topic description (34 questions)

Given an integer array in ascending order nums, and a target value target. Find the start and end positions of the given target value in the array.

The time complexity of your algorithm must be O (log n ) level.

If the target value does not exist in the array, return [-1, -1].

  • Sample input

    nums = [5,7,7,8,8,10], target = 8
    
  • Sample output

    [3,4]
    

Ideas

This question is a typical binary search problem, but this is a little different from the most basic binary search problem, that is, the searched number may be repeated, while the general binary search is to find and return directly, here you can’t return directly, because you I don’t know if the value you found is the first, last, or some in the middle.

For there is no repeat basic binary number lookup, the general is to use while(left <= right)to circulate judge found direct return, returns can not be found -1, and here need to slightly improve a little bit. Is not used herein while(left <= right)to cycle, using while(left < right)cyclically determined.

Using while(left <= right)the loop out, left > right, the interval [left, right]length is negative, when the solution must not be out of the loop. Is used while(left < right), the time out of the loop, leftand rightmay be the same, the interval [left, right]length is 1, and if it solvability leftand rightnecessarily the same, the solution is at this time left.

Next, return to this topic, divide the topic into two parts, and find the first position and the last position of the element. First look at how to find the first position of the search element, that is, how to halve the search interval:

  • target == nums[middle]: At this time, it cannot be returned directly, because this is not necessarily the first element. How to narrow the range? To find the first element, the first element or is it middle, or in middlefront, so the middleback section can be ignored. Let now right = middle.
  • target > nums[middle]: This is the same as the basic binary search, let left = middle + 1.
  • target < nums[middle]: Let right = middle - 1.

Look at the entire code snippet that finds the position of the first element:

public int findFisrtIndex(int[] nums, int target) {
     
     

    if (nums == null || nums.length == 0)
        return -1;

    if (nums.length == 1)
        return nums[0] == target ? 0 : -1;

    int left = 0;
    int right = nums.length - 1;
    int middle;

    while (left < right) {
     
     
        middle = left + (right - left) / 2;
        if (target == nums[middle]) {
     
     
            right = middle;
        } else if (target > nums[middle]) {
     
     
            left = middle + 1;
        } else {
     
     
            right = middle - 1;
        }
    }

    if (nums[left] == target)
        return left; 
    return -1;
}

The next step is to find the position of the last element. It's basically the same as the first idea, so I won't explain it, just look at the code behind.

Let me talk about a little more detail here. When writing binary search, if the interval is not correctly divided, it is easy to cause an infinite loop, that is, if the interval cannot be reduced when there are two elements, it will cause an infinite loop. When writing the code to find the last element, middlethe selection method should be rounded up. It cannot be rounded down like finding the position of the first element, otherwise it will cause an infinite loop. Try it on two elements by yourself. Here Note that it is easy to make mistakes.

Code

public int[] searchRange(int[] nums, int target) {
     
     

    int firstIndex = findFisrtIndex(nums, target);
    if (firstIndex == -1)
        return new int[] {
     
     -1, -1}; 
    int lastIndex = findLastIndex(nums, target);
    return new int[] {
     
     firstIndex, lastIndex};
}

public int findFisrtIndex(int[] nums, int target) {
     
     

    if (nums == null || nums.length == 0)
        return -1;

    if (nums.length == 1)
        return nums[0] == target ? 0 : -1;

    int left = 0;
    int right = nums.length - 1;
    int middle;

    while (left < right) {
     
     
        middle = left + (right - left) / 2;
        if (target == nums[middle]) {
     
     
            right = middle;
        } else if (target > nums[middle]) {
     
     
            left = middle + 1;
        } else {
     
     
            right = middle - 1;
        }
    }

    if (nums[left] == target)
        return left; 
    return -1;
}

public int findLastIndex(int[] nums, int target) {
     
     
    if (nums == null || nums.length == 0)
        return -1;

    if (nums.length == 1)
        return nums[0] == target ? 0 : -1;

    int left = 0;
    int right = nums.length - 1;
    int middle;

    while (left < right) {
     
     
        middle = left + (right - left + 1) / 2;
        if (target == nums[middle]) {
     
     
            left = middle;
        } else if (target > nums[middle]) {
     
     
            left = middle + 1;
        } else {
     
     
            right = middle - 1;
        }
    }

    if (nums[left] == target) {
     
     
        return left;
    }
    return -1;
}

summary

Finally, I will write a little summary of this binary search.

  • For the most basic binary search, use while (left <= right)the line, and the problem slightly more complex, with while (left < right)more easily resolved.
  • For binary search is narrow down the range, to clarify how narrow the range at each step (such as the title nums[middle]and targetequal).
  • For interval division, infinite loops are prone to appear when there are two elements left, so when you are not sure whether there will be infinite loops, just bring the situation of the two elements and try it out to see if you need to take rectification. Rounded up.

Guess you like

Origin blog.csdn.net/qq_41512783/article/details/109588198