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

文章讲述了如何使用双指针法优化有序数组平方问题的时间复杂度,介绍了滑动窗口技巧在解决长度最小子数组元素问题上的应用,以及模拟螺旋矩阵生成过程的方法。
摘要由CSDN通过智能技术生成

977.有序数组的平方

 思路:

暴力法:平方后排序,时间复杂度为O(nlogn),不满足条件
双指针法:非递减顺序即从小到大的顺序,平方之后的值是按照当前数值的绝对值决定大小的,0的平方是最小的

  • 有负数和正数的序列,最大值出现在两端
  • 只有 >=0 值的序列,最大值出现在右端
  •  只有 <=0 值的序列,最大值出现在左端

因此,从两端遍历数据,从返回数组的末尾填充数据可以满足条件

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        left = 0
        right = len(nums) - 1
        res = [0] * len(nums)
        index = len(nums) - 1
        while left <= right:
            if nums[left] ** 2 <= nums[right] ** 2:
                res[index] = nums[right] ** 2
                right -= 1
            else:
                res[index] = nums[left] ** 2
                left += 1
            index -= 1
        return res

209.长度最小的子数组元素

最开始考虑暴力的写法,小case能通过,大case超时。看了文档之后用了滑动窗口,以窗口右侧(即结束窗口)索引进行遍历,左侧窗口逐渐移动,值得学习。

注意:Python中的无限大使用float('inf')表示

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        # 暴力解法,双重循环,超时
        # size = len(nums)
        # res = float('inf')
        # for i in range(size):
        #     tmp = nums[i]
        #     for j in range(i+1, size+1):
        #         if tmp >= target and j-i < res:
        #             res = j-i
        #             break
        #         if j == size:
        #             break
        #         tmp += nums[j]
        #     if tmp >= target and j - i < res:
        #         res = j - i
        # return 0 if res > size else res

        # 暴力解法,上面写的比较乱,参考文档重写一遍
        size = len(nums)
        res = float('inf')
        for i in range(size):
            cur_sum = 0
            for j in range(i, size):
                cur_sum += nums[j]
                if cur_sum >= target:
                    res = min(res, j-i+1)
                    break
        return res if res != float('inf') else 0



# 滑动窗口,很精妙的写法,没有想出来
class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        # 滑动窗口
        i = 0  # i为滑动窗口的左边,j为滑动窗口的右边
        res = float('inf')
        cur_sum = 0

        # 以窗口右边索引进行遍历
        for j in range(len(nums)):
            cur_sum += nums[j]
            while cur_sum >= target:
                res = min(res, j-i+1)
                cur_sum -= nums[i]
                i += 1
        return res if res != float('inf') else 0

59.螺旋矩阵II

看题解之前的思路

模拟螺旋矩阵的过程 i为行,j为列 比如n为4,i 0 j 0-3, j 3 i 1-3, i 3 j 2-0, j 0 i 2-1, i 1 j 1-2, j 2 i 2, i 2 j 1 这个过程的规律在哪里?看不出来

看了解题思路之后

确实是模拟的思路,但是模拟是有技巧的,需要有规律。和二分查找的区间规定是类似的,遵循区间定义为不变量

比如n为4,区间为左闭右开,可以看出每一圈能够构成一个循环。一次循环可以填充两行两列,偶数的循环次数为/2,奇数的循环次数也是/2,但是奇数需要最后处理中间的数值。

循环一:i 0 j 0-2, j 3 i 0-2, i 3 j 3-1, j 0 i 3-1 起始为0,0

循环二:i 1 j 1, j 2 i 1, i 2 j 2, j 1 i 2 起始为1,1

每一个循环内有四条边,四条边没什么联系,但是不同循环内的相同边规律相同(边界有所不同),因此每条边都可以写一个循环来实现。

注意:Python中[[0]*n]*n会把[0]*n拷贝n次,需要用 res = [[0] * n for _ in range(n)]

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        loop = n // 2  # 循环次数
        # res = [[0] * n] * n  # 结果值,注意考虑python特性,这种写法是错误的
        res = [[0] * n for _ in range(n)]
        count = 1  # 计数值
        offset = 1  # 限制边界值
        startx = 0  # 每次循环开始的位置
        starty = 0  # 每次循环开始的位置

        while loop > 0:
            # 开始对每条边的过程进行模拟,考虑n为4
            # 循环一:i 0 j 0-2, j 3 i 0-2, i 3 j 3-1, j 0 i 3-1 起始为0,0
            # 循环二:i 1 j 1, j 2 i 1, i 2 j 2, j 1 i 2  起始为1,1
            for j in range(starty, n-offset):
                res[startx][j] = count
                count += 1

            for i in range(startx, n-offset):
                res[i][n-offset] = count
                count += 1

            for j in range(n-offset, starty, -1):
                res[n-offset][j] = count
                count += 1

            for i in range(n-offset, startx, -1):
                res[i][starty] = count
                count += 1

            loop -= 1
            startx += 1
            starty += 1
            offset += 1

        if n % 2 != 0:
            res[n//2][n//2] = count

        return res

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值