【代码随想录】d2-数组part02-python

1.LeeCode 977. 有序数组的平方

1.1题目及讲解

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

题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/
文章讲解:https://programmercarl.com/0977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.html
视频讲解: https://www.bilibili.com/video/BV1QB4y1D7ep

1.2代码实现

思路:

  • 看题目以后想到的就是遍历数组,然后每个平方之后再排序
  • 已经知道可以用双指针,且知道平方后数据趋势,两边大,中间小,但是想不到双指针方法具体怎么写

方法一:遍历计算,存放在新数组中,然后进行排序

nums = [-4,-1,0,3,10]
new_nums = []
for i in range(len(nums)):
    new_nums.append(nums[i] * nums[i])
new_nums.sort()
print(new_nums)

方法二:暴力法+列表推导式

nums = [-4,-1,0,3,10]
print(sorted(i*i for i in nums))

方法三:双指针

def fun(nums):
    k = len(nums)-1  # 原数组最后一位元素下标,用来做新数组下标
    result = [0] * len(nums)
    i,  j = 0, k  # 首位指针
    while i <= j:  # i=j时,是能取到元素的,有意义的
        if nums[i] * nums[i] >= nums[j] * nums[j]:  # 判断i和j所指向的元素,哪个平方更大,相等时取哪边都一样,所以=不用特殊考虑
            result[k] = nums[i] * nums[i]  # 上面找出来的是最大的元素,存放在新数组时,需要从索引最大位置往前放 ,k就是最后一个元素的下标
            k -= 1  # 获取到最后一位元素就减一,继续存前一位元素
            i += 1  # i指向的元素更大,取了这一位元素后,i需要向后一位,去对比下一个元素
        else:
            result[k] = nums[j] * nums[j]
            k -= 1
            j -= 1  # j指向的元素更大,取了这一位元素后,j需要向前一位,去对比下一个元素
    return result

nums = [-4,-1,0,3,10]
print(fun(nums))

1.3总结

  • 看完视频以后才知道双指针的写法
  • 创建数组时,如果数组后续要用到数组的索引,不能只创建一个空数据,而是要*长度 ,这样后续用新数组的索引时才不会报错

2.LeeCode 977. 有序数组的平方

2.1题目及讲解

给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

题目链接:https://leetcode.cn/problems/minimum-size-subarray-sum/
文章讲解:https://programmercarl.com/0209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.html
视频讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE

2.2代码实现

思路:

  • 一开始想到的是初始化左右指针,循环左指针遍历所有元素,右指针在左指针每遍历一个元素后去循环选其他的元素,然后代码超时了…
  • 看了视频讲解,发现这种方式和两层for循环的暴力法没有区别,但是又没想到右指针作为循环条件的情况
    方法一:暴力破解(超时)
def fun(nums, target):
    if max(nums) >= target:
        return 1
    if sum(nums) < target:
        return 0
    l, r = 0, 1
    res = len(nums)
    while l <= len(nums) - 2 and r <= len(nums) - 1:
        if sum(nums[l:r+1]) >= target:
            res = min(res, r - l)
            l += 1
            r = l + 1
        else:
            r += 1
    return res

target = 11
nums = [1,2,3,4,5]
print(fun(nums, target))

方法二:滑动窗口

def fun(nums,target):
    l = r = 0
    s = 0
    res = float('inf')  # 要找到最小的连续数组,先初始化一个最大的
    while r < len(nums):
        s += nums[r]  # 右指针每移动一位,和加一次
        while s >= target:  # 和一旦>=target,也就是找到了一个数组>=target,此时移动左指针,找到所有以当前右指针所在位置能够大于target的数组
            res = min(res,r-l+1)  # 获取更短的那个数组
            s -= nums[l]  # 左指针右移了,和要减掉之前的一位
            l += 1  # 左指针右移
        r += 1  # 右指针一定是往后移的,已经用while s >= target这个循环过滤了所有不向后移的情况
    return res if res !=float('inf') else 0


target = 11
nums = [1,1,1,1,1,1,1,1]
print(fun(nums, target))

