代码随想录学习Day 1

数组基础知识

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

2.数组下标都是从0开始的。

3.数组内存空间的地址是连续的

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

但其实数组的元素并不能删除,只能覆盖

查看二维数组地址的代码如下:

def test_arr():
    array = [[0, 1, 2],
             [3, 4, 5]]
    for row in array:
        for elem in row:
            print(f"Element {elem}: Address {id(elem)}")

输出结果为:

Element 0: Address 140707786699664
Element 1: Address 140707786699696
Element 2: Address 140707786699728
Element 3: Address 140707786699760
Element 4: Address 140707786699792
Element 5: Address 140707786699824

相邻元素之间的地址相差32位,8位为一个字节,所以每个元素之间相差4个字节,因为定义的是int型的数组。

704.二分查找

题目链接

讲解链接

二分法使用前提:
1.必须为有序数组

2.数组中无重复元素(若存在重复元素,则返回的下标可能不唯一)

重点:区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。

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

①左闭右闭法:定义target在[left,right]区间中

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left, right = 0, len(nums) - 1  # 左闭右闭,此时right要取最右边的值,所以为len-1
        while left <= right:  # 左闭右闭情况下left==right仍是有效区间,需要考虑相等的情况
            middle = (left + right) // 2  # 左右相加除2取整
            if nums[middle] < target:
                left = middle + 1  # 此时middle的值<target,所以在下一阶段中应该舍弃,需要+1
            elif nums[middle] > target:
                right = middle - 1  # 同上,右端点-1舍弃middle的值
            else:
                return middle
        return -1

②左闭右开法:定义target在[left,right)区间中

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left, right = 0, len(nums)  # 此处由于是左闭右开,right不包含在区间内,所以直接取len
        while(left < right):  # 左闭右开情况下不存在left==right的情况,所以用<
            middle = (left + right) // 2
            if nums[middle] < target:
                left = middle + 1  # 同左闭右闭法
            elif nums[middle] > target:
                right = middle  # 由于right不包含在区间内,所以不用舍弃middle,不需要-1
            else:
                return middle
        return -1

27.移除元素

题目链接

讲解链接

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

采用暴力解法,需要两层循环,一层用来遍历数组,另一层用来从后往前逐个覆盖。时间复杂度为O(n^2),在力扣上可以AC。

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        i, size = 0, len(nums)
        while i < size:
            if nums[i] == val:
                for j in range(i + 1, size):
                    nums[j - 1] = nums[j]
                i -= 1
                size -= 1
            i += 1
        return size

若追求更低的时间复杂度,则考虑双指针法,通过使用快慢两个指针在一层循环下完成任务。

快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组

慢指针:指向更新 新数组下标的位置

删除过程示意图及代码如下

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        fast, slow = 0, 0  # 定义快慢两个指针
        for fast in range(len(nums)):
# 只有在不等于的情况下才会进行覆盖,因为fast寻找的是非目标元素,slow则用来保存非目标元素所在的下标
            if nums[fast] != val:  
                nums[slow] = nums[fast]
                slow += 1
        return slow

这样的方法并不会改变元素的相对位置,且时间复杂度仅为O(n) 。

如果题目中元素的相对位置可以改变,并且要求移动的次数尽可能少,那么可以采用如下方法。采用两个指针分别指向数组的头和尾,然后从左边分别查找与val相同的元素,从右边查找与val不同的元素。然后用右侧不等于val的元素来覆盖左侧等于val的元素。

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        if nums is None or len(nums)==0: 
            return 0 
        l=0
        r=len(nums)-1
        while l<r: 
            while(l<r and nums[l]!=val):
                l+=1
            while(l<r and nums[r]==val):
                r-=1
            nums[l], nums[r]=nums[r], nums[l]
        print(nums)
        if nums[l]==val: 
            return l 
        else: 
            return l+1

  • 23
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值