代码随想录算法训练营第二天 | 977.有序数组的平方,209.长度最小的子数组,59.螺旋矩阵II

977.有序数组的平方

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

暴力排序

 先平方再排序,刚开始犯了几个小错误:

1. 平方计算是num**2或者pow(num,2)

2. python排序函数是sort(),默认升序,reverse = ture降序

解出来如下:

class Solution(object):
    def sortedSquares(self, nums):
        nums_out = []
        for i in range(len(nums)):
            nums_out.append(nums[i]**2)
        
        nums_out.sort()
        
        return nums_out

时间复杂度:O(n+nlogn)

 双指针法

用处:数组是有序的, 只不过有负数,数组平方的最大值就在数组的两端

方法: i指向起始位置,j指向终止位置;定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置

如果A[i] * A[i] < A[j] * A[j] 那么result[k--] = A[j] * A[j]; 。

如果A[i] * A[i] >= A[j] * A[j] 那么result[k--] = A[i] * A[i]; 。

看完思路后写出代码出现一点小问题:

1. while i <= j 不能写成i>0 and j<l,要保证双指针位置

2. 想import numpy创建数组有点问题nums_out = np.empty(l,dtype = float)

最终如下:

class Solution(object):
    def sortedSquares(self, nums):
        l = len(nums)
        nums_out = [float('inf')]*l
        k = l-1
        i = 0
        j = l-1

        while i <= j:
            if nums[i]**2 <= nums[j]**2:
                nums_out[k] = nums[j]**2
                j -= 1
            else: 
                nums_out[k] = nums[i]**2
                i += 1
            k -= 1

        return nums_out

时间复杂度:O(n)

看了解析python还有一个暴力排序法+列表推导法:

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        return sorted(x*x for x in nums)

 

209.长度最小的子数组

题目:给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的连续子数组[numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

暴力解法

超出时间限制了:

class Solution(object):
    def minSubArrayLen(self, target, nums):
        l = len(nums)
        result = l+1
        for i in range(l):
            s = 0
            for j in range(i,l):
                s += nums[j]
                if s >= target:
                    out_l = j-i+1
                    result = min(out_l, result)
                    break
        if result == l+1: result = 0
        return result

几个注意的语法问题:

1. 这里的result可以定义为float('inf')好像蛮常用的 

2. 条件满足直接break

3. 最后的判断可以写得更简洁

return min_len if min_len != float('inf') else 0

时间复杂度:O(n^2)

空间复杂度:O(1)

 

滑动窗口

滑动窗口:在于根据当前子序列和大小的情况,不断调节子序列的起始位置

只用一个for循环,那么这个循环的索引,一定是表示滑动窗口的终止位置

确定三点: 

窗口:满足其和 ≥ s 的长度最小的连续子数组

窗口的起始位置:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)

窗口的结束位置:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引

关键在于对窗口起始位置的移动,减去sum里的值

刚开始是这么写的:

class Solution(object):
    def minSubArrayLen(self, target, nums):
        l = len(nums)
        result = float('inf')
        i = 0
        s = 0
        for j in range(l):
            s += nums[j]
            if s >= target:
                out_l = j-i+1
                result = min(out_l, result)
                s -= nums[i]
                i += 1

        if result == float('inf'): result = 0
        return result

出现了问题,问了gpt才知道:

用if 对s进行判断,对窗口减去值只进行了一次,例如,如果target是7,数组是[2,3,1,2,4,3],当窗口扩展到包含前五个元素时,总和为12,这时仅仅减去窗口的第一个元素(即2)并向前移动i一次,可能并不足以使窗口的和小于target,而是应该继续移动i直到窗口的总和再次小于target,然后再次尝试扩展窗口来寻找可能的更小的满足条件的窗口。

所以这里应该使用一个while循环来不断地尝试缩小窗口的大小(即移动i),直到窗口的总和小于target为止,然后再继续尝试扩展窗口。这样可以确保总是找到最小长度的满足条件的子数组。

修改如下:

class Solution(object):
    def minSubArrayLen(self, target, nums):
        l = len(nums)
        result = float('inf')
        i = 0
        s = 0
        for j in range(l):
            s += nums[j]
            while s >= target:
                out_l = j-i+1
                result = min(out_l, result)
                s -= nums[i]
                i += 1

        if result == float('inf'): result = 0
        return result

时间复杂度:O(n)

空间复杂度:O(1)

 

59.螺旋矩阵II

题目:给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

刚拿到毫无思路www,转头去看解析。

坚持循环不变量原则

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

 这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。

说的很好,但是本菜鸟还是没懂,去看了眼代码,自己写了一遍:

class Solution(object):
    def generateMatrix(self, n):
        matrix = [[0 for i in range(n)] for i in range(n)]
        loop = n//2
        center = n//2
        x = 0
        y = 0
        count = 1

        for offset in range(1,loop+1):
            for i in range(y,n-offset):
                matrix[x][i] = count
                count += 1
            for i in range(x,n-offset):
                matrix[i][n-offset] =count
                count += 1
            for i in range(n-offset,y,-1):
                matrix[n-offset][i] = count
                count += 1
            for i in range(n-offset,x,-1):
                matrix[i][y] = count
                count += 1
            x += 1
            y += 1
        
        if n%2 != 0: matrix[center][center] = count
        return matrix

刚开始犯了个错误,for逆循环的时候没有加-1步长,导致range的起始值大于结束值,而默认步长为 1,这意味着循环体不会被执行。

时间复杂度 O(n^2): 模拟遍历二维矩阵的时间

空间复杂度 O(1)

数组总结 

二分法:循环不变量原则 

双指针法:通过一个快指针和慢指针在一个for循环下完成两个for循环的工作

滑动窗口: 根据当前子序列和大小的情况,不断调节子序列的起始位置

模拟行为:循环不变量原则

  • 19
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值