"Power button" on 34 questions: Find the elements in the sorted array in the first and last position (binary search)

"Power button" on 34 questions: Find the elements in the sorted array in the first and last position

Topics address

Video explain address

This question requires us to an ordered array numsto find the target element in the targetemergence of the first and last position. If the target element does not appear in an ordered array, considered the start and end positions, respectively -1and -1.

Method One: violence to solve (Brute Force)

One way is easy to think of the solution is violence, we only need to traverse from beginning to end once the array, we can find the first position and the last position of the target elements appear. According to the meaning of problems, we think that the most general case, the number is strictly less than the first encounter target, then the number of encounters are equal to targetthe number of the last encountered are strictly greater than target.

  • So if we can traverse start, check to traverse the elements equal target, just equal encountered targetwhen recording the current location;
  • Then went traversal, traverse to check whether the elements are not equal target, not equal to just encounter targetwhen recording previous location to the current location.

The time complexity of this algorithm is O ( N ) O (N) , does not meet the requirements of the subject. Here we look at the code.

Java code:

public class Solution {

    public int[] searchRange(int[] nums, int target) {
        int[] targetRange = new int[]{-1, -1};

        int len = nums.length;
        if (len == 0) {
            return targetRange;
        }

        for (int i = 0; i < len; i++) {
            if (nums[i] == target) {
                targetRange[0] = i;
                break;
            }
        }

        // 连第 1 个位置都没有找到,说明已经遍历完整个数组了
        if (targetRange[0] == -1) {
            return targetRange;
        }

        for (int i = targetRange[0] + 1; i < len; i++) {
            if (nums[i] != target) {
                targetRange[1] = i - 1;
                break;
            }
        }

        if (targetRange[1] == -1) {
            targetRange[1] = len - 1;
        }
        return targetRange;
    }
}

explain:

  • First create a two-element integer array targetRange, the initialization value [-1, -1], then the length of the array is assigned to a variable len, when the length of the array is equal to 0time, direct return targetRange;

  • Then from the labeled 0traversing the place, as long as the equivalent to find targetthe elements, it will be targetRangethe subscript 0of that element assigned to i, and then exit the loop;

  • One thing to note here is: if in the course of the entire traversal, targetRange[0]have not been re-assigned, it shows that the target element targetin an ordered array numsdoes not exist, the remains will be targetRangereturned to;

  • Then we target element from the position of the first occurrence of targetRange[0]traversing the next position, as long as the detected elements are not equal target, recording its previous location and will targetRange[1]assigned to i - 1, and then you can exit the loop.

  • Also pay attention to detail that, if the target element in the last position just ordered array, in fact, the body of the loop is simply no way to be executed, so you can make a final judgment, if targetRange[1]not yet been assigned, put it assigned to the last position in the array.

Method Two: binary search

Here we look at how to use binary search to find the start and end positions of the target element in an ordered array.

  • The basic idea of binary search is: a look at the range of values of the elements in the range of intermediate positions of nums[mid]the target element targetsize relationship, and then decide which part of the target value falls in.

  • For this question, find the biggest difference with the common problem of dichotomy is that the target element targetis likely to exist in a more orderly array;

  • And when we use binary search value in an intermediate position of the element method to see nums[mid]exactly equal to the target element targetwhen the need to continue to find it, but this time is relatively easy to fall into the error linear search, the correct approach is to continue binary search .


  • Obviously, the position of the target element must appear the first time can not be strictly less than targetthe position of the element, according to the analysis solution before the violence, the position of the target element appears 1st is strictly less than targetthe boundary position of the element, so we this dichotomy boundary can be found by using this idea;

  • Symmetrically, the position of the target element must appear last 1 can not be strictly greater than targetthe position of elements, the position of the last occurrence of the target element 1 is strictly greater than targetthe boundary position of the element, so we can use this idea by dichotomy find the boundary.

Here we look at the code:

Java code:

public class Solution {

    public int[] searchRange(int[] nums, int target) {
        int len = nums.length;
        if (len == 0) {
            return new int[]{-1, -1};
        }

        int firstPosition = findFirstPosition(nums, target);
        if (firstPosition == -1) {
            return new int[]{-1, -1};
        }

        int lastPosition = findLastPosition(nums, target);
        return new int[]{firstPosition, lastPosition};
    }

    private int findFirstPosition(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            int mid = (left + right) >>> 1;
            // 小于一定不是解
            if (nums[mid] < target) {
                // 下一轮搜索区间是 [mid + 1, right]
                left = mid + 1;
            } else {
                right = mid;
            }
        }

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

