Leetcode 977: 有序数组的平方
讲解前:
这道题我一拿到以后就有了思路,不过一开始我的方向有些问题,首先题目让我们可以返回一个新的数组就代表我们可以开一个新的空间O(n) 不用担心在原地修改原数组的问题,所以我想那很简单,找两个指针一个指向res数组一个指向原数组然后每次在原数组中遍历一个新的数字就和res数组中指针指向的current作比较然后按照是大是小来决定添加到哪里。我一写出来就发现了这种解法的问题,在res数组中一个指针根本没办法把接收到的新值安排在正确的位置
后来我重新想了想发现了一个非常重要的问题就是我的这种解法压根没有用到题目中所给的数组是有序的这个条件,然后我仔细想了想有序的问题发现如果我们安排两个指针分别指向原数组的头和尾,那么这两个指针left and right 永远包含了当前数组中每个数平方过后的最大值,因为left 指向最小的负数 right指向最大的正数,比如 [-4, -2, -1, 0, 2, 3, 7] 这里平方最大的就是49 which is pointed by right pointer,然后我们找到了之后就可以把right pointer向左移动指向下一个大的正数也就是3,然后这时还是一样最大的16 然后有left pointer keep track。这种方法哪怕数组中只有负数或者只有正数也可以work
接下里我们就可以通过两个指针进行比较然后移动来把平方过后每一个最大的数字一一添加到我们的res数组中去,最后返回时把数组reverse一下变成了题目要求的从小到大(或者添加的时候就从后往前添加)
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
res = []
left, right = 0, len(nums) - 1
while left <= right:
l = nums[left] ** 2
r = nums[right] ** 2
if l > r:
res.append(l)
left = left + 1
else:
res.append(r)
right = right - 1
return res[::-1]
讲解后:
看完了卡哥的视频讲解以后发现他的思路和我想的是一样的,唯一的区别就是在他的代码里也有一个变量来记录存放res的index,所以就可以从后往前加入数据最后return res
Leetcode 209: 长度最小子数组
讲解前:
一拿到这道题我就想到了滑动窗口的解法,但是之前做过的滑动窗口的题目中,窗口的大小都是固定的例如三元组之类的题但是这里最小的子数组,这个答案也可以是单独的一个数字,所以我一开始有些头疼
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
res = []
for i, num in enumerate(nums):
length = 1
while i + length <= len(nums):
if sum(nums[i: i + length]) < target:
length = length + 1
else:
res.append(length)
break
if not res:
return 0
return min(res)
这是我自己思考以后写出来的code,没有通过提交,因为超出时间限制了,但是通过了所给的testcase。这应该算是一种暴力解法,我遍历数组中的每一个数字,都假设他们是子数组的开头,然后去找他们最小可以新添加几个数字就达到大于等于target的目标,然后把这个length存起来放入一个res数组中,最后return res数组中最小的值就是答案,因为这种解法我需要在每一个循环中call sum() function,sum() 对一个list本身就是O(n) 的时间复杂度,所以这里我的解法使用了 O(n^2) 的时间复杂度
讲解后:
接下里的解法是我看了卡哥的视频讲解后自己写的
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
res = len(nums)
start = 0
has_res = False
s = 0
for end in range(len(nums)):
s = s + nums[end]
while start <= end and s >= target:
has_res = True
curr_length = end - start + 1
res = min(res, curr_length)
s = s - nums[start]
start = start + 1
if has_res:
return res
else:
return 0
这里我添加了一个edge case,其实在看视频的时候我就发现没有提到如果所有的元素加起来都没有达到target我们该如何处理,因为res一开始已经定义为了最大的可能(数组的长度),所以没办法直接返回,于是我写了一个flag,用来在最后return的时候判断,如果我们从来没有进过while loop也就没有成功达到s >= target的条件,那么就直接return 0
然后我去看了这道题的文章,发现了文章中卡哥代码和我的不同点
class Solution:
def minSubArrayLen(self, s: int, nums: List[int]) -> int:
l = len(nums)
left = 0
right = 0
min_len = float('inf')
cur_sum = 0 #当前的累加值
while right < l:
cur_sum += nums[right]
while cur_sum >= s: # 当前累加值大于目标值
min_len = min(min_len, right - left + 1)
cur_sum -= nums[left]
left += 1
right += 1
return min_len if min_len != float('inf') else 0
第一点就是卡哥用了两个while loop,而我是用了for loop来循环我们唯一需要每个都遍历的right/end pointer,其次就是卡哥这里一开始instead of assigning res with length of nums, 卡哥直接让他等于正无穷大然后再最后return的时候也是一样查看了一下res的值在之前的代码中是否得到了update来确定有没有正确的值还是返回 0
Leetcode 59: 螺旋矩阵II
讲解前:
我对这道题一点头绪都没有,我目前自己也还没有刷过有关于二维数组的题
我这里列举出来了如果按顺序往矩阵里添加数据的过程,规律也能总结出来根据螺旋的规则,其实就是如果我们把每一个矩阵中的位置作为[i, j],就先保持i不变然后增加j,在保持j不变增加i,当i,j都等于n - 1以后再变成i不变减少j以此类推,但是我觉得这样不是理想的解法
讲解后:
看了卡哥的视频之后发现确实这道题没什么算法,就应该认真的把边界选好以后马一圈一圈把数字填好就行了,有点后悔没有自己尝试一开始去做,这里是卡哥的代码
class Solution:
def generateMatrix(self, n: int) -> 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) : # 每循环一层偏移量加1,偏移量从1开始
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