• 算法图解——查找数组中元素的第一个和最后一个位置( 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....

  • 相关阅读:
    SpringBoot+Vue实现指定账号审批单据时前端进行语音播报
    Jquery中使用JsonP加载本地json文件解决跨域问题
    Android中WebView加载sdcard中的html显示
    Android中WebView加载sdcard中的html时提示:ERR_FILE_NOT_FOUND和ERR_ACCESS_DENIED
    【20220302】育己人
    保序回归问题学习笔记
    可持久化数据结构学习笔记
    WC2022 打不过去年记
    Solution Set 「LOCAL」冲刺省选 Round XI
    Solution Set 「LOCAL」冲刺省选 Round XII
  • 原文地址:https://www.cnblogs.com/gjmhome/p/14402314.html
Copyright © 2020-2023  润新知