Leetcode每日一题2021/01/11

【每日一题】Leetcode:34. 在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 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

分析:
1
思考:
2
思路:
4
问题:
3
今天真是一个不停踩坑的过程,然后自己好好地去看了一下题解和二分法相关的内容。

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        if(n == 0): return [-1, -1]
        if(n == 1 and nums[0] == target): return [0, 0]
        def findFirst(l, r):
            # 结束时,l=r
            while(l < r):
                mid = (r + l)//2
                # 下一个[l, mid]
                if(nums[mid] == target):
                    r = mid
                # 下一个[l, mid-1]
                elif(nums[mid] > target):
                    r = mid - 1
                # 下一个[mid+1, r]
                elif(nums[mid] < target):
                    l = mid + 1
            if(nums[l] == target):
                return l
            return -1
        
        def findLast(l, r):
            while(l < r):
                mid = (r + l + 1)//2
                # 下一个,[mid, r]
                if(nums[mid] == target):
                    l = mid
                # 下一个,[l, mid-1]
                elif(nums[mid] > target):
                    r = mid - 1
                # 下一个,[mid+1, r]
                elif(nums[mid] < target):
                    l = mid + 1
            if(l == r and nums[l] == target):
                return l
            return -1
        l, r = 0, n - 1
        return [findFirst(l, r), findLast(l, r)]

5

  • 二分法
    问题:
    1、循环的边界;(用left<right还是left<=right)
    2、区间的收缩;(区间怎么收缩)
    3、mid的取值。(有些是(left+right)/2,有些是(left+right+1)/2,为什么?)
    5
    参考
    https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/solution/si-lu-hen-jian-dan-xi-jie-fei-mo-gui-de-er-fen-cha/
  • 个人理解
    主要是两个问题:
    1、用left < right还是用left <= right进行循环控制
    2、两种循环控制的区间收缩要注意什么;
    3、中位数mid怎么取值,加不加1。
    理解:
    1、两种循环控制都可以。
    对于left < right,常用用于区间元素查找,因为当退出循环时left=right,这里是还剩了一个值没有遍历的,即left和right都指向的这个值,而这个值就是目标值。
    对于left <= right,常用于区间元素排除,当退出循环时,所有的元素都已经遍历了,没有找到合适的说明就没有了。
    2、收缩的道理都是一样的,就是每次循环都要进行区间的收缩,否则可能造成死循环
    3、中位数+1这个情况,在此题仅对left < right这种情况下有使用,是避免死循环的办法,即取右中位数,如当数组为[2,2]找2时,查找最后一个2的出现就需要取右中位数,否则就会死循环。
  • 小结
    left < right,注意mid = (r + l + 1)//2的使用,否则可能死循环。
    left <= right,向左收缩是当nums[mid]=target时不动左边界,收缩右边界。向右收缩是当nums[mid]=target时不动右边界,收缩左边界。并且返回下标的初值是len(num)。

猜你喜欢

转载自blog.csdn.net/weixin_40910614/article/details/112468739