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

一、今日任务

977.有序数组的平方

文章讲解 视频讲解

209.长度最小的子数组

文章讲解 视频讲解

59.螺旋矩阵II

文章讲解 视频讲解

二、有序数组的平方

2.1 题目:977.有序数组的平方

2.2 解题过程

拿到题目第一时间想到的解法是先一边循环计算平方,再一遍循环排序。

代码如下

class Solution(object):
    def sortedSquares(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        for i in range(0, len(nums)):
            nums[i] = nums[i] * nums[i]
        for i in range(0, len(nums)):
            for j in range(1, len(nums) - i):
                if nums[j] < nums[j-1]:
                    temp = nums[j-1]
                    nums[j-1] = nums[j]
                    nums[j] = temp
        return nums

毫不意外,超时。

也看到了建议在O(n)的时间复杂度里解出来。

其实可以看做一个非有序的数组进行排序。只要找到O(n)的排序方法就行。

这是想到了归并排序。只要找到分段处就可以执行。

代码如下:

def sortedSquares1(self, nums):
    """
    :type nums: List[int]
    :rtype: List[int]
    """
    NewNums = []
    flag = -1
    for i in range(0, len(nums)):
        if nums[i] < 0:
            flag = i
        nums[i] = nums[i] * nums[i]
    if flag == -1:
        return nums
    else:
        n = flag
        p = flag + 1
        i = 0
        while n >= 0 and p < len(nums):
            if nums[n] < nums[p]:
                NewNums.append(nums[n])
                n -= 1
            else:
                NewNums.append(nums[p])
                p += 1
            i += 1
        while i < len(nums) and n >= 0:
            NewNums.append(nums[n])
            n -= 1
            i += 1
        while i < len(nums) and p < len(nums):
            NewNums.append(nums[p])
            p += 1
            i += 1
    return NewNums

但是依然有不足之处,在这里插入图片描述

所以,速度不够,内存耗费多。

2.3 阅读材料改进

文章中指出的双指针法,比自己思考的程度更深一些,发挥这题的特色,节省寻找分段点的时间。

同时,也给出了自己看力扣给出的内存和速度其实并不准确。

即自己是O(2n)的时间复杂度,而文章给出的是O(n)的时间复杂度。

以下是复现代码:

def sortedSquares2(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        NewNums = [None]*len(nums)
        left = 0
        right = len(nums)-1
        i = len(nums) - 1
        while left <= right:#i>=0也对
            if nums[left] * nums[left] > nums[right] * nums[right]:
                NewNums[i] = nums[left] * nums[left]
                left += 1
            else:
                NewNums[i] = nums[right] * nums[right]
                right -= 1
            i -= 1
        return NewNums

三、长度最小的子数组

3.1 题目: 209.长度最小的子数组

3.2 解题过程

注意:N个正整数,和一个正整数target。

要求:连续子数组,满足在原数组里最短的和>=target。如果不存在返回0。

首先的确是一头雾水,又回到算法题的常见模式,无敌复杂脑袋。

那就先思考暴力算法。

超时的暴力解法如下,18/20

class Solution(object):
    # 暴力算法
    def minSubArrayLen(self, target, nums):
        """
        :type target: int
        :type nums: List[int]
        :rtype: int
        """
        MinLen = len(nums) + 1
        for i in range(0, len(nums)):
            sum = 0
            for j in range (i, len(nums)):
                sum += nums[j]
                if sum >= target:
                    if MinLen > j-i+1:
                        MinLen = j-i+1
                    break
        if MinLen == len(nums) + 1:
            return 0
        return MinLen

接着根据提示写出滑动窗口的方法,遇到的问题是遇到满足>=target后的更新问题。

def minSubArrayLen2(self, target, nums):
        """
        :type target: int
        :type nums: List[int]
        :rtype: int
        """
        MinLen = len(nums) + 1
        begin = 0
        end = 0
        sum = 0
        while end < len(nums):
            sum += nums[end]
            if sum >= target:
                if MinLen > end - begin + 1:
                    MinLen = end - begin + 1
                # 重点
                sum -= nums[begin]
                begin += 1
                sum -= nums[end]
                end -= 1
            end += 1
        if MinLen == len(nums) + 1:
            return 0
        return MinLen

3.3 阅读材料改进

3.3.1 滑动窗口知识点

寻找连续子数组应该是非常常用的方法。

滑动窗口包括三点非常重要的地方:

  • 窗口里是什么
  • 起始位置在什么情况下变化
  • 终止位置在什么情况下变化

在本题中,窗口里是sum,当sum>=target时起始位置前移,当sum<target 时终止位置前移。结束条件是遍历完数组。

以下是代码复现:

def minSubArrayLen3(self, target, nums):
        """
        :type target: int
        :type nums: List[int]
        :rtype: int
        """
        MinLen = len(nums) + 1
        begin = 0
        end = 0
        sum = 0
        while end < len(nums):
            sum += nums[end]
            while sum >= target:
                if MinLen > end - begin + 1:
                    MinLen = end - begin + 1
                sum -= nums[begin]
                begin += 1
            end += 1
        if MinLen == len(nums) + 1:
            return 0
        return MinLen

显然会比一个while,彻底解决自己得一个很大的问题。

四 、螺旋矩阵II

4.1 题目: 59.螺旋矩阵II

4.2 解题过程

首先这个题目有够让人闻风丧胆的意味在的。

同样是没有什么头绪。

按照老方法,先暴力再找有没有更好的解法。可是怎么暴力呢。

思考方向,就是为每一个数安排位置。

第一个解法,思路是顺时针嘛,顺序是右下左上,但是,忽略了惯性的原因而导致错误。
在这里插入图片描述

错误代码如下:

# 暴力解法:右下左上,错误解法
def generateMatrix(self, n):
    """
    :type n: int
    :rtype: List[List[int]]
    """
    nums = [[0 for col in range(n)] for row in range(n)]
    val = 1
    row = 0
    col = 0
    while val <= n*n:
        nums[row][col] = val
        if col+1 < n and nums[row][col+1] == 0:
            col += 1
        elif row+1 < n and nums[row+1][col] == 0:
            row += 1
        elif col-1 >= 0 and nums[row][col-1] == 0:
            col -= 1
        elif row - 1 >= 0 and nums[row - 1][col] == 0:
            row -= 1
        val += 1
    return nums

再次尝试,考虑惯性,其中当惯性不满足,只要改变一个方向就一定能走。

代码如下:

class Solution(object):
    # 考虑惯性
    def generateMatrix(self, n):
        """
        :type n: int
        :rtype: List[List[int]]
        """
        nums = [[0 for col in range(n)] for row in range(n)]
        val = 1
        row = 0
        col = 0
        step = 0
        row_step = [0, 1, 0, -1]
        col_step = [1, 0, -1, 0]
        while val <= n * n:
            nums[row][col] = val
            if row+row_step[step] < n and row+row_step[step] >= 0 and\
                    col+col_step[step] < n and col+col_step[step] >= 0 and \
                    nums[row+row_step[step]][col+col_step[step]] == 0:
                row += row_step[step]
                col += col_step[step]
            else:
                step = (step + 1) % 4
                row += row_step[step]
                col += col_step[step]
            val += 1
        return nums

4.3 阅读材料改进

随想录中给的是自己最开始的思路,同时通过随想录发现了自己的错误的解决方法。

可以通过圈层的计算来规避。同时一定要记住左闭右开

以下是改进算法:

def generateMatrix2(self, n):
    """
    :type n: int
    :rtype: List[List[int]]
    """
    nums = [[0 for col in range(n)] for row in range(n)]
    val = 1
    row = 0
    col = 0
    loop, mid = n//2, n//2
    for offset in range(1, loop+1):
        for i in range(col, n-offset):
            nums[row][i] = val
            val += 1
        for i in range(row, n-offset):
            nums[i][n-offset] = val
            val += 1
        for i in range(n-offset, col, -1):
            nums[n-offset][i] = val
            val += 1
        for i in range(n-offset, row, -1):
            nums[i][col] = val
            val += 1
        col += 1
        row += 1

    if n % 2 != 0:  # n为奇数时,填充中心点
        nums[mid][mid] =val
    return nums

五、总结

这两天一共完成了5道题目。

第一道二分查找,复习了二分查找的两个基本方法,左闭右闭和左闭右开。

左闭右闭:

left=0,right=len(nums)-1

while(left<=right)

left = middle+1, right=middle-1

左闭右开:

left=0,right=len(nums)

while(left<right)

left = middle+1, right=middle

第二道 移除元素,学习到了快慢指针法。一个慢定位,一个快查找。

第三道 平方数组,双向指针法,和自己的归并。

第四道 最小子数组,学习到了滑动窗口,这其中最重要的还是窗口里是什么,起始位置变化条件,结束位置变化条件。其中的while真的是非常巧妙。

第五道 螺旋矩阵,顺时针加惯性。

其实还是没有领会到不变性的魅力。希望二刷能够。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值