【Day2】代码随想录算法训练营 - 数组(二)

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

题目描述

个人觉得题目描述有些问题“非递减顺序”不太严谨,[4, 5, 4, 7, 9, 2]也是非递减序列。猜测题目想表达“递增序列”。
在这里插入图片描述

解题思路

简单想法:双指针从左右端分别算平方数,哪个大则添加入新列表,依次遍历即可,最后返回逆序新列表。
时间复杂度:O(n)
空间复杂度:O(n)

代码

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        square_list = []
        left, right = 0, len(nums) - 1
        while left <= right:
            if nums[left] * nums[left] < nums[right] * nums[right]:
                square_list.append(nums[right] * nums[right])
                right -= 1
            else:
                square_list.append(nums[left] * nums[left])
                left += 1
        return square_list[::-1]

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

1. 题目描述

在这里插入图片描述

2. 解题思路

暴力破解法(Can’t AC,超时),原因在于对于数组过长(目测元素数量10000+),并且很多种连续元素求和能满足目标条件
这里重点归纳双指针“滑动窗口”方法。
方法:

left, right = 0
min_len = len(nums)
total_sum = 0 # 左指针和右指针之间元素求和
for right in range(0, len(nums)):
    total_sum += nums[right]
    while total_sum >= target:
        left

左指针和右指针之间元素求和记为sum(以下描述sum会根据左右指针变动自动更新值),右指针控制结束位置,左指针控制开始位置,左右指针初始化均为0.

  • sum小于目标值时,一直动右指针
  • sum大于等于目标值时,左指针右移并记录最短长度
  • 右指针右移直至数组最后一个位置

优点:

  • 最直观优点为减少了暴力解法中重复的求和操作
  • 虽然也是两层循环(for+while),其中外层for控制右指针,内层while循环控制左指针,但是每次执行循环(不论是内循环还是外循环)左右指针必有一个指针在动,这样最多左右指针同时移动到末尾(即[1, 1, 1, 1, 100], 101这种输入情况), 因此时间复杂度为O(2*n)
  • 右指针的作用即增加新元素,左指针的作用为及时剔除掉没有用的元素

3. 代码

3.1 暴力解法

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        min_len = len(nums) + 1
        for i in range(len(nums)):
            total_sum = 0
            this_len = 0
            for j in range(i, len(nums)):
                total_sum += nums[j]
                this_len += 1
                if total_sum >= target and this_len < min_len:
                    min_len = this_len
                    break
            if total_sum < target:
                if min_len == len(nums) + 1:
                    return 0
                else:
                    return min_len
        if min_len == len(nums) + 1:
            return 0
        else:
            return min_len          

3.2 左右指针滑动窗口法

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        min_len = len(nums)
        this_len = 0
        left, right = 0, 0
        total_sum = 0
        for right in range(len(nums)):
            total_sum += nums[right]
            this_len += 1
            while total_sum >= target:
                total_sum -= nums[left]
                left += 1
                this_len -= 1
                min_len = min(this_len, min_len)
        # 不符合条件时min_len == len(nums)恒成立
        if min_len == len(nums):
            return 0
        # 符合条件时min_len < len(nums)恒成立
        else:
            return min_len + 1

题目三:59. 螺旋矩阵II

题目描述

在这里插入图片描述

解题思路

开始想的太复杂了,其实很多if/else条件根本用不到(例如往右走到头根本不用考虑往上走的情况即不用考虑row_direction=-1的情况,此时row_direction=1恒成立,类似不存在情况还有很多),实际上row_directioncolumn_direction只需其中一个即可。

本题解法的关键在于弄明白if/else的判断条件:

  • 前提条件:往上下左右走的条件均为下一个位置不为空且下一个位置不到边界
  • 由顺时针决定了以下两点
    • 如果之前往右走,则走到头一定往下走
    • 如果之前往左走,走到头一定往上走
  • 往上或者下走到头则左右方向颠倒

代码

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        init_num = 0
        row = 0
        column = 0
        this_num = 1
        column_direction = 1
        result = [[init_num] * n for i in range(n)]
        while this_num != n * n:
            result[row][column] = this_num 
            this_num += 1
            if column_direction == 1:
                if column != n - 1 and result[row][column + 1] == init_num:
                    column += 1
                else:
                    if row != n - 1 and result[row + 1][column] == init_num:
                        row += 1
                    else:
                        column_direction = -1
                        column -= 1
            else:
                if column != 0 and result[row][column - 1] == init_num:
                    column -= 1
                else:
                    if row != 0 and result[row - 1][column] == init_num:
                        row -= 1
                    else:
                        column_direction = 1
                        column += 1
        result[row][column] = n * n
        return result
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值