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



人生没那么多观众的呢?为什么昨天晚上两点钟写的博客早上起来居然几百个人看过了。。。。

977.有序数组的平方

题目链接
讲解链接
在这里插入图片描述

思路

时间复杂度复杂度取决于排序,快排是O(nlogn)这里介绍双指针O(n)
分析:新数组是递增的,原来是从负数开始的递增的

快排暴力冒泡等排序方法以后补充
def bubble_sort(arr):
    n = len(arr)
    for i in range(n):
        for j in range(0, n-i-1):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr
def quick_sort(arr):
    if len(arr)<=1:
        return arr
    else:
        middle = len(arr)//2
        left = [x for x in arr if x<arr[middle]]
        middle_ele = [arr[middle]]
        right = [x for x in arr if x>arr[middle]]
        return quick_sort(left)+middle_ele+quick_sort(right)

双指针排序

因为题目中从负数开始的,所以这个排序有点特殊;
那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间,中间是最小值
方法:双指针法,i指向起始位置,j指向终止位置。
定义一个新数组result,和A数组一样的大小,让k一开始指向result数组终止位置,从后往前放。【因为i和j起始的位置是最大值,而新数组要求排序为从小到大,所以是从后往前放】

class Solution(object):
    def sortedSquares(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        n = len(nums)
        i, j, k= 0, n-1, n-1 #分别标注原来数组的开头和结尾
        nums_new = [0] * n 
        while i <= j:
            if nums[i]**2 < nums[j]**2:
                nums_new[k] = nums[j]*nums[j]
                j -= 1
             else: #包括了等于的情况
                nums_new[k] = nums[i]*nums[i]
                i += 1
            k -= 1
        return nums_new

209.长度最小的子数组

题目链接
讲解链接
在这里插入图片描述
在这里插入图片描述

方法一、滑动窗口法

【非常巧妙🥰】

所谓滑动窗口,就是不断的调节子序列的起始位置终止位置,从而得出我们要想的结果
✨for循环中的应该是窗口的终止位置,也就是说我们这个终止位置遍历一次到最后就结束了。
这样就可以保证时间复杂度为O(n);这里可以看一下讲解文章里面的动图,简单易懂。


🎉我的理解寻找每个终止位置j对应的最小窗口,最后取这些最小窗口里面的最小值 先j后i,依次滑动
具体:固定i,j先滑动,找到满足S的j之后,再向后滑动i,找到满足S、在固定j的情况下最小的j-1;再固定i,滑动j,重复操作
更具体:起始位置为i(初始为0),终止位置开始从头滑动到窗口里面的和为S,接着缩小窗口(即,移动i到最短的满足S条件的窗口)找到当前j中最大的i;再固定i,继续滑动j,重复操作;

  • 窗口的起始位置如何移动:如果当前窗口的值大于等于s了,窗口就要向前移动了(也就是该缩小了)。再去移动
  • 窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。


给的都是python3的代码,所以我写了python的

记录自己写代码注意点
  1. range是不包括最后一个的,如果要遍历到最后,range(len(list)),不要减一啊啊啊
  2. cur_len = j - i + 1和len_min = cur_len if cur_len < len_min else这两行代码可以 len_minmin_len = min(min_len, right - left + 1)
def minSubArrayLen(self, target, nums):
    """
    :type target: int
    :type nums: List[int]
    :rtype: int
    """
    i,n = 0, len(nums)
    len_min = n+1
    sum_ = 0
    for j in range(n): #range是不包括最后一个的,这里还是错
        sum_ += nums[j]
        while sum_ >= target:#注意这里要是while而不是if,因为i往后可能会滑动不止一次
            sum_ -= nums[i]
            # cur_len = j - i + 1
            # len_min = cur_len if cur_len < len_min else len_min
            len_min = min(j-i+1,len_m)
            i += 1
    return len_min if len_min < n +1 else 0

方法二 暴力求解

标准答案的优雅的代码:

class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        l = len(nums)
        min_len = float('inf')
        
        for i in range(l):
            cur_sum = 0
            for j in range(i, l):
                cur_sum += nums[j]
                if cur_sum >= s:
                    min_len = min(min_len, j - i + 1)
                    break
        
        return min_len if min_len != float('inf') else 0

不知道为什么自己写就一堆bug

"""
自己暴力求解,双层遍历,结果最后超出时间。各种debug==
"""
class Solution(object):
    def minSubArrayLen(self, target, nums):
        """
        :type target: int
        :type nums: List[int]
        :rtype: int
        """
        start, stop = 0, len(nums) - 1
        len_min = len(nums) + 1
        while start < stop:
            sum_ = nums[start]
            if sum_ >=target:
                len_cur = 1 #设置为第一个的特殊情况
                len_min = len_cur if len_cur < len_min else len_min
                return 1
            for i in range(start + 1, stop+1):
                sum_ += nums[i]
                if sum_ >= target:
                    len_cur = i - start +1
                    len_min = len_cur if len_cur < len_min else len_min
                    break
            start += 1
        if nums[-1] == target:#补充为最后一个的特殊情况
            return 1
        return len_min if len_min < len(nums)+1 else 0

59.螺旋矩阵

题目链接
讲解链接
在这里插入图片描述

在这里插入图片描述
这道题目可以说在面试中出现频率较高的题目**,本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力**。

思路

气死我了,昨天写的思路没有保存啊啊啊啊啊狗屎
总体理解:一圈一圈地写,先写第一圈写完再写第二圈里面,不要跟着图示绕;奇数圈额外判别一下

要坚持循环不变量原则:例如下面这个图就是坚持左闭右开原则。

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上
    由外向内一圈一圈这么画下去。
    在这里插入图片描述

标准代码一

矩阵的x和y用startx, starty, offset来表征,而不是像我,i和j会被上一条边影响

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        nums = [[0] * n for _ in range(n)]
        startx, starty = 0, 0               # 起始点
        loop, mid = n // 2, n // 2          # 迭代次数、n为奇数时,矩阵的中心点
        count = 1                           # 计数

        for offset in range(1, loop + 1) :      # 每循环一层偏移量加1,偏移量从1开始
            for i in range(starty, n - offset) :    # 从左至右,左闭右开
                nums[startx][i] = count
                count += 1
            for i in range(startx, n - offset) :    # 从上至下
                nums[i][n - offset] = count
                count += 1
            for i in range(n - offset, starty, -1) : # 从右至左
                nums[n - offset][i] = count
                count += 1
            for i in range(n - offset, startx, -1) : # 从下至上
                nums[i][starty] = count
                count += 1                
            startx += 1         # 更新起始点
            starty += 1

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

标准代码二

使用了四个边界,没有用offset这个变量

class Solution(object):
    def generateMatrix(self, n):
        if n <= 0:
            return []
        
        # 初始化 n x n 矩阵
        matrix = [[0]*n for _ in range(n)]

        # 初始化边界和起始值
        top, bottom, left, right = 0, n-1, 0, n-1
        num = 1

        while top <= bottom and left <= right:
            # 从左到右填充上边界
            for i in range(left, right + 1):
                matrix[top][i] = num
                num += 1
            top += 1

            # 从上到下填充右边界
            for i in range(top, bottom + 1):
                matrix[i][right] = num
                num += 1
            right -= 1

            # 从右到左填充下边界

            for i in range(right, left - 1, -1):
                matrix[bottom][i] = num
                num += 1
            bottom -= 1

            # 从下到上填充左边界

            for i in range(bottom, top - 1, -1):
                matrix[i][left] = num
                num += 1
            left += 1

        return matrix

自己写的注意点记录

  1. python创建指定大小矩阵的方法:nums = [[0] * n for _ in range(n)]
  2. 思想:关于奇数和偶数的区别,自己想的时候想复杂了,奇数只要最后判别一下就行。其余的都是绕圈
  3. 关于第二圈开始的i,具体为每轮循环结束后i要不要减一,是debug才知道的
  4. 粗心:忘了平方和return
class Solution(object):
    def generateMatrix(self,n):
        """
        :type n: int
        :rtype: List[List[int]]
        """
        startx, starty = 0, 0
        offset = 0
        count = 1
        i, j = 0, 0
        nums = [[0] * n for _ in range(n)]  # python初始化nxn矩阵的方法!!记住
        epoch = 1
        while (epoch <= n // 2):
            # 先写第一行
            for j in range(starty + offset, n - 1 - offset):  # 第一条边从左往右
                nums[i][j] = count
                count += 1
            j += 1  # 下一条边的起始位置应该是:之前没有包括的最后一个元素
            for i in range(startx + offset, n - 1 - offset):  # 第二条边从上往下
                nums[i][j] = count
                count += 1
            i += 1
            for j in range(n - 1 - offset, starty + offset, -1):
                nums[i][j] = count
                count += 1
            j -= 1
            for i in range(n - 1 - offset, startx + offset, -1):
                nums[i][j] = count
                count += 1
            # i -= 1 #这里的i是不是要减一debug了一下
            offset += 1
            epoch += 1
        if n % 2 == 1:
            nums[n // 2][n // 2] = n * n  # 最后忘了平方了
        return nums  # 忘了return

总结

今天组会效果还是不好,晚上错过了跟大老板的讨论,还是yy了一会儿,来不及第三题了,以后绝不会在没写完博客之前看手机。这么不顺利的时候心态真的很容易崩溃。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值