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循环的条件更容易想到,把行列范围,通过边界来控制,而不是偏移量,感觉更好理解