分析:

  • 1.在数组nums 中使用双指针中的左右指针技巧,初始化 left = right = 0,把索引区间 [left, right] 称为一个「窗口」。
  • 2.left不动,不断地增加 right 指针扩大窗口,直到窗口符合要求(窗口内数值之和>=target)。
  • 3.此时,停止增加 right,转而不断增加 left 指针缩小窗口 ,直到窗口不再符合要求。
  • 4.重复第 2 和第 3 步,直到 right 到达数组末尾。
  • 5.注意最后的返回值,如果找不到这样的数组则返回0

第 2 步相当于在寻找一个「可行解」,然后第 3 步在优 化这个「可行解」,最终找到最优解,也就是最短的覆盖子串。左右指针轮流前进,窗口大小增增减减,窗口不断向右滑动,这就是「滑动窗口」。

3.LeeCode 59.螺旋矩阵II

3.1题目及讲解

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

题目链接:https://leetcode.cn/problems/spiral-matrix-ii/
文章讲解https://programmercarl.com/0059.%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5II.html
视频讲解:https://www.bilibili.com/video/BV1SL4y1N7mV/

3.2代码实现

没有思路,不知道怎么下手

def fun(matrix,n):
    start_x = 0
    start_y = 0
    count =1
    mid =loop = n//2
    for offset in range(1, loop + 1): # 根据偏移量确定循环范围
        for j in range(start_y, n - offset):
            matrix[start_x][j] = count
            count += 1
        for i in range(start_x, n - offset):
            matrix[i][n - offset] = count
            count += 1
        for j in range(n - offset,start_y,-1):
            matrix[n - offset][j] = count
            count += 1
        for i in range(n - offset,start_x,-1):
            matrix[i][start_y] = count
            count += 1
        start_x += 1 # 外圈循环完毕,加+到内圈来循环
        start_y += 1
    if n%2 !=0: # 处理n为计数的情况,中心没有循环,只有一个元素,只需要赋值即可
        matrix[mid][mid] =n **2

    return matrix

n = 4
matrix = [[0 for _ in range(n)] for _ in range(n)]
print(fun(matrix,n))

分析:

  • 保持循环不变量原则,每条边的处理都保持一样,使用左闭右开区间,最顶点的边界交由下一条边来处理
  • 通过控制offset来控制整体循环次数,即螺旋几次
  • 开始循环以后,通过控制行及列的范围来给行列固定的某一个位置赋值
  • left to right时,行不变,循环列,列往后,递增
  • top to bottom时,列不变,循环行,行往下,递增
  • right to left时,行不变,循环列,列往前,递减
  • bottom to top时,列不变,循环行,行往上,递减

记录一下看到的更能理解的解答
解题思路:
初始化一个 n×n 大小的矩阵 mat,然后模拟整个向内环绕的填入过程:

  • 1.定义当前左右上下边界 l,r,t,b,初始值 num = 1,迭代终止值 tar = n * n;
  • 2.当 num <= tar 时,始终按照 从左到右 从上到下 从右到左 从下到上 填入顺序循环,每次填入后:
    • 执行 num += 1:得到下一个需要填入的数字;
    • 更新边界:例如从左到右填完后,上边界 t += 1,相当于上边界向内缩 1。
  • 3.使用num <= tar而不是l < r || t < b作为迭代条件,是为了解决当n为奇数时,矩阵中心数字无法在迭代过程中被填充的问题。
  • 4.最终返回 mat 即可。
    作者:Krahets
    链接:https://leetcode.cn/problems/spiral-matrix-ii/solutions/12594/spiral-matrix-ii-mo-ni-fa-she-ding-bian-jie-qing-x/
    来源:力扣(LeetCode)
    在这里插入图片描述
class Solution:
    def generateMatrix(self, n: int) -> [[int]]:
        l, r, t, b = 0, n - 1, 0, n - 1
        mat = [[0 for _ in range(n)] for _ in range(n)]
        num, tar = 1, n * n
        while num <= tar:
            for i in range(l, r + 1): # left to right
                mat[t][i] = num
                num += 1
            t += 1
            for i in range(t, b + 1): # top to bottom
                mat[i][r] = num
                num += 1
            r -= 1
            for i in range(r, l - 1, -1): # right to left
                mat[b][i] = num
                num += 1
            b -= 1
            for i in range(b, t - 1, -1): # bottom to top
                mat[i][l] = num
                num += 1
            l += 1
        return mat

分析:
上面这种方式,while循环的条件更容易想到,把行列范围,通过边界来控制,而不是偏移量,感觉更好理解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值