977.有序数组的平方
1. 文章链接
2. 看到题目第第一想法
要非递减顺序的排序数字,这种情况可以双指针。
left_pt指向左端元素,平方为left_sq,right_pt指向右端元素的平方right_sq。
比较left_sq和right_sq,
如果left_sq较小,则将新元素加入结果数组,更新left_pt向右移动。
直到两个指针碰到,将最后一个元素加入队尾即可。
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
left_pt = 0
right_pt = len(nums) - 1
sq_res_list = []
while left_pt < right_pt:
left_sq = nums[left_pt] * nums[left_pt]
right_sq = nums[right_pt] * nums[right_pt]
if left_sq <= right_sq:
sq_res_list = [right_sq] + sq_res_list
right_pt -= 1
else:
sq_res_list = [left_sq] + sq_res_list
left_pt += 1
sq_res_list = [(nums[left_pt] * nums[left_pt])] + sq_res_list
return sq_res_list
3. 实现过程中遇到的困难
因为nums是非递减序列,所以左右两端开始时,平方值一定哪个都不是最小值。
要拿到最小值只能是最后两个指针重叠的那个值,一定不是哪个较小先放哪个,这样求不出一个非递减序列的。
所以我姑且每次新进来一个值都插到数组的开头,但是Python是否有从头插入的方法?我不清楚,所以直接用列表拼接的。
4. 看完代码随想录之后的想法
l, r, i = 0, len(nums)-1, len(nums)-1
res = [float('inf')] * len(nums) # 需要提前定义列表,存放结果
这样创建列表不会遇到for循环费时间的问题。
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
left_pt = 0
right_pt = len(nums) - 1
sq_res_list = [float("inf")] * len(nums)
res_idx = len(nums) - 1
while left_pt < right_pt:
left_sq = nums[left_pt] * nums[left_pt]
right_sq = nums[right_pt] * nums[right_pt]
if left_sq <= right_sq:
sq_res_list[res_idx] = right_sq
right_pt -= 1
res_idx -= 1
else:
sq_res_list[res_idx] = left_sq
left_pt += 1
res_idx -= 1
sq_res_list[res_idx] = (nums[left_pt] * nums[left_pt])
return sq_res_list
5. 学习时长
构思:15分钟
实现:10分钟
209.长队最小的子数组
1. 文章链接
2. 看到题目第第一想法
连续字数组应该使用滑动窗口。
因为要返回最小长度数组的长度,我觉得还需要一个最小长度的统计量min_len_int。
从滑动窗口长度为 开始,
- 如果滑动窗口内的数字比target小,那就应该右侧边界增长一个单元。
- 如果滑动窗口内的数字,更新
min_len_int, 那就应该左侧边界收缩一个单元。
直到右侧边界不能继续增长,或者左侧边界继续收缩将会超出数组右端。
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
win_left_bound = 0
win_right_bound = 1 # 滑窗是左闭右开
sum_int = nums[win_left_bound]
min_len_int = len(nums) + 1
while win_right_bound <= len(nums):
# print(win_left_bound, win_right_bound, sum_int)
if (sum_int < target) and (win_right_bound < len(nums)):
sum_int += nums[win_right_bound]
win_right_bound += 1
elif (sum_int >= target) and (win_left_bound < win_right_bound):
tmp_len_int = win_right_bound - win_left_bound
if tmp_len_int < min_len_int:
min_len_int = tmp_len_int
sum_int -= nums[win_left_bound]
win_left_bound += 1
else:
break
if min_len_int == len(nums) + 1:
return 0
return min_len_int
3. 实现过程中遇到的困难
我觉得最困难的就是想到判断条件,既能保证找到我们想要的最小长度,又能让指针不超范围。 一开始想的是控制循环的条件,但是后来发现应该是控制增长和收缩的判断条件,而且如果不满足增长条件,也不满足收缩条件,应该立刻终止了,因为已经不能再移动滑窗了。
4. 看完代码随想录之后的想法
- 窗口右侧边界不需要判断,就是数组的遍历指针,
- 窗口左侧会根据sum的值超过target而向前,从而搜索滑窗。
- 更新最小长度直接可以用
min不需要用一个if. - 不是看到双层循环就是, 每个元素就做一次入队一次出队,实际上是。
5. 学习时长
构思:20分钟
实现:30分钟 (主要浪费在滑窗边界没有坚守住不变量)
看文档:15分钟
59.螺旋矩阵 II
1. 文章链接
2. 看到题目第第一想法
一定要规定好上下左右四个边界,这个很容易出错。
- 从左向右走完一行,那说明从上到下的起点需要+1.
- 从上到下走完一列,那说明从右向左的起点需要-1.
- 从右向左走完一行,那说明从下到上的起点需要-1.
- 从下到上走完一列,那说明从左到右的起点需要+1.
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
res_list = [[0] * n for _ in range(n)]
count = 1
left = 0
right = n
up = 0
down = n
while (n * n) >= count:
# 从左到右
col_idx = left
row_idx = up
while col_idx < right:
print(row_idx, col_idx, count)
res_list[row_idx][col_idx] = count
count += 1
col_idx += 1
up += 1
# 从上到下
row_idx = up
col_idx = right - 1
while row_idx < down:
print(row_idx, col_idx, count)
res_list[row_idx][col_idx] = count
count += 1
row_idx += 1
right -= 1
## 从右到左
col_idx = right - 1
row_idx = down - 1
while col_idx >= left:
print(row_idx, col_idx, count)
res_list[row_idx][col_idx] = count
count += 1
col_idx -= 1
down -= 1
# 从下到上
row_idx = down - 1
col_idx = left
while row_idx >= up:
print(row_idx, col_idx, count)
res_list[row_idx][col_idx] = count
count += 1
row_idx -= 1
left += 1
return res_list
3. 实现过程中遇到的困难
一个是每一行起始位置都要重新赋值,这一点一开始没注意到,只有打印输出后才发现位置有问题。 另一个是二维数组的初始化不对:
我用的是res_list = [[0] * n] * n
而文档中用的是res_list = [[0] * n for _ in range(n)]
这一点ChatGPT如是说:
在Python中,[[0] * n] * n和[[0] * n for _ in range(n)]都可以用来创建一个n * n的二维数组,但是它们的内部结构是不同的。
[[0] * n] * n会创建一个包含n个指向相同列表对象的引用的列表。这意味着当您修改其中一个列表时,所有n个列表都会发生改变。例如:
>>> res_list = [[0] * 3] * 3
>>> res_list[0][0] = 1
>>> print(res_list)
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]
在这个例子中,修改res_list[0][0]会导致所有子列表的第一个元素都被修改,因为它们都指向同一个列表对象。这通常不是我们希望看到的行为。
另一方面,[[0] * n for _ in range(n)]会创建一个包含n个不同列表对象的列表。这意味着当您修改其中一个列表时,其他列表不会受到影响。例如:
>>> res_list = [[0] * 3 for _ in range(3)]
>>> res_list[0][0] = 1
>>> print(res_list)
[[1, 0, 0], [0, 0, 0], [0, 0, 0]]
在这个例子中,修改res_list[0][0]只会影响到第一个子列表,其他子列表不会受到影响。
因此,为了避免上述问题,建议使用[[0] * n for _ in range(n)]来创建n * n的二维数组。
4. 看完代码随想录之后的想法
他用了for循环,我用的while。
他用offset和n-offset来表示边界。
另外我觉得,我的根据count是否达到来判断是否跳出循环更简单。
5. 学习时长
1小时。