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

今日总结:

  1. 我会用列表推导法啦!
  2. 不用太在意超过xx人,只要自己分析的出来算法复杂度就可以了!
  3. 滑动窗口也可以理解为双指针法的一种,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
  4. 注意python的引用,建议初始化列表只用一种方法。

1. 有序数组的平方977

力扣题目链接

文档讲解

视频讲解:《代码随想录》算法视频公开课 (opens new window)双指针法经典题目!LeetCode:977.有序数组的平方 (opens new window)

状态:先用暴力法做出来了一遍,然后尝试用了双指针和pop(没做出来,就差一步,不用pop就行)

题目如下——

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

示例 1:

  • 输入:nums = [-4,-1,0,3,10]
  • 输出:[0,1,9,16,100]
  • 解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]

示例 2:

  • 输入:nums = [-7,-3,2,3,11]
  • 输出:[4,9,9,49,121]

【要素察觉】双指针

  • 有序数组
  • 如果存在负数,中间值最小

【代码实现】

(暴力)先平方再排序

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        # 暴力法
        res = [num * num for num in nums]
        res.sort()  # 任意排序算法皆可
        return res

(双指针)while

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        l, r, i = 0, len(nums)-1, len(nums)-1
        res = [float('inf')] * len(nums) # 需要提前定义列表,存放结果
        while l <= r:
            if nums[l] ** 2 < nums[r] ** 2: # 左右边界进行对比,找出最大值
                res[i] = nums[r] ** 2
                r -= 1 # 右指针往左移动
            else:
                res[i] = nums[l] ** 2
                l += 1 # 左指针往右移动
            i -= 1 # 存放结果的指针需要往前平移一位
        return res

2. 长度最小的子数组209

力扣题目链接(opens new window)https://leetcode.cn/problems/remove-element/)

文档讲解

视频讲解:《代码随想录》算法视频公开课 (opens new window)拿下滑动窗口! | LeetCode 209 长度最小的子数组

状态:自己做出来的!滑动窗口!

题目如下——

给定一个含有 n 个正整数的数组和一个正整数 target

找出该数组中满足其总和大于等于 target 的长度最小的 连续 子数组

[numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。**如果不存在符合条件的子数组,返回 0

【要素察觉】滑动窗口

所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果

209.长度最小的子数组

其实从动画中可以发现滑动窗口也可以理解为双指针法的一种!只不过这种解法更像是一个窗口的移动,所以叫做滑动窗口更适合一些。

在本题中实现滑动窗口,主要确定如下三点:

  • 窗口内是什么? -> 满足其和 ≥ s 的长度最小的 连续 子数组。
  • 如何移动窗口的起始位置? -> 如果当前窗口的值大于等于s了,窗口就要向前移动了(也就是该缩小了)。
  • 如何移动窗口的结束位置?-> 窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

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

思路一:暴力解法

27.移除元素-暴力解法

思路二:快慢指针

27.移除元素-双指针法

【代码实现】

(暴力解法)for + for循环,只要不符合条件就break

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

(滑动窗口) 本质是双指针,改变了索引位置

class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        l = len(nums)
        left = 0
        right = 0
        min_len = float('inf')
        cur_sum = 0 #当前的累加值
        
        while right < l:
            cur_sum += nums[right]
            
            while cur_sum >= s: # 当前累加值大于目标值
                min_len = min(min_len, right - left + 1)
                cur_sum -= nums[left]
                left += 1
            
            right += 1
        
        return min_len if min_len != float('inf') else 0

【练习题】

3. 螺旋矩阵II 59

力扣题目链接

文档讲解

视频讲解:《代码随想录》算法视频公开课 (opens new window)拿下螺旋矩阵!LeetCode:59.螺旋矩阵II

状态:初始化有问题;用了20min,一开始会陷入超过时间限制的问题。

题目如下——

给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

示例:

输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]

【思路】模拟

面试中出现频率较高的题目,本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。

大家还记得我们在这篇文章数组:每次遇到二分法,都是一看就会,一写就废 (opens new window)中讲解了二分法,提到如果要写出正确的二分法一定要坚持循环不变量原则

而求解本题依然是要坚持循环不变量原则。

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

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

由外向内一圈一圈这么画下去。

可以发现这里的边界条件非常多,在一个循环中,如此多的边界条件,如果不按照固定规则来遍历,那就是一进循环深似海,从此offer是路人

这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。

【代码实现】

(直接按照思路模拟)

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

[注意] python语言的引用问题

初始化认准:[0 for _ in range(n)],别的会共用地址。

Python:正确生成列表的方法

image-20240418234515617

【练习题】

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值