    private int findLastPosition(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            int mid = (left + right + 1) >>> 1;
            // 大于一定不是解
            if (nums[mid] > target) {
                // 下一轮搜索区间是 [left, mid - 1]
                right = mid - 1;
            } else {
                left = mid;
            }
        }
        return left;
    }
}
  • First is still assign to a variable length of the array len;

  • Then make a judgment Laid: when the length of the array 0when the direct return [-1 , -1];

  • Next, we find the first half of targetthe position of the first occurrence, and we put it into a package private method findFirstPosition:

    • Initializes the left border left = 0and right border right = len - 1, represents the left and right borders of the range to be searched;
    • Next constantly binary search target element, we can continue the cycle conditions written while (left < right)note written here is strictly less than this is a relatively common wording, its idea is to meet the requirements of the elements to make a judgment on the final benefits are there must exit the cycle time left == rightset up, we do not consider in the end should return leftor return rightof. However, such an approach has several places to note, we will immediately mention.
    • Then the code is calculated at an intermediate position of the subject int mid = left + (right - left) / 2;
    • According to the analysis just when nums[mid] < targetthe time, midas well as midall the elements on the left is definitely not targetthe first occurrence of a position, and therefore the elements of the next round we will be in search [mid + 1, right], and therefore, the left margin is set mid + 1;
    • Next is nums[mid] < targetthe opposite, nums[mid] >= targetthis time searching interval is ifthe opposite of this branch of the search space, that is [left, mid], we have to verify: If we see a number strictly greater than target, targetthe first occurrence of a certain position appears to the left of this number; If we see a number exactly equal target, it is possible that the first occurrence of a position, there may targetoccur the first one position to the left of it, but this will not in the right position, so that the next round of the search interval is [left, mid]There is no problem, then you need to set the right boundary right = mid;
    • In exiting the loop when there is a next target element left(or is rightthis time equal to their value) did not see, because the title says, the target element there may not exist in the array, therefore, need to do it again alone judgment, this step is called post-processing.
    • If nums[left] == targetthe subscript position leftis the targetposition of the first occurrence of otherwise -1.
  • Symmetrically, we look to write targetcode for the last occurrence of the position.

    • First, it is certain that, if in the lookup targetposition of the first occurrence of the time, we did not find target, in the Find targetposition of last occurrence, we certainly will not find this number, so you can do a special judge ;

    • findLastPositionThe structure and the findFirstPositionlike, we directly copy down, you need to change that ifand elselogic, based on an analysis earlier, when nums[mid] > targetthe time, midand midall the elements on the right is definitely not targetthe last one where they appear, so the next element of a search on in certain [left, mid - 1], therefore, the right boundary set mid - 1;

    • Next is nums[mid] > targetthe opposite, nums[mid] <= targetthis time searching interval is ifthe opposite of this branch of the search space, that is [mid, right], we have to verify: If we see a number strictly less than target, targetappeared last a certain position appears to the right of this number; If we see a number exactly equal target, it may appear that the last one position, there may targetappear the last one in its right position, but must not be left in this position, therefore, is to search for the next round of the interval [mid, right]There is no problem, then you need to set the left margin left = mid;

    • This time to pay special attention to is this: Once you see left = midwith right = mid - 1this boundary in a binary search shrinkage behavior, we need to take time in the middle of the number, make some small adjustments, that is, in this parenthesis Riga 1:int mid = left + (right - left + 1) / 2;

    • The reason is this: /is an integer division, that the default rounding behavior is rounded down, ie (3 + 4) / 2 = 3. When we use the original wording, midnever fail to get right, and the boundary is shrinking left = midwith right = mid - 1time, we draw a diagram of it this way, when the search range to be only two elements, since the intermediate never fail to get the right number we found that interval inseparable, at this time, once this code executes a branch to either the left border or right border will not consider the middle, then the code into an infinite loop;

    • To solve this problem, in fact I have just said, we need to take the middle number when the next integer division rounding behavior change on rounding, namely in parentheses Riga 1, although this rounding behavior changes require only last only the remaining two elements of time to make, but we just let the whole take on the whole is not the problem;

    • This one is a summary of the experience, but also people in the use of gradually summed up, in fact, this process is not difficult to find, we only need to print out in the proceedings at the time of infinite loop left, rightand midvalues, it is easy to identify problems and think of a solution;

    • In exiting the loop when there is there is still a subject of the next element left(or is rightthis time their values are equal) did not see. However, we note that, in fact, the code can be executed here, it is not that, targetin numsa certain presence, take a look at our previous judgment. Therefore, we have no need to judge nums[left]whether or not equal target, then leftthe value is necessarily targetin an orderly array numsappeared in the last 1 index.

Debugging code:

Java code:

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int len = nums.length;
        if (len == 0) {
            return new int[]{-1, -1};
        }

        int firstPosition = findFirstPosition(nums, target, len);
        if (firstPosition == -1) {
            return new int[]{-1, -1};
        }

        int lastPosition = findLastPosition(nums, target, len);
        return new int[]{firstPosition, lastPosition};
    }

    private int findLastPosition(int[] nums, int target, int len) {
        int left = 0;
        int right = len - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            System.out.println("left = " + left + ", mid = " + mid + ", right = " + right);
            
            // 严格大于 target 的时候不是解
            if (nums[mid] > target) {
                // 下一轮搜索的区间是 [left, mid - 1]
                System.out.println("下一轮搜索的区间是 [left, mid - 1]");
                right = mid - 1;
            } else {
                System.out.println("下一轮搜索的区间是 [mid, right]");
                // [mid, right]
                left = mid;
            }
        }
        return left;
    }

    private int findFirstPosition(int[] nums, int target, int len) {
        int left = 0;
        int right = len - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            // 严格小于 target 的时候不是解
            if (nums[mid] < target) {
                // 下一轮搜索的区间是 [mid + 1, right]
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        if (nums[left] == target) {
            return left;
        }
        return -1;
    }
}
发布了442 篇原创文章 · 获赞 330 · 访问量 123万+

Guess you like

Origin blog.csdn.net/lw_power/article/details/104066739