代码随想录 day1:第一章 数组part01

代码随想录

数组基础:

  1. 数组是存放在连续内存空间上的相同类型数据的集合。
  2. 数组可以方便的通过下标索引的方式获取到下标下对应的数据。
  3. 数组下标都是从0开始的。
  4. 数组内存空间的地址是连续的。​

        正是因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。数组的元素是不能删的,只能覆盖。

704. 二分查找 

        熟悉根据左闭右开,左闭右闭两种区间规则写出来的二分法。一定要注意边界条件 。

关键词:有序且升序,无重复元素。因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件。

        二分查找涉及的很多的边界条件,逻辑比较简单,但就是写不好。例如到底是 while(left < right) 还是 while(left <= right),到底是right = middle呢,还是要right = middle - 1呢?

写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。

  • 左闭右闭:[left, right] 

        因为定义target在[left, right]区间,所以有两点:

        1. while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=

        2. if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1

        3. left,right=0,len(nums)-1# 定义target在左闭右闭的区间里,[left, right]

时间复杂度:O(log n);空间复杂度:O(1)

def search(self, nums: List[int], target: int) -> int:
        #左闭右闭
        left,right=0,len(nums)-1# 定义target在左闭右闭的区间里,[left, right]
        while left<=right:
            middle=(left+right)//2
            if nums[middle]<target:
                left=middle+1
            elif nums[middle]>target:
                right=middle-1
            else:
                return middle
        return -1
  •  左闭右开:[left, right)

    有如下两点:

        1. while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的

        2. if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]

        3. left,right=0,len(nums)# 定义target在左闭右开的区间里,即:[left, right)

  • 时间复杂度:O(log n);空间复杂度:O(1)
left,right=0,len(nums)# 定义target在左闭右开的区间里,即:[left, right)
        while left<right:
            middle=(left+right)//2
            if nums[middle]<target:
                left=middle+1
            elif nums[middle]>target:
                right=middle
            else:
                return middle
        return -1

27. 移除元素

题目:给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。

解决方法:快慢指针。在数组和链表的操作中非常常见,很多题目,链表、数字等操作,都使用双指针法。

原地移除,快指针找不等于val的元素,慢指针将快指针找到的元素覆盖原来的元素。

def removeElement(self, nums: List[int], val: int) -> int:
        # 快慢指针
        slow,fast=0,0
        while fast<len(nums):
            if nums[fast]!=val:
                nums[slow]=nums[fast]# 覆盖即移除
                slow+=1
                fast+=1
            else:
                fast+=1
        return slow

35.搜索插入位置

题目:给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。请必须使用时间复杂度为 O(log n) 的算法。

这题还多了个额外的条件,即如果不存在数组中的时候需要返回按顺序插入的位置,考虑这个插入的位置 pos,它成立的条件为:nums[pos−1]<target≤nums[pos]。

其中 nums代表排序数组。由于如果存在这个目标值,返回的索引也是 pos,因此我们可以将两个条件合并得出最后的目标:「在一个有序数组中找第一个大于等于 target的下标」。不断用二分法逼近查找第一个大于等于 target 的下标 。

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        #若存在,则返回下标,不存在,则返回比他稍大元素的下标,也就是返回右坐标
        # nums[pos-1]<target<=nums[pos],返回pos的下标
        # 找到大于等于的第一个数
        # 左闭右开
        left,right=0,len(nums)
        while left<right:
            middle=(left+right)//2
            if nums[middle]<target:
                left=middle+1
            else:
                right=middle
        return right

 

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

题目:给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

def lower_bound1(nums,target):
        #二分法,左闭右开
        left,right=0,len(nums)#[left,right)
        while left<right:#相等时没有意义
            middle=(left+right)//2
            if nums[middle]<target:
                left=middle+1#[midlle+1,right)
            else:
                right=middle#[left,middle)
        return left# # 返回 left 还是 right 都行,因为循环结束后 left == right

    # def lower_bound2(nums,target):
    #     #二分法,左闭右闭
    #     left,right=0,len(nums)-1#[left,right]
    #     while left<=right:
    #         middle=(left+right)//2
    #         if nums[middle]<target:
    #             left=middle+1
    #         else:
    #             right=middle-1
    #     return left

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        # start是大于等于,end是小于等于target的位置
        start=lower_bound1(nums,target)#找到第一个等于target的位置,左边小于target
        if start==len(nums) or nums[start]!=target:
            return [-1,-1] # nums 中没有 target
        #如果start存在,那么end一定存在
        end=lower_bound1(nums,target+1)-1
        return [start,end]

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值