Leetcode 35. 搜索插入位置 Python

力扣原题链接: Leetcode Q35

题目描述

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
题目要求
必须使用时间复杂度为 O(log n) 的算法。
由于要求使用时间复杂度为O(log n) 的算法,那么自然而然我选择了二分法来解决这个问题。
重要题目提示
nums 为 无重复元素 的 升序 排列数组
“无重复元素”和“升序”是两个很重要的前提。
无重复元素:一旦有重复元素,那么使用二分查找法返回的元素下标可能并不是最后一个重复元素。
升序:说明数组是有序数组,这也是使用二分法的前提。数组升序的性质也提示我们要寻找第一个大于target的位置作为插入位置。如果是降序的话,就得另当别论。
我们知道在寻找target在数组的位置时,如果找不到target,那么将会返回-1。这道题便是针对找不到target的情况,不再返回-1,而是返回target 之后第一个 大于target的位置了。

Leetcode代码

  1. 左闭右闭情况 [left,right]
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        left,right=0,len(nums)-1
        while left<=right:
            middle=left+(right-left)//2
            if nums[middle]>target:
                right=middle-1
            elif nums[middle]<target:
                left=middle+1
            else: return middle
        return left

手搓
target 0 应该插入0
1 round l0, r3 middle=0+3//2=1 --> l0, r1-1=0
2 round l0, r0 middle=0+(0)//2=0 --> l0, r=0-1=-1
跳出循环 return l

target 4 应该插入2
1 round l0, r3 middle=0+3//2=1 --> l=1+1=2, r3
2 round l2, r3 middle=2+(3-2)//2=2 --> l2, r=2-1=1
跳出循环 return l

target 7 应该插入4
1 round l0, r3 middle=0+3//2=1 --> l=1+1=2, r3
2 round l2, r3 middle=2+(3-2)//2=2 --> l=2+1=3, r3
3 round l3, r3 middle=3+(3-3)//2=3 --> l=3+1=4, r3
跳出循环 return l
可以自己手搓循环… …
我们能发现最后一次循环,left等于middle,但不一定等于right。

那为什么返回left?
因为退出while循环后,left > right,此时有两种情况:

  • 一种是middle指向的值大于target(此时middle是第一个大于target的下标),此时right=middle-1导致了left大于right,而target要插入的位置是middle的位置,即left,因为left和middle相等
  • 另一种是middle指向的值小于target,此时left=middle+1导致了left大于right,而target要插入的位置是middle+1的位置,即left
  • 因此退出循环时,left指向的就是第一个大于target的位置,right指向的就是最后一个小于target的位置
  1. 左闭右开情况 [left,right)
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        left,right=0,len(nums)
        while left<right:
            middle=left+(right-left)//2
            if nums[middle]>target:
                right=middle
            elif nums[middle]<target:
                left=middle+1
            else: return middle
        return left

左闭右开依旧返回left,而不用考虑+1还是-1的问题。

总结

简单地说,由于数组升序的性质,我们找的一定得是第一个大于target的位置。随着while循环进行,left和right会不断的收缩,一直假设target在left和right中间, 到最后退出循环,也没找到,那么这个时候left指向的就是第一个大于target的位置,考虑到left在区间内始终是能取到的数值(不受开闭影响,始终是闭),left就一定是target插入的位置。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值