代码随想录算法训练营第一天| 704. 二分查找(相关题目 35、34)、27. 移除元素。

目录

leetcode - 704

衍生 - 35

衍生 - 34

Leetcode - 27


leetcode - 704

二分查找有两种范式,一种是左闭右开,一种是左闭右闭。

如图,左边指的是左闭右开,初始状态下,start = 0,end = len(nums),也就是最后一个元素后一位,右侧对应的是一个开区间。左闭右开的情况下,start 是不会等于end的,所以循环条件就是start < end , 当target < nums[mid]时,end = mid,这里记住开区间start = mid就行,任何时候target > nums[mid]时,start = mid +1

右边指的是左闭右闭,start = 0 ,end = len(nums) -1也就是对应我们最后一个元素,右侧对应的是一个闭区间。闭区间,srart是可以等于end的,所以循环条件是 start <= end。 当target < nums[mid]时,start = mid-1。

时间复杂度为(logn), 空间复杂度为1, 若用递归的方式,时间复杂度为(logn),空间复杂度为递归深度乘以每次递归的空间复杂度 即: logn * 1 =  logn

# 左闭右闭
def search(nums: List[int], target: int) -> int:
        start = 0
        end = len(nums)-1

        while start <= end:
            mid = (start + end) //2
            if nums[mid] == target:
                return mid
            elif nums[mid] > target:
                
                end = mid-1
            else:
                start = mid+1

        else:
            return -1

# 左闭右开
def search(nums: List[int], target: int) -> int:
        start = 0
        end = len(nums)

        while start < end:
            mid = (start + end) //2
            if nums[mid] == target:
                return mid
            elif nums[mid] > target:
                
                end = mid
            else:
                start = mid+1

        else:
            return -1

衍生 - 35

关于插入问题 

 第一种方法是同上面的方法  

 def searchInsert(nums: List[int], target: int) -> int:
        start = 0
        end = len(nums) -1

        while start <= end:
            mid = (start + end) //2
            if nums[mid] == target:
                return mid
            elif nums[mid] > target:
                end = mid -1
            else:
                start = mid+1

        else:
            return start
            

 先查找这个值,如果找不到就插在start的位置上

但是更为常用的是  循环条件为 start < end  ,对于start 和 end的操作分别是  start = mid+1 ,end = mid  这种方式在二分法中(非单纯二分查找)更为常用

def searchInsert(nums: List[int], target: int) -> int:
        start = 0
        end = len(nums) -1

        while start < end:
            mid = (start + end) //2
            if nums[mid] == target:
                return mid
            elif nums[mid] > target:
                end = mid
            else:
                start = mid+1

        else:
            # 如果target 大于start处的元素,那么就插在start的后一位
            if nums[start] < target:
                return start +1
            return start

衍生 - 34

首先是在第一题的二分大框架下,找到目标元素后,向其左右遍历寻找即可,题目没啥新意

def searchRange(nums: List[int], target: int) -> List[int]:
        start = 0
        end = len(nums) -1

        while start <= end:
            mid  = (start + end) //2
            if nums[mid] == target:
                res = [mid]
# 从mid 出发 寻找前后相邻目标元素的小标,一旦遍历到非目标元素 停止遍历
                for k in range(mid+1,len(nums)):
                    if nums[k] == target:
                        res.append(k)
                    else:
                        break
               # 从 mid出发,到0结束,因为是反向遍历,所以步长是-1
                for k in range(mid,-1,-1):
                    if nums[k] == target:
                        res.append(k)
                    else:
                        break
                return [min(res),max(res)]
            
            elif nums[mid] > target:
                end = mid -1
            else:
                start = mid+1
        
        else:
            return [-1,-1]

Leetcode - 27

首先明确 这道题是让你返回新数组的长度,假设新数组长度为s,则题目会默认截取原数组中前s个元素与答案对比

这题最简单的方法就是 边删除目标元素 边判断数组中是否还存在目标函数,如果不存在则停止循环

def removeElement(nums: List[int], val: int) -> int:
        while val in nums:
            nums.remove(val)

        return len(nums)

另一种是用快慢指针的方法,快指针用于不断向后遍历新元素,慢指针用于表示更新后数组的最新状态,其实就是一个将非目标元素不断往数组前面填充的过程,慢指针从下标0处开始,快指针一旦找到非目标元素,就扔给慢指针处,慢指针处记录这个值后,慢指针再指向下一个下标,思想很好

def removeElement(nums: List[int], val: int) -> int:
    
            # 快指针遍历元素
        fast = 0
    # 慢指针记录位置
        slow = 0
        for fast in range(len(nums)):
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
        
        return slow

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值