Day 02 数组

文章讲述了如何使用双指针法解决有序数组的平方生成问题,以及在处理子数组问题时遇到的挑战,如边界判断和优化循环。作者还提到在Python中使用NumPy创建空矩阵的方法和范围函数的调整
摘要由CSDN通过智能技术生成

977.有序数组的平方

最开始的思路是,使用双指针法来从数组的两端向中间遍历,选出最大的数字。.append() 方法是在列表的末尾添加元素,而不是开头。因此,如果按照从大到小的顺序将元素添加到新列表中,那么在最后反转列表之前,新列表实际上是按照递减顺序排列的。代码细节上我调整了几次,其中比较关键的区间的问题,一个还是.append()函数的问题,我试图用new.append(nums[left]*nums[left],new.append(nums[right]*nums[right]))一次添加两个,但事实.append() 方法只接受一个参数,即要添加到列表末尾的元素。

还有一个就是while left<=right:的判断,什么时候结束,我最开始觉得是left<right就可以了,当left==right时,当数组中只剩下一个元素时,它的平方就是需要添加到新数组中的最后一个元素。如果 left < right 作为循环条件,那么当 left 和 right 相等时,循环会提前结束,导致最后一个元素的平方没有被添加到新数组中。

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        # 先看到非递减数组
        # 要返回一个新的数组又由平方组成,需要新数组重新满足非递减
        # 说明可能会会出现[-4,-1,0,3,10]这种负数,要判断谁最大,就可以双指针
        # 不过这样是每次指针选择最大值/是直接赋值还是排序感觉需要考虑
        # 我准备.sort()
        # 不过复杂度O(n)我就不知道怎么确认了
        new=[]
        left=0
        right=len(nums)-1
        while left<=right:
            if nums[left]*nums[left]>nums[right]*nums[right]:
                new.append(nums[left]*nums[left])
                left+=1
            elif nums[left]*nums[left]<=nums[right]*nums[right]:
                new.append(nums[right]*nums[right])
                right-=1

        new.sort()
        return new

ps.数组反转的方法2 return new[::-1]

后来发现可以设一个k=len(nums)-1, 用new[k]=xxx  k-- 的方法更新,不用翻转了

 209.长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 连续

子数组

 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

这题尴尬了,很快想到了双指针滑动,但是一直很纠结,想是先固定left,去寻找满足求和大于等于target的right,先确定一个窗口,然后去移动两个指针,问题就来了,怎么同时移动两个指针呢?我还在想写窗口的大小的+1和-1,但是这又涉及到和target的大小判断,要记录最小值。就是首先想先写个循环来找到合适的两个初始的符合条件的指针,后来觉得实在是太麻烦了。

我的错误:

## 错误代码
class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        # 话说感觉可以双指针做,长度是right-left+1
        
        left,right=0,0
        length_min=len(nums)  ### 错误1
        total=0

        while right<len(nums):
            if total<target:
                right+=1  ## 错误2
                total+=nums[right]
            elif total>=target:
                if total-nums[left]>=target:
                    left+=1
                length_min=min(length_min,right-left+1)
        return length_min
                   

错误1:length_min初始化为len(nums)可能不是最佳的选择,因为如果没有找到任何满足条件的子数组,返回len(nums)可能会让人误解为整个数组就是满足条件的子数组。但是存在例如[1,2,3,1,2] target=10,这种,就不满足了。

参考改为:length_min = float('inf')

错误2:直接移动right,total还设置为0,直接省去了第一个nums[0]

错误3: if total-nums[left]>=target:这个条件判断并不正确,这个条件实际上是在检查去掉左指针所指向的元素后,剩余的总和是否仍然大于等于target

正确的逻辑应该是:当total达到或超过target时,先尝试更新最小窗口大小,然后再检查是否可以移动左指针(即去掉左指针所指向的元素后,剩余的总和是否仍然大于等于target)。如果可以移动左指针,则移动它并更新total

话说这一版本我不知道错哪里了

