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

算法详解

977.有序数组的平方

(一)遍历解法(暴力解法)

算法复杂度:遍历O(n) + 排序O(nlogn)

思路

(1)遍历每一个数组中的元素并执行平方操作;
(2)排序nums.sort()

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        length = len(nums)
        
        for i in range(length):    # 时间复杂度为O(n)
            nums[i] = nums[i] ** 2
        nums.sort()                # 时间复杂度为O(nlogn)
        return nums

(二)双指针解法

算法复杂度:O(n);
说明:while left <= right 将循环n次。

易错点
  • 有序数组中可能含有负数。当负数出现时,其平方值可能远大于正数平方值。
  • 仅包含正数的有序数组无需排列,因此即使采用遍历法算法复杂度为O(n)。
思路
  • 当数组中存在负数时,数组的平方最大值出现在数组的“两端”。因此从两端同时遍历可以有效找到数组中平方的最大值。
代码
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        left, right, new_right = 0, len(nums) - 1, len(nums) - 1
        new_nums = [0] * len(nums)  # 生成一个和nums大小相同的数组

        while left <= right:
            if nums[left] ** 2 > nums[right] ** 2: 
                # 始终将比较之后的最大值添加到新数组中
                new_nums[new_right] = nums[left] ** 2
                # nums[left] ** 2 已经添加到新数组中故left右移
                left += 1    
            else:
                new_nums[new_right] = nums[right] ** 2
                right -= 1
            # 每对新数组赋值完一次之后移动一次新数组的下标
            new_right -= 1
         
        return new_nums

209. 长度最小的子数组

滑动窗口(小加右,大减左)

算法复杂度:O(n);
说明:while 将循环n次。

易错点
  • 小加右:当前数字之和小于目标值时,增量为右指针的值。
  • 大减左:当前数字之和大于(或等于)目标值时,减量为左指针的值。
  • 注意:当数字之和满足目标值且循环没有结束时,依然需要往下继续寻找下一个满足需要的数组。
  • 最小长度比较:当满足大于等于目标值时,可以通过right-left+1计算当前数组的长度,并与最小数组长度比较,保留最小长度。
  • 注意:当大于目标值时虽然乍一看不满足条件,但大于目标值时数组长度一定也大于长度最小的数组,遂简化代码。
思路
  • 初始化两个指针,按照“小加右,大减左”原则滑动窗口,满足条件的数组计算长度与最小长度(初始化为无穷大)比较。
代码
class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        length = len(nums)
        left, right = 0, 0
        min_len = float('inf')
        sum = 0

        while right < length:
            sum += nums[right] # 累加时新增的是右指针值
            
            while sum >= target:
                min_len = min(min_len, right-left+1) # 当大于目标值时长度一定大于最小长度
                sum -= nums[left]  # 超过/等于目标值时减掉左指针值
                left += 1 # 执行完右移
            
            right += 1 # (无论大于小于等于)执行完右移
        
        return min_len if min_len != float('inf') else 0

59. 螺旋矩阵2

双循环算法

算法复杂度:O(n^2);
说明:内外for循环各O(n)。

易错点
  • 循环不变量选取:如下图所示,每一圈螺旋的生成都按照类似的规律执行。其中螺旋数loop = n // 2
    在这里插入图片描述
  • 奇数螺旋矩阵中心点值另外赋值:当n为奇数时,会出现最内圈螺旋只有一个值的现象,为和n为偶数的算法统一,且简化代码,另外赋值nums[mid][mid],其中mid = n // 2
思路
  • 初始化两个指针,按照“小加右,大减左”原则滑动窗口,满足条件的数组计算长度与最小长度(初始化为无穷大)比较。
代码

(1)内循环:可以首先根据上图(i,j)变化规律推导出每一圈螺旋变化的规律,代码如下:

cnt = 1
        matrix = [[0]*n for _ in range(n)]
        # i = 1
        for j in range(n-1):
            matrix[i][j] = cnt
            cnt += 1
        # j = n - 1
        for i in range(n-1):
            matrix[i][j] = cnt
            cnt += 1
        # i = n - 1
        for j in range(n-1,2,-1):
            matrix[i][j] = cnt
            cnt += 1
        # j = 1
        for i in range(n-1,2,-1):
            matrix[i][j] = cnt
            cnt += 1

(2)外循环:offset是由循环不变量得到的变量值,即第一圈时,需要保留最后一个值最为下一圈的起始位置;第二圈时offset其实也为1,但是考虑到第一圈已经生成位置不需要再访问,因此offset为2,以此类推。注意:offset取值不能大于(小于等于)loop。总体代码如下:

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        cnt = 1
        start_x = 0
        start_y = 0
        offset = 1
        loop, mid = n // 2, n // 2
        matrix = [[0]*n for _ in range(n)]

        for offset in range(1, loop + 1):
            for j in range(start_y, n-offset):
                matrix[start_x][j] = cnt
                cnt += 1
            
            for i in range(start_x, n-offset):
                matrix[i][n-offset] = cnt
                cnt += 1
            
            for j in range(n-offset, start_y, -1):
                matrix[n-offset][j] = cnt
                cnt += 1
            
            for i in range(n-offset, start_x, -1):
                matrix[i][start_y] = cnt
                cnt += 1 

            start_x += 1
            start_y += 1
         
        #  n为奇数时还需要填充一个芯
        if n % 2 != 0:
            matrix[mid][mid] = cnt
                      
        return matrix

总结

解决数组算法题记住“双指针”法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值