LeetCode习题——在排序数组中查找元素的第一个和最后一个位置(二分查找)

Posted Heyking

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode习题——在排序数组中查找元素的第一个和最后一个位置(二分查找)相关的知识,希望对你有一定的参考价值。

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

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

题目

给你一个按照非递减顺序排列的整数数组 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]

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

分析或原理

这题的难点在于target有可能会有多个,如何确定边界值。先说有两种类型的解法,一种是暴力,一种是二分法求边界,由于必须设计时间复杂度为 O(log n) 的算法解决此问题,所以选择二分法。

题解

暴力方法

通过遍历数组,存储第一个和最后一个,但是时间复杂度会到O(n),不符合题目要求的,但是力扣中可以通过。

class Solution 
    public int[] searchRange(int[] nums, int target) 
        // 暴力方法
        int [] index = -1,-1; 	// 初始值设置为[-1, -1]
        for(int i=0;i<nums.length;i++)  // 遍历nums数组
           if(nums[i] == target)		// 找到等于target的数
               if(index[0] == -1)	  // 如果当前索引等于-1说明,说明此之前没有找到一个相等的,所以最小的就是它
                   index[0] = i;
               
               if(index[1]<=i)		  // 如果当前索引大于index[1],即可替换右边界
                   index[1] = i;
               
            
        
        return index;
    

二分法

我们可以通过写几个方法帮我找到左右边界,通过调用方法寻找。

public int[] searchRange(int[] nums, int target) 
    // 二分法
    int len = nums.length;
    if(len == 0) 	// 如果数组为空则直接返回[-1, -1]
        return new int[]-1, -1;
    
    int leftPosition = findLeftPosition(nums, target);  // 寻找左边界
    if (leftPosition == -1) 		// 如果没找打左边界 则直接返回[-1, -1]
        return new int[]-1, -1;
    
    int rightPosition = findRightPosition(nums, target); // 寻找右边界
    return new int[]leftPosition, rightPosition; // 直接返回左右边界即可

查找左边界

private int findLeftPosition(int[] nums, int target) 
    // 二分法查找
    int left = 0;
    int right = nums.length - 1;
    while (left < right)
        int mid = (left + right)  1;
        if (nums[mid] < target)
            // 下一轮搜索的区间是 [mid + 1, right]
            left = mid + 1;
         else if (nums[mid] == target) 
            // 下一轮搜索的区间是 [left, mid]
            right = mid;
         else 
            // nums[mid] > target
            // 下一轮搜索的区间是 [left, mid - 1]
            right = mid - 1;
        
    
    // 上述循环可能找到的是插入位置而不一定是等于target所以需要判断一下
    if (nums[left] == target) 
        return left;
     else 
        return -1;
    

查找右边界

private int rightPosition(int[] nums, int target)
    int left = 0;
    int right = nums.length - 1;
    while (left < right)
        int mid = (left + right + 1) / 1;  // 这里选择向上取整
        if (nums[mid] < target)
            // 下一轮搜索的区间是 [mid + 1, right]
            left = mid + 1;
         else if (nums[mid] == target) 
            // 下一轮搜索的区间是 [mid, right]
            left = mid;
         else 
            // nums[mid] > target
            // 下一轮搜索的区间是 [left, mid - 1]
            right = mid - 1;
        
    
    return left;

当你面对困难时,不要害怕挑战。挑战并不可怕,重要的是你需要勇敢地面对它,积极寻找解决问题的方法。只要你努力不懈、持之以恒,最终你一定能够克服难关。

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

LeetCode 0034. Find First and Last Position of Element in Sorted Array在排序数组中查找元素的第一个和最后一个位置【Medium】【Python】【二分】

Problem

LeetCode

Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.

Your algorithm‘s runtime complexity must be in the order of O(log n).

If the target is not found in the array, return [-1, -1].

Example 1:

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

Example 2:

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

问题

力扣

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

你的算法时间复杂度必须是 O(log n) 级别。

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

示例 1:

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

示例 2:

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

思路

二分查找

两次二分查找。
1. 查找 left,所以 nums[mid] < target 时,才移动 left 指针
2. 查找 right,所以 nums[mid] <= target 时,才移动 left 指针
3. lower_bound 返回的是开始的第一个满足条件的位置,而 upper_bound 返回的是第一个不满足条件的位置。所以,当两个相等的时候代表没有找到,如果找到了的话,需要返回的是 [left, right - 1]。

时间复杂度: O(logn)
空间复杂度: O(1)

Python代码

class Solution(object):
    def searchRange(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        # solution one: binary search
        left = self.lowwer_bound(nums, target)
        right = self.higher_bound(nums, target)
        if left == right:
            return [-1, -1]
        return [left, right - 1]
    
    def lowwer_bound(self, nums, target):
        # find in range [left, right)
        left, right = 0, len(nums)
        while left < right:
            mid = int((left + right) / 2)
            if nums[mid] < target:  # <
                left = mid + 1
            else:
                right = mid
        return left
    
    def higher_bound(self, nums, target):
        # find in range [left, right)
        left, right = 0, len(nums)
        while left < right:
            mid = int((left + right) / 2)
            if nums[mid] <= target:  # <=
                left = mid + 1
            else:
                right = mid
        return left

        # # solution two: bisect
        # left = bisect.bisect_left(nums, target)
        # right = bisect.bisect_right(nums, target)
        # if left == right:
        #     return [-1, -1]
        # return [left, right - 1]

代码地址

GitHub链接

以上是关于LeetCode习题——在排序数组中查找元素的第一个和最后一个位置(二分查找)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

《LeetCode之每日一题》:90.在排序数组中查找元素的第一个和最后一个位置

5-003-(LeetCode- 34) 在排序数组中查找元素的第一个和最后一个位置

[LeetCode]34. 在排序数组中查找元素的第一个和最后一个位置(二分)

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