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

文章介绍了如何使用双指针法优化有序数组的平方问题,从暴力破解的O(nlogn)降低到O(n)的时间复杂度。同时,讨论了滑动窗口在解决寻找最小子数组长度问题中的应用,提供了一种更高效的O(n)解决方案。此外,还讲解了构建螺旋矩阵的循环不变原则方法。
摘要由CSDN通过智能技术生成

977.有序数组的平方

题目链接:力扣

视频链接:双指针法经典题目 | LeetCode:977.有序数组的平方_哔哩哔哩_bilibili

初印象:首先的思路是“求平方+排序”,简洁清晰,但缺点在于时间复杂度为O(n + nlogn) = O(n)。那么,有没有优化的方案呢?

学习提升:之前“二分查找”中使用了双指针的方法,而这道题目可以借鉴。由于数组是有序的,如果全是正数(可以包括0)或者全是负数(可以包括0)那么只需要求平方,不需要排序。但问题麻烦就麻烦在同时有负数和正数时,求平方之后会导致顺序变化。

而这一点也是双指针法的关键所在,由于数组是有序的,所以求平方之后,两头的数值一定是最大的,所以只需要从两边向中间逐个比较左右两边的数值大小,将较大的数从后向前放入结果数组。

这里我设了一个flag用来指示当前应该插入结果数组的位置。

# 暴力破解
class Solution(object):
    def sortedSquares(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        results = []
        for num in nums:
            results.append(num ** 2)
        results.sort()
        
        return results

# 双指针法
class Solution(object):
    def sortedSquares(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        num_len = len(nums)
        results = range(0,num_len)
        flag = num_len - 1
        leftindex = 0
        rightindex = num_len - 1
        while leftindex <= rightindex and flag >= 0:
            left_num = nums[leftindex] ** 2
            right_num = nums[rightindex] **2
            if left_num < right_num :
                results[flag] = right_num
                rightindex -= 1
            else:
                results[flag] = left_num
                leftindex += 1
            flag -= 1
        return results

        

复杂度分析:暴力破解法O(nlogn)、双指针法O(n)


209.长度最小的子数组

题目链接:力扣

视频链接:拿下滑动窗口! | LeetCode 209 长度最小的子数组_哔哩哔哩_bilibili

初印象:刚开始拿到题目,觉得有些复杂,尤其是要找到长度最小的子数组,排列组合的知识突然攻击我(>_<!)。冷静下来之后,看到可以对数组中的元素进行挨个搜索,使用一个for循环和一个while循环来解决,for循环用来遍历数组中的每个元素,while循环用来确定每个元素满足条件的最短连续子数组。

学习提升:学习了代码随想录中的滑动窗口之后,有种豁然开朗的感觉。分析了一下,滑动窗口适用于需要连续的子数组满足一定的逻辑条件的问题,能够一边判断,一边移动窗口,将两个循环简化为一个循环。

# 暴力破解法,下次刷的时候补!

# 滑动窗口法
class Solution(object):
    def minSubArrayLen(self, target, nums):
        """
        :type target: int
        :type nums: List[int]
        :rtype: int
        """
        i = 0
        sub_sum = 0
        results = len(nums)
        for j in range(len(nums)):
            sub_sum += nums[j]
            while sub_sum >= target:
                subL = j - i + 1
                results = min(results,subL)
                sub_sum -= nums[i]
                i += 1
        if i == 0:
            return 0
        else:
            return results

复杂度分析:暴力破解法O(n^2)、 滑动窗口法O(n)

59.螺旋矩阵II

题目链接:力扣

视频链接:一入循环深似海 | LeetCode:59.螺旋矩阵II_哔哩哔哩_bilibili

初印象:题目意思很容易理解,而且思路也并不复杂,但是就是简单的操作需要重复做,麻烦。属于是想起来好像很简单,但是实现起来有些繁琐,特别容易出错。

学习提升:从代码随想录中学到的“循环不变原则”非常有用,由于每一步得到规则是统一的,因此,在处理边界的时候,能够很好地避免出错,整个按照这个思路写下来,十分清晰,不得不说,循环不变原则yyds!

class Solution(object):
    def generateMatrix(self, n):
        """
        :type n: int
        :rtype: List[List[int]]
        """
        startx = 0
        starty = 0
        offset = 1
        loop = n / 2
        count = 1
        results = [[0] * n for _ in range(n)]
        for _ in range(loop):
            i = startx
            j = starty
            # 从左向右
            while j < n -offset:
                results[i][j] = count
                count += 1
                j += 1
            # 从上向下
            while i < n -offset:
                results[i][j] = count
                count += 1
                i += 1
            # 从右向左
            while j > starty:
                results[i][j] = count
                count += 1
                j -= 1
            # 从下向上
            while i > startx:
                results[i][j] = count
                count += 1
                i -= 1
            startx += 1
            starty += 1
            offset += 1
        if n % 2 == 1:
            results[loop][loop] = n ** 2

        return results

复杂度分析:O(n^2)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值