class Solution:  
  
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:  
  
        # 初始化左右指针和最小长度  
        left, right = 0, 0  
        length_min = float('Inf')  # 初始化为正无穷大  
        total = 0    
        # 开始遍历数组  
        while right < len(nums):  
            # 将当前元素加入总和  
            total += nums[right]  
            # 这里的逻辑错误:在total小于target时,错误地增加了right和total  
            if total < target:  
                right += 1           
            # 当总和达到或超过target时  
            elif total >= target:  
                # 更新最小长度  
                length_min = min(length_min, right - left + 1)  
                # 尝试移动左指针  
                total -= nums[left]  
                left += 1  
        # 返回最小长度  
        return length_min

# 我忘了之前right移动找到的已经是连续的能刚好满足target的情况了,不存在left移动了,right可以保持的情况

class Solution:  
  
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:  
  
        # 初始化左右指针和最小长度  
        left, right = 0, 0  
        length_min = float('Inf')  # 初始化为正无穷大  
        total = 0    
        # 开始遍历数组  
        while right < len(nums):  
            # 将当前元素加入总和  
            total += nums[right]  
            
            while total >= target:  
                # 更新最小长度  
                length_min = min(length_min, right - left + 1)  
                # 尝试移动左指针  
                total -= nums[left]  
                left += 1  
            right+=1 # 我忘了之前right移动找到的已经是连续的能刚好满足target的情况了,不存在left移动了,right可以保持的情况
        # 返回最小长度  
        return length_min if length_min != float('inf') else 0  # 要检查是否存在呀!!!

 59.螺旋矩阵II

不会初始化空白矩阵,记录下:

在 Python 中,zeros 函数不是内置的,它通常是 NumPy 库中的一个函数。

有导入 NumPy 库,那么 zeros 函数会报错。可以通过以下方式导入 NumPy 并使用 zeros 函数:

import numpy as np
res = np.zeros((n, n), dtype=int)

或者,如果不想使用 NumPy,可以简单地使用列表推导式来创建一个空的二维列表:

nums = [[0] * n for _ in range(n)]

最开始写成

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        ## 螺旋矩阵啊,好难拆解的样子

        left, right = 0, n - 1  
        top, bottom = 0, n - 1  
        count = 1 
        target=n*n
        res=zeros(n,n)
        while count <= target:
            #从左到右填充,相当于缩小上边界
            for j in range(left,right):     ##         
                res[top][j] = count
                count+=1
            #缩小上边界
            top+=1
            # 从上向下填充,相当于缩小右边界
            for i in range(top,bottom):    ##
                res[i][right] = count
                count+=1
            #缩小右边界
            right-=1
            #从右到左填充,相当于缩小下边界
            for j in range(right-1,left):
                res[bottom][j] = count
                count+=1
            #缩小下边界
            bottom-=1
            # 从下向上填充,相当于缩小左边界
            for i in range(bottom,top-1):
                res[i][left] = count
                count+=1
            #缩小左边界
            left+=1
        return res   

感觉几点:一个left/right,top/bottom会碰撞

for i in range(bottom,top-1):   range 函数接受三个参数:起始值、结束值和步长,倒序!

在Python中,range(start, stop, step)函数生成一个序列,从start开始,到stop结束(但不包括stop),并且步长为step。当我们从右向左填充时,我们需要从right列开始,到left列结束(不包括left列),因此步长应该是-1

为了确保包括left列的前一列,我们需要将stop参数设置为left-1,因为如果设置为left,由于range函数不包括结束值,那么left列将不会被填充。

同理,四个range边界都要修改,这样就依次填充边界。

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        ## 螺旋矩阵啊,好难拆解的样子

        left, right = 0, n-1
        top, bottom = 0, n-1   
        count = 1 
        target=n*n
        res= [[0]*n for _ in range(n)]

        while count <= target and left<=right and top<=bottom:
            #从左到右填充,相当于缩小上边界
            for j in range(left,right+1):            
                res[top][j] = count
                count+=1
            #缩小上边界
            top+=1

            # 从上向下填充,相当于缩小右边界
            for i in range(top,bottom+1):
                res[i][right] = count
                count+=1
            #缩小右边界
            right-=1
            #从右到左填充,相当于缩小下边界
            for j in range(right,left-1,-1):
                res[bottom][j] = count
                count+=1
            #缩小下边界
            bottom-=1
            # 从下向上填充,相当于缩小左边界
            for i in range(bottom,top-1,-1):
                res[i][left] = count
                count+=1
            #缩小左边界
            left+=1
        return res  

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值