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

977.有序数组的平方

文章讲解:代码随想录

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

思路:

暴力法:阅读完题目的第一想法就是先对数组中每个数值进行平方,然后排序。题目强调了非递减顺序,因此应该是从小到大排序。我先对数组中的数值循环平方后,使用了冒泡排序法进行排序。以下是我的代码:

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]
        # 冒泡排序
        for m in range(len(nums) - 1):
            for n in range(len(nums) - m - 1):
                if nums[n+1] < nums[n]:
                    nums[n], nums[n+1] = nums[n+1],nums[n]
        return nums

 很明显这种方法的时间复杂度是很高的,为O(n + nlogn),在查看了文章解析后,学习到了双指针法,根据昨天的学习经验,双指针法在解决数组这类问题中非常重要,要好好掌握。

双指针法:原数组本身是有序的,在平方后,数组中数值的位置会发生改变。不难理解,数组平方后的最大值一定在原数组的两端,此时就可以考虑双指针法。用两个指针来比较原数组左右两端平方后的数值,创建一个和原数组一样大的新数组,从最末端开始存放最大值,以此类推。代码如下:

左右指针:原数组的左右两端

i 指针:新数组的最右端即最末端 

class Solution(object):
    def sortedSquares(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        left, right, i = 0, len(nums) - 1, len(nums) - 1  # 定义三个指针,left和right指针分别在原数组的左右两端,i指针在新数组的末端
        new_nums = [float('inf')] * len(nums)  # 定义一个新数组用来存放平方后的数值,float('inf')表示正无穷大的浮点数
        while left <= right:
            if nums[left] ** 2 < nums[right] ** 2:  # 如果右边指针所指数值平方后大于左边数值的平方,则将右边指针所指数值的平方值放在新数组的最末端
                new_nums[i] = nums[right] ** 2
                right -= 1 # 此时右指针需要往前一位,看下一个数值的平方
            else:
                new_nums[i] = nums[left] ** 2  # 同理,左边指针所指数值的平方大于右边指针所指数值的平方
                left += 1
            i -= 1 # 从最末端开始添加数值,添加一个后往前移一位
        return new_nums
            

双指针的时间复杂度为O(n) ,与暴力法比提高了很多。

 209.长度最小的子数组

文章讲解:代码随想录

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

思路:拿到题目后最直接的想法就是通过两层循环遍历,把所有数值和得出然后取最小长度,但是显然这种方法的时间复杂度很高为O(n^2)。训练营提示了这道题应该用滑动窗口的思路来做。

滑动窗口:简单来说,有两个指针分别称作左指针和右指针。左右指针之间的范围即为窗口。两个指针都是从数组的0位置起,右指针最先往右移动,左指针保持在原地,当窗口内的值的和大于等于目标值即符合题意时,右指针停止移动。此时通过移动左指针来找到窗口内符合题意的最小长度。代码中详细写了注释如下:

左右指针:区间内表示窗口

class Solution(object):
    def minSubArrayLen(self, target, nums):
        """
        :type target: int
        :type nums: List[int]
        :rtype: int
        """
        left = 0  # 代表窗口的起始位置,初始化为0
        right = 0  #代表窗口的终止位置,初始化为0
        sum = 0 #当前窗口中的所有数值的累加值
        min_length = float('inf')  # 最小长度
        sub_length = 0  # 右指针停止移动时的子序列长度

        while right < len(nums):  # 当右指针移动范围没有超过总长度时,右指针从0一直向右移动
            sum += nums[right]  # 计算右指针移动范围内值的总和
            while sum >= target:  # 如果该值大于等于目标值,右指针停止移动
                sub_length = right - left + 1  # 此时左指针向右移动,计算左右指针之间范围内的长度
                min_length = min(min_length, sub_length) # 取最小值即题目所求
                sum -= nums[left] # 此时总和应该减去左指针移动过的值才是窗口范围内的总和
                left += 1  # 左指针移动一次加一
            right += 1  # 如果一直没有满足右指针移动范围内值的总和大于等于目标值,右指针一直向右移动加一
        return min_length if min_length != float('inf') else 0  # 最终如果找到最小值返回最小长度,如果没有满足题目要求则返回0

滑动窗口法的时间复杂度为O(n),和暴力法相比大大提高了运行效率。

59.螺旋矩阵II

文章讲解:代码随想录

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

思路:读完题目后一脸懵,直接就看了视频讲解。这道题的关键就是明确好转一圈各边的边界,通过遵循左闭右开的原则,能够使每一边遵循同样的原则将这一圈走完。代码的核心部分就是定义好矩阵螺旋排序的起始位置和终止位置。代码以及详细的注释如下:

nums :n X n 矩阵里应该存放的数值

startX, startY:起始点的位置

class Solution(object):
    def generateMatrix(self, n):
        """
        :type n: int
        :rtype: 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):  # offset代表偏移量,为了保证每一边的遍历都是左闭右开,第一圈开始偏移一,逐圈增加
            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

时间复杂度为O(n^2)。

今日心得:

首先关于有序数组的平方,学习到了使用双指针来解决,左右指针从数组两端开始计算数值的平方,依次将最大值放入新的数组中,这道题让我认识到了双指针的重要性。

其次,第二道题的滑动窗口的解决办法其实也是双指针进行操作,由此可见,双指针在解决数组问题中非常重要。滑动窗口的核心是先移动右指针,当达到某一条件后,再移动左指针从而得到最小值。

最后一道题在我看来是今天最复杂的一道题,需要非常细心,要明确好矩阵在螺旋排序时,每一条边的边界,明确好起始和终止位置。明天需要再巩固一遍!

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组平方",和Leetcode 209 "长度最小数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小数组

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值