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

文档讲解:代码随想录

视频讲解:代码随想录B站账号

状态:看了视频题解和文章解析后做出来了

977. 有序数组的平方

暴力解法

拿到题目后一开始使用的是暴力解法:

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

思路就是首先算出每一个元素的平方,然后再对新数组进行排序。

复杂度:与排序算法复杂度一致

双指针解法

看完视频和文档后学习到了优化的题解:

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        res = []
        left, right = 0, len(nums)-1

        while left <= right:
            if nums[left] ** 2 < nums[right] ** 2:
                res.insert(0, nums[right] ** 2)
                right -= 1
            else:
                res.insert(0, nums[left] ** 2)
                left += 1

        return res

这段代码用到了双指针的思路,因为原数组就已经是从大到小排列了,那么平方后的最大值肯定出现在数组的两端而非中央。

所以我们将左指针指向数组的第一个元素,右指针指向最后一个元素,通过对比两个元素的大小,把平方更大的元素加入到新的列表中,然后收敛指针。

循环的条件是当左指针小于等于右指针,之所以加上等于号,是因为当两个指针同时指向一个元素的时候,这个元素的值也需要被加入到结果列表中。不加等号就会忽略掉这个元素。

复杂度:O(n)

209.长度最小的子数组

暴力解法

照例先来个暴力解法

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        res = math.inf
        for i in range(len(nums)):
            for j in range(i, len(nums)):
                if sum(nums[i:j+1]) >= target:
                    res = min(res, j-i+1)

        if res == math.inf:
            res = 0

        return res

 没有通过全部的test case,因为时间复杂度太高

复杂度:O(n^2)

滑动数组

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        i = 0 # initial position
        sums = 0
        res = math.inf

        for j in range(len(nums)):
            sums += nums[j] # expand the right side, add the value to sums
            while sums >= target:
                res = min(res, j-i+1) # if greater than target, update length to res
                sums -= nums[i] # subtract the value of the left side
                i += 1 # move left side to find minimum length

        if res == math.inf:
            return 0

        return res

滑动数组的思路是滑动右侧数组,直到数组包含的元素之和大于等于target值,然后滑动左侧数组缩小数组长度,不断更新数组长度直到缩小到比target小。

看到题解前我使用了双指针的解法,但无法遍历到所有可能性的数组。滑动数组的方法可以保证遍历到结果是因为它在滑动右侧的时候就测试了结果数组是右侧结尾的可能性,这就已经包含了全部的可能性了。非常精妙。

复杂度:O(n)

59.螺旋矩阵II

直接上代码:

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        nums = [[0] * n for _ in range(n)]
        start = 0
        count = 1
        loop, mid = n // 2, n // 2

        for offset in range(1, loop + 1):
            for i in range(start, n - offset): # 左闭右开
                nums[start][i] = count
                count += 1
            for i in range(start, n - offset):
                nums[i][n - offset] = count
                count += 1
            for i in range(n-offset, start, -1):
                nums[n - offset][i] = count
                count += 1
            for i in range(n-offset, start, -1):
                nums[i][start] = count
                count += 1

            start += 1

        if n % 2 == 1:
            nums[mid][mid] = count

        return nums

                

                

核心思想:

1. 使用左闭有开的方式遍历正方形的每一条边,使得每次遍历的模式一定

2. 使用offset变量作为遍历圈数的计数,确定每一轮遍历的边界

3. 使用start确定当前遍历的圈数,作为起始点

4. 判断n是否为奇数,如果是奇数,最中心的点需要手动赋值

优化:

将卡尔老师代码中的startx, starty优化为一个start变量,因为一次遍历中x和y的起始点一致,所以不需要两个变量来控制。

复杂度:O(n^2)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值