算法图解——查找数组中元素的第一个和最后一个位置( Find First and Last Pos of Ele in Array)

1. 题目描述

Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.If target is not found in the array, return [-1, -1].Follow up: Could you write an algorithm with O(log n) runtime complexity?

翻译:

给定按升序排序的整数nums数组,查找给定目标的起始和结束位置值。如果在数组中找不到目标,返回[-1,-1]。后续:是否可以编写运行时复杂度为O(logn)的算法?

2. 示例

示例1:

Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]

示例2:

Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]

示例3:

Input: nums = [], target = 0
Output: [-1,-1]

3. 要求

  • 0 <= nums.length <= 105
  • -109 <= nums[i] <= 109
  • nums is a non-decreasing array【非递减数组】.
  • -109 <= target <= 109

4. 题目解析

看到这个题目中的要求,得知:数组为非递减,且要求复杂度为O(lgN),看到这个,我就想起了二分法查找,但是二分法查找是查找某一位数的,而不是查找多位。

所以,从这里出发其实有一个思路,就是:先用二分查找算法,找到一个等于target的数字的位置下标,然后再在该下标左右遍历,如有相同的数字,则肯定在左右两侧,因为数组是非递减的嘛。

但是,这样的话,复杂度就不是 lgN 了。

那么,该如何求解呢?不知道大家还记不记的C/C++中有一个函数叫 ceil() 和 floor() ,这两个分别是向上向下取整。

同样的思想,我们将target+0.5 和 target-0.5,然后查找这两个值在数组中的位置,找到后,中间夹着的区间就是 target 的所有下标位置。

所以,这题的关键就是实现二分查找算法,哈哈哈,如果hr直接考你二分算法,是不是好low,但是这样一包装就高大上了有木有?

5. 代码如下

class Solution {
    public int[] searchRange(int[] nums, int target) {
        if(nums==null || nums.length<=0){
            return new int[]{-1,-1};
        }
        Arrays.sort(nums);
        int left = binarySearch(nums,target - 0.5f);
        int right = binarySearch(nums,target + 0.5f);
        
        if(left == right){
            return new int[]{-1,-1};
        }else{
            return new int[]{left,right-1};
        }
    }
    
    public int binarySearch(int[] nums, float target){
        int left = 0;
        int right = nums.length-1;
        while(left<right){
            //int mid = left+(right-left)>>1;//这里需要注意,本来是想用移位操作符,但是要考虑计算优先级;
       
int mid = left+((right-left)>>1); if(nums[mid] > target){ right = mid-1; }else{ left = mid+1; /*这里有点疑问,就是如果是等于target,且nums中有多个target时,那么此时left可能是处于中间的target的位置。 这样的话,还要left = mid+1,显然就错过了最左侧target的下标。
          其实,没有必要担心这个问题,因为nums是int型数组,不会等于terget的。
*/ } } } }

 针对上面的疑问,我加了点输出log,debug一下就明白了:

package Top100;

import java.util.Arrays;

class Top1 {
    public static int[] searchRange(int[] nums, int target) {
        if(nums==null || nums.length<=0){
            return new int[]{-1,-1};
        }
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            System.out.printf(nums[i]+" ");
        }
        System.out.println((target - 0.5f)+" "+(target + 0.5f));//4.5,5.5
        int left = binarySearch(nums,target - 0.5f);
        int right = binarySearch(nums,target + 0.5f);
        System.out.println(left+" "+right);
        if(left == right){
            return new int[]{-1,-1};
        }else{
            return new int[]{left+1,right-1};
        }
    }
    
    public static int binarySearch(int[] nums, float target){
        int left = 0;
        int right = nums.length-1;
        while(left<right){
            System.out.println(left+" "+right+" "+((right-left)>>1));
            int mid = left+((right-left)>>1);
            if(nums[mid] > target){
                right = mid-1;
            }else{
                left = mid+1;
            }
        }
        return right;
    }
    
    public static void main(String[] args) {
        int[] nums = {1,3,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,6,8,9};
        int patten = 5;
        int[] ret = searchRange(nums,patten);
        System.out.println(ret[0]+"--"+ret[1]);
    }
}

输出:

1 3 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 6 8 9 4.5 5.5
0 23 11
12 23 5
12 16 2
12 13 0
0 23 11
12 23 5
18 23 2
21 23 1
13 21
14--20

Over....

原文地址:https://www.cnblogs.com/gjmhome/p/14402314.html