• LeetCode高频题34. 在排序数组中查找元素的第一个和最后一个位置


    LeetCode高频题34. 在排序数组中查找元素的第一个和最后一个位置

    提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目
    互联网大厂们在公司养了一大批ACM竞赛的大佬们,吃完饭就是设计考题,然后去考应聘人员,你要做的就是学基础树结构与算法,然后打通任督二脉,以应对波云诡谲的大厂笔试面试题!
    你要是不扎实学习数据结构与算法,好好动手手撕代码,锻炼解题能力,你可能会在笔试面试过程中,连题目都看不懂!比如华为,字节啥的,足够让你读不懂题
    在这里插入图片描述


    题目

    给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

    如果数组中不存在目标值 target,返回 [-1, -1]。

    你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

    来源:力扣(LeetCode)
    链接:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


    一、审题

    示例 1:

    输入:nums = [5,7,7,8,8,10], target = 8
    输出:[3,4]
    示例 2:

    输入:nums = [5,7,7,8,8,10], target = 6
    输出:[-1,-1]
    示例 3:

    输入:nums = [], target = 0
    输出:[-1,-1]

    提示:

    0 <= nums.length <= 105
    -109 <= nums[i] <= 109
    nums 是一个非递减数组
    -109 <= target <= 109


    二、解题

    比如arr中找6
    6的开头结尾位置6–8
    找不到-1,-1
    在这里插入图片描述

    算法原型:在有序数组中,二分查找>=x,最左位置,<=x最右位置

    在有序数组arr中
    找>=x最左的位置【满足条件,记录当前位置i,使劲往左搜】
    如果找到中间位置[M]<x,说明x在M右边,下次让L=M+1
    如果找到中间位置[M]>=x,可能M左边还有>=x的呢,先记下当前达标位置i=M,下次让R=M-1
    直到L>R停止搜索

    在这里插入图片描述
    手撕代码:

            //算法原型:
            //找>=x最左的位置【满足条件,记录当前位置i,使劲往左搜】
            //如果找到中间位置[M]<x,说明x在M右边,下次让L=M+1
            //如果找到中间位置[M]>=x,可能M左边还有>=x的呢,先记下当前达标位置i=M,下次让R=M-1
            //直到L>R停止搜索
            public static int findBigEqual(int[] arr, int L, int R, int x){
                int i = -1;//默认没有
                while (L <= R){
                    int M = L + ((R - L) >> 1);
                    if (arr[M] < x) L = M + 1;
                    else {
                        i = M;
                        R = M - 1;//使劲往左找
                    }
                }
    
                return i;
            }
    
            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    找<=x最右的位置【满足条件,记录当前位置j,使劲往右搜】
    可以二分查找
    如果找到中间位置[M]<=x,可能M右边还有<=x的呢,先记下当前达标位置j=M,下次让L=M+1
    如果找到中间位置[M]>x,说明x在M左边,下次让R=M-1
    直到L>R停止搜索
    在这里插入图片描述
    手撕代码:

    //找<=x最右的位置【满足条件,记录当前位置j,使劲往右搜】
            //可以二分查找
            //如果找到中间位置[M]<=x,可能M右边还有<=x的呢,先记下当前达标位置j=M,下次让L=M+1
            //如果找到中间位置[M]>x,说明x在M左边,下次让R=M-1
            //直到L>R停止搜索
            public static int findLessEqual(int[] arr, int L, int R, int x){
                int i = -1;//默认没有
                while (L <= R){
                    int M = L + ((R - L) >> 1);
                    if (arr[M] > x) R = M - 1;
                    else{
                        i = M;
                        L = M + 1;//使劲往右找
                    }
                }
    
                return i;
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    本题就利用上面这个算法原型,这还是非常非常简单的

    比如找target=6
    (1)则找<=6的最右的位置R
    (2)找>=6最左的位置L

    看看LR不是-1,就是找到了,再看L<=R而且L处是target,R处也是target的话,绝对完美L–R就是结果
    否则就没有
    手撕代码

    
    
            public int[] searchRangeReview(int[] nums, int target) {
                //比如找target=6
                if (nums == null || nums.length == 0) return new int[] {-1, -1};
    
                int N = nums.length;
                int[] ans = new int[2];//0左边界,1右边界
                ans[0] = -1;
                ans[1] = -1;//,默认没有
    
                //(2)找>=6最右的位置R
                int L = findBigEqual(nums, 0, N - 1,target);
                //(1)则找<=6的最右的位置i
                int R = findLessEqual(nums, 0, N - 1, target);
    
                //反正L和R要么同时为-1,要么不会为-1
                //你看看ij处是6吗?是就是j--i,//否则就是i-1,j+1
                if (L != -1 && R != -1){
                    ans[0] = L <= R && nums[L] == target ? L : -1;
                    ans[1] = L <= R && nums[R] == target ? R : -1;
                }
    
                return ans;
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    绝对完美
    测试一把:

        public static void test(){
            int[] arr = {5,7,7,8,8,10};
            int target = 7;
            Solution solution = new Solution();
            int[] res = solution.searchRange(arr, target);
            System.out.print(res[0] + " " + res[1]);
            System.out.println();
    
            res = solution.searchRangeReview(arr, target);
            System.out.print(res[0] + " " + res[1]);
        }
    
        public static void main(String[] args) {
            test();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1 2
    1 2
    
    • 1
    • 2

    LeetCode测试:
    在这里插入图片描述
    绝对碉堡
    在这里插入图片描述


    总结

    提示:重要经验:

    1)算法原型:在有序数组中,二分查找>=x,最左位置,<=x最右位置,使劲朝着一边找,之前记录已经找到的位置i
    2)比如找target(1)则找<=6的最右的位置R,(2)找>=6最左的位置L,如果LR不是-1,必然L<=R,必然就是找到了的
    3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。

  • 相关阅读:
    天锐绿盾加密软件——企业数据防泄密-CAD图纸、文档、源代码加密管理系统@德人合科技
    linux下日志查看命令
    jieba.posseg是jieba中的一个组件,它用于对文本进行词性标注
    java微信小程序 ssm电动车智能充电系统
    CockroachDB集群部署
    Java :职责链模式
    卷积神经网络(CNN)理解
    Hutool的BeanUtil.copyProperties() 的改进详情
    浙大工商管理硕士(MBA)创客班适合哪些人群申请报考?
    js 事件参考
  • 原文地址:https://blog.csdn.net/weixin_46838716/article/details/125434985