首页 > 其他分享 >34. 在排序数组中查找元素的第一个和最后一个位置

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

时间:2024-12-28 19:43:24浏览次数:5  
标签:target nums int res 34 查找 数组 排序 left

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

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

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

示例 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]

思路

1. 遍历法(线性查找)

这种方法是通过遍历整个数组来找到 target 的第一个和最后一个位置,时间复杂度为 O(n),即数组的长度。虽然时间复杂度较高,但对于较小的数组或者不要求最优效率的场景,它是一种简单且直观的解决方案。

实现:

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res = new int[2];
        res[0] = -1;  // 初始化为 -1,表示没有找到
        res[1] = -1;

        // 查找第一个出现的位置
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == target) {
                res[0] = i;
                break;  // 找到第一个出现的位置,退出循环
            }
        }

        // 查找最后一个出现的位置
        for (int i = nums.length - 1; i >= 0; i--) {
            if (nums[i] == target) {
                res[1] = i;
                break;  // 找到最后一个出现的位置,退出循环
            }
        }

        return res;
    }
}

2. 双指针法

在这个方法中,我们使用两个指针,分别从数组的两端向中间靠近,找出第一个和最后一个目标值。这种方法通常用于数组已经排序或者部分有序的情况。时间复杂度为 O(n),比遍历法稍微优化,但仍然不如二分查找高效。

实现:

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res = new int[2];
        res[0] = res[1] = -1;  // 默认返回 -1, -1

        // 从左边开始找到第一个 target
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            if (nums[left] == target) {
                res[0] = left;
                break;
            }
            left++;
        }

        // 从右边开始找到最后一个 target
        left = nums.length - 1;  // 重置 left 指针
        while (left >= 0) {
            if (nums[left] == target) {
                res[1] = left;
                break;
            }
            left--;
        }

        return res;
    }
}

3. 哈希表(Hash Map)

这种方法是使用一个哈希表来存储 target 出现的位置。时间复杂度为 O(n),需要额外的空间来存储位置。如果目标数组中只有一个 target,或者有多个但排序不重要,这种方法可能会有用。然而在这个问题的上下文中,因为数组是排序的,所以哈希表不是最优解。

import java.util.HashMap;

class Solution {
    public int[] searchRange(int[] nums, int target) {
        HashMap<Integer, Integer> map = new HashMap<>();
        int[] res = new int[2];
        res[0] = res[1] = -1;

        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == target) {
                if (!map.containsKey("first")) {
                    map.put("first", i);  // 第一个出现的位置
                }
                map.put("last", i);  // 最后一个出现的位置
            }
        }

        if (map.containsKey("first") && map.containsKey("last")) {
            res[0] = map.get("first");
            res[1] = map.get("last");
        }

        return res;
    }
}

4. 利用 Java 内置的 Arrays.binarySearch

我们可以先通过 Arrays.binarySearch 方法找到 target 在数组中的任意位置,然后从该位置向左和向右扩展来寻找第一个和最后一个位置。这种方法实际上与二分查找非常类似,稍微简化了代码,但仍然是 O(log n) 时间复杂度。

import java.util.Arrays;

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res = new int[2];
        res[0] = res[1] = -1;

        // 使用 binarySearch 找到 target 的任意位置
        int index = Arrays.binarySearch(nums, target);
        if (index < 0) {
            return res;  // 如果没找到,直接返回 [-1, -1]
        }

        // 找第一个出现的位置
        int left = index;
        while (left > 0 && nums[left - 1] == target) {
            left--;
        }

        // 找最后一个出现的位置
        int right = index;
        while (right < nums.length - 1 && nums[right + 1] == target) {
            right++;
        }

        res[0] = left;
        res[1] = right;
        return res;
    }
}

标签:target,nums,int,res,34,查找,数组,排序,left
From: https://www.cnblogs.com/drunkerl/p/18637848

相关文章

  • [4434] 20 流程优化:部署流程中的构建流程策略优化
    上节课我们分析了部署流程中,安装依赖阶段执行效率的影响因素和执行过程细节。思考题是如果使用npm的话,在最佳条件下是否也可以达到像Yarn一样瞬间完成依赖安装呢?答案是当然可以。在今天课程的第一部分我们就将了解如何利用安装目录缓存达到这一效果。我们将从部署流程效率优......
  • 学习012-02-03-14 How to: Reorder an Action Container‘s Actions Collection(如何:对
    Howto:ReorderanActionContainer’sActionsCollection(如何:对操作容器的操作集合进行重新排序)InanXAFapplicationUI,ActionsarelocatedwithinActionContainers.YoucanusetheActionBase.CategorypropertyandtheApplicationModel’sActionDesign......
  • c语言书籍排序 多数组协同排序 按价格排序【书名同步】 带有空格的字符串读取
    题目:编写程序,从键盘输入n(n<10)本书的名称和定价并存入结构数组中,按单价从小到大排序并输出排序后的书籍信息。输入输出示例:括号内为说明,无需输入输出输入样例:3(n=3)ProgramminginC21.5ProgramminginVB18.5ProgramminginDelphi20输出样例:Programmingin......
  • 记一个itertools排列组合和列表随机排序的例子
    朋友不知道哪里弄来了一长串单词列表,一定要搞个单词不重复的组合。那么这个时候我们就可以想到读书时所学的排列组合知识了,而这个在Python中可以怎么实现呢?我记录如下:使用itertools模块实现排列组合在Python中,排列组合可以通过itertools模块来实现。以下是两个主要函......
  • 删除拼排序链表中的重复元素(最优解)
    题目来源82.删除排序链表中的重复元素II-力扣(LeetCode)题目描述给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。示例1:输入:head=[1,2,3,3,4,4,5]输出:[1,2,5]示例2:输入:head=[1,1,1,2,3]......
  • 十大排序---下
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、归并排序二、快速排序三、计数排序四、桶排序五、基数排序总结前言今天我们来继续学习十大排序中剩下的五个。提示:以下是本篇文章正文内容,下面案例可供参考一、归并排序    ......
  • mysql 一个字段多种排序方式
    一、mysql一个字段多种排序数据idname1tkj1000020-1.11test2tkj1000020-13tkj1000020-2.1test4tkj1000020-2.2test5tkj1000020-26tkj1000020.1test7tkj1000020.1test_0018tkj1000020.2test9tkj1000020.3test10tkj1000020aest......
  • [VUE]CALL_AND_RETRY_LAST分配失败-JavaScript堆内存不足 errno134
    使用vscode开发项目,由于项目较大,在运行npmrundev命令后,在一定的时间范围内,对vscode中的代码进行保存后,会自动编译运行,保存几次后就报错,需要重新运行npmrundev,很耗费时间)后报错报错:CALL_AND_RETRY_LASTAllocationfailed-JavaScriptheapoutofmemory(CALL_AND_RETRY_LAS......
  • sql超时 sql中存在关键字 in 和 not in 和 <> 和 分组排序和 子查询 代码优化
    针对SQL查询中存在 IN、NOTIN、<>、分组排序和子查询的情况,优化这些查询可以显著提高性能。以下是一些具体的优化建议:1.优化 IN 和 NOTIN使用 IN 替代 NOTIN:NOTIN 在处理 NULL 值时可能会导致性能问题。可以考虑使用 NOTEXISTS 或 LEFTJOIN 替代......
  • 148. 排序链表
    题目链接解题思路:在链表上使用排序算法。注意,不能使用快排,因为快排的最差时间复杂度是O(n^2),数组形式的快排,以随机数划分能够得到O(n*logn),但是链表的形式,不太好以随机数的方式划分。所以最好的排序方法是使用归并排序。先用快慢指针,将链表分成两部分,然后两部分分别归并排......