DAY 1 数组

数组理论基础

数组是存放在连续内存空间上的相同类型数据的集合。

数组可以方便的通过下标索引的方式获取到下标对应的数据。

举一个字符数组的例子,如图所示:

算法通关数组

需要两点注意的是

  • 数组下标都是从0开始的。
  • 数组内存空间的地址是连续的

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

例如删除下标为3的元素,需要对下标为3的元素后面的所有元素都要做移动操作,如图所示:

算法通关数组1

数组的元素是不能删的,只能覆盖。


二分法 

二分法的前提是数组为有序数组,且无重复数组

易错点:

#易错点1:
while left<right      ||    while left<=right
#易错点2:
if nums[mid] > target:    
    right =mid     ||    right = mid -1

左闭右开,左闭右闭 两种区间规则

704. 二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

提示:

  1. 你可以假设 nums 中的所有元素是不重复的。
  2. n 将在 [1, 10000]之间。
  3. nums 的每个元素都将在 [-9999, 9999]之间。

方法一:左闭右闭

[left,right]:

while left <=right.      
    # left和while可以相等,例如:[1,1]是合法区间
if nums[mid] > target:  
    right = mid -1    
    # mid值大于target,下一个区间不能包含mid值
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums)-1
        while left <= right:
            mid = (left+right)//2
            if nums[mid] < target:
                left = mid +1 #[mid+1, right]
            elif nums[mid]> target:
                right = mid-1 #[left, mid-1]
            else:
                return mid
        return -1

# 如果target一定存在也可以写成:
# lower_bound 返回最小的满足 nums[i] >= target 的 i
# 如果数组为空,或者所有数都 < target,则返回 len(nums)
# 要求 nums 是非递减的,即 nums[i] <= nums[i + 1]


def lower_bound(nums: List[int], target: int) -> int:
    left, right = 0, len(nums) - 1  # 闭区间 [left, right]
    while left <= right:  # 区间不为空
        # 循环不变量:
        # nums[left-1] < target
        # nums[right+1] >= target
        mid = (left + right) // 2
        if nums[mid] < target:
            left = mid + 1  # 范围缩小到 [mid+1, right]
        else:
            right = mid - 1  # 范围缩小到 [left, mid-1]
    return left  # 或者 right+1

遇到的问题:

  • mid = (left+right) //2一定要放进循环,确保每次迭代都更新mid
  • 第二段代码
    • 如果 target 存在于 nums 中,left 将最终指向 target 的索引。(可以直接使用 left 作为插入位置)
    • 如果 target 不在 nums 中,left 将指向第一个大于 target 的元素的索引,或者是数组的末尾。

 方法二:左闭右开

[left,right)

  • 除2个易错点外还要注意right的取值
right = len(nums) #右开,取不到len(nums)
while left < right:
    #[1,1)无意义
if nums[mid] < target:
    left = mid+1  # [mid+1,right) 左闭不能包含mid
elif nums[mid] > target:
    right = mid   #[left,mid) 
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums) #[left,right)
        while left < right:
            mid = (left+right)//2
            if nums[mid] < target:
                left = mid+1  #[mid+1, right]
            elif nums[mid] > target:
                right = mid   #[left,mid)区间不可包含mid,右开取不到
            else:
                return mid
        return -1
  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)

27. 移除元素

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

假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:

  • 更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。
  • 返回 k

数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。

库函数:

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        m = nums.count(val)
        for i in range(m):
            nums.remove(val)

双指针思想:

把 nums 中的不等于 val 的数,依次填在 0,1,2,⋯ 这些下标上。快指针去搜索不等于val的值,慢指针记录下标。

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        k = 0 #初始化要填入的下标k=0, 慢指针
        for x in nums: #快指针
            if x!=val:
                nums[k] = x
                k+=1
        return k

算法复杂度:

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

总结:

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置

977. 有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

暴力法: 

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        for i in range(len(nums)):
            nums[i] *= nums[i] #平方后排序
        nums.sort() #sort函数的时间复杂度为O(N logN)
        return nums

#暴力排序法+列表推导法
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        return sorted(x*x for x in nums)

算法复杂度

  • O(nlogn)
  • O(1)

双指针思想:

数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。

此时可以考虑双指针法了,i指向起始位置,j指向终止位置。

定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。

与其从中间开始向两边合并,不如从两边开始向中间合并,这样无需计算从中间的哪个位置开始。

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        l = 0
        r = len(nums)-1
        res = [0]*(len(nums)) #定义一个新数组
        for i in range(len(nums)-1,-1,-1):
            x = nums[l]**2
            y = nums[r]**2
            if x >y:
                res[i] = x
                l+=1
            else:
                res[i] = y
                r-=1
        return res
               

算法复杂度:O(n) 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值