代码随想录算法-day2

  • LeetCode 977.有序数组的平方(补)
  • LeetCode 209.长度最小的子数组
  • LeetCdoe 59.螺旋矩阵II

前言

第二天了,继续坚持!


LeetCode 977.有序数组的平方(补)

题目链接
文章讲解
视频讲解

977-1 原始想法

拿到题目,原数组可能出现负数,要输出non-decreasing的平方数组,直接平方+排序的暴力方法肯定不优雅,考虑使用双指针法。但是,参照第一天LeetCode27的快慢指针也不行,因为排序是一个逐步比较“行进”的过程,当slow包含的数组大小到了2个以上,就要逐个覆写数组的数值,时间复杂度激增。

977-2 随想录提醒

这一次派上了首尾指针法派上了用场。由于题目明确说明原始数组也是non-decreasing的,数组各元素平方之后肯定是从两头到中间递减的,所以只需要指针从数组的两端开始,逐个比对当前指针所指向的元素大小,在放入一个与nums大小相同的新数组result当中即可。执行操作之后,对指针继续更新移位,直至两个指针相遇,就遍历完了所有元素,复杂度为O(n)

977-3 最终题解

class Solution(object):
    def sortedSquares(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        left, right, loc = 0, len(nums)-1, len(nums)-1
        result = [float('inf')] * len(nums)
        # result = nums # 不能直接这样写,这样会造成混乱
        while (left <= right):
            if nums[left]**2 <= nums[right]**2:
                result[loc] = nums[right]**2
                right -= 1
            else:
                result[loc] = nums[left]**2
                left += 1
            loc -= 1
        return result

977-4 Debug过程

上面已经在代码中注明了,不能采用result = nums的写法,因为python中对数组直接采用赋值运算符(也就是“=”)是对原有数组的引用,并非我们以为的复制。可以参考这篇博客


LeetCode 209.长度最小的子数组

题目链接
文章讲解
视频讲解

209-1 原始想法

看到本题很容易想到的就是暴力解法:使用两个for循环嵌套,外层表示区间的起始索引,内层是区间的终止索引,这样也能解出答案,但是效率太低了。

209-2 随想录提醒

使用滑动窗口法(其实和前面提到双指针法本质是一样的,都是比较数据,实现对区间端口索引的更新)。
关于滑动窗口法与暴力法的不同,我的理解是,前者是后者的剪枝,充分运用了“数组在物理上是连续的”这一特性。可能有点绕,下面是详细解释:如果从算法运行的初始几步看,窗口法和暴力法是一致的,起始结点都是0,终止结点依次增加,直到超过或者达到target,之后不同于暴力法继续进入for循环归零“重开”,窗口法采用的是"储存+迭代"的思路,区间内部的元素和用sum来储存(个人觉得这是窗口法的关键一招),变更区间后利用min函数比较新区间的sum和上一区间sum的大小,一路迭代更新,避免了多次重复计算,最终输出全局最小的结果。这样的复杂度只有O(n),也就是把数组遍历一遍的资源。
如果把握住算法的动态性,可以这么看:所选区间的变化无法就两种,即有时向右扩大,有时自左收缩。当然,具体的理解,还是得看代码和随想录的gif。

209-3 最终题解

class Solution(object):
    def minSubArrayLen(self, target, nums):
        """
        :type target: int
        :type nums: List[int]
        :rtype: int
        """
        left, subL = 0, len(nums)+1
        sumValue = 0
        for right in range(0, len(nums)): # 这里与暴力法的两层循环是一样的,都是对数组进行遍历
            sumValue += nums[right]
            while(sumValue >= target): # 这是十分关键的地方
                subL = min(subL, right-left+1)
                sumValue = sumValue - nums[left]
                left += 1
        return subL if subL!=len(nums)+1 else 0

209-4 Debug过程

一开始没有理解滑动窗口法的内核是“用一层遍历循环干两层循环的活”,尤其是上面标注的for循环中while循环的写法,导致和双指针法混淆了。
插一句灵魂拷问:为什么是滑动窗口法的时间复杂度是O(n)?
随想录中也有解释,这里补充以下:要注意与两个for循环嵌套不同,while中的for循环不一定在每次for循环中都会走入,因此不能简单地认为时间复杂度就是n×n。宏观来看,在最坏情况,算法终点时left和right指针同时指向数组的最后一个元素,这一情景下,窗口对每个元素都完成了一次“纳入”和“吐出”的操作,故复杂度时2×n,即O(n)。


LeetCode 59. 螺旋矩阵II

59-1 原始想法

这道题没什么好说的吧,就纯场景模拟,考的就是对代码边界条件的掌控。

59-2 随想录提醒

和二分查找的易错点一样,要注意区间是左闭有开还是左开右闭,这会影响边界条件的处理。显然,上下左右四个方位的区间模式要是一致的,要么左闭右开,要么左开右闭。

59-3 最终题解

class Solution(object):
    def generateMatrix(self, n):
        """
        :type n: int
        :rtype: List[List[int]]
        """
        i, counter = 0, 1
        offset = 1 
        Matrix = [[float('inf')]*n for _ in range(n)]
        while offset <= n//2:
            for j in range(offset-1, n-offset):
                Matrix[offset-1][j] = counter
                counter += 1
            for i in range(offset-1, n-offset):
                Matrix[i][j+1] = counter
                counter += 1                
            for j in range(n-offset, offset-1, -1):
                Matrix[i+1][j] = counter
                counter += 1                
            for i in range(n-offset, offset-1, -1):
                Matrix[i][j-1] = counter
                counter += 1                
            offset += 1
        if n%2==1: Matrix[n//2][n//2]=counter # 如果n为奇数,那么上面的四个for循环无法照顾到矩阵正中间的元素
        return Matrix

59-4 Debug过程

for循环的边界条件一如既往的难调,还是得多练吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值