当前位置: 首页 > news >正文

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

1.题目

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

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

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

1.1 示例

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

1.2 提示

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

     

2. 暴力思路

首先想到暴力,遍历整个数组然后把符合要求的存入一个 List 中,然后把集合中第一个和最后一个元素封装成数组返回。想想当题目元素只有一个时,new int[]{list.get(0), list.get(list.size() - 1)} 也能满足需求。 但这样时间复杂度为O(n) 了,但提交也能过。


2.1 代码

   public int[] searchRange(int[] nums, int target) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == target) {
                list.add(i);
            }

        }

        return convert(list);


    }

    private int[] convert(List<Integer> list) {
        if (list == null || list.isEmpty()) {
            return new int[]{-1, -1};
        }


        return new int[]{list.get(0), list.get(list.size() - 1)};
    }

3 二分优化


3.1 思路

题目说数组是递增的,用 left 和 right 两个指针来划定搜索范围,mid 是中间元素的索引。如果中间元素等于目标值,那可能这个元素就是第一个出现的位置,但也可能存在更早的相同元素,所以需要把 right 调整到 mid - 1,继续往左找。如果中间元素小于目标值,说明要找的元素在右边,left 调整到 mid + 1;否则,就在左边找。这个过程不断缩小范围,直到找到最左边的目标元素。
同理找最后的方法是一致的。

代码是通过两次二分查找分别找到目标元素的最左和最右出现的位置。这种方式的时间复杂度是 O(log n),比线性扫描的 O(n) 要高效得多。


3.2 代码
 

    public int[] searchRange(int[] nums, int target) {
        int first = findFirst(nums, target);
        int last = findLast(nums, target);
        return new int[]{first, last};

    }

    private int findFirst(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        int first = -1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                first = mid;
                right = mid - 1;
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return first;

    }

    private int findLast(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        int last =   - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                last = mid;
                left = mid + 1;
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return last;

    }

相关文章:

  • 深入理解 MySQL 8 C++ 源码:SELECT MOD(MONTH(NOW()), 2) 的函数执行过程
  • Cross-correlation 加速算法公式推导
  • 算法从0到100之【专题一】- 双指针第一练(数组划分、数组分块)
  • mysql云上安装慢问题解决
  • nasm - BasicWindow_64
  • 关于重启Pod后,CNI网络插件问题报错
  • AI 内容检测工具全解析,助力内容创作无忧
  • 蓝桥杯备考策略
  • Linux常用操作
  • java每日精进 2.20 MQ相关复健
  • 【量化策略】均值回归策略
  • 蓝桥杯 2.基础算法
  • gen_gauss_filter用于检测带方向的线条
  • 运维脚本——6.资源优化
  • 斐波那契数列模型:在动态规划的丝绸之路上追寻斐波那契的足迹(下)
  • 系统思考—价格策略
  • 【CSS】---- CSS 变量,实现样式和动画函数复用
  • MyBatis框架七:缓存
  • 【Golang 面试题】每日 3 题(六十一)
  • 前后端分离的Netty + WebSocket实现聊天室
  • 国家能源局:支持民营企业参股投资核电项目
  • 牛市早报|今年国内核电项目审批首次开闸,离境退税起退点下调
  • 上海超万套保租房供应高校毕业生,各项目免押、打折等优惠频出
  • 伊朗国防部发言人:发生爆炸的港口无进出口军用物资
  • 第一集丨《无尽的尽头》值得关注,《榜上佳婿》平平无奇
  • 第二十届华表奖提名名单公布,张译、王一博、马丽、郭帆等入围