文章目录
977. 有序数组的平方
题目的特点在于“有序”,所以双指针可以成为一个合格的解法。题目不难,但是要迅速意识到可以用双指针。
时间复杂度:
O
(
n
)
O(n)
O(n)
Naive的双指针(自己的解法)
- 找到正负号变换的 index(这一步其实可以省略)
- 从变换的 index 向两边同时查找,一次遍历,依次取得最小平方
问题在于写的丑陋,同时还需要最后的收尾(可以优化 while 的 termination condition?)
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
results = []
negative_count = 0
for i in range(len(nums)):
if nums[i] < 0:
negative_count += 1
if negative_count == 0:
for i in range(len(nums)):
results.append(nums[i] ** 2)
return results
else:
negative_idx = negative_count - 1
positive_idx = negative_count
while (negative_idx >= 0 and positive_idx <= len(nums)-1):
if nums[positive_idx] < -nums[negative_idx]:
results.append(nums[positive_idx] ** 2)
positive_idx += 1
else:
results.append(nums[negative_idx] ** 2)
negative_idx -= 1
for i in range(negative_idx, -1, -1):
results.append(nums[i] ** 2)
for i in range(positive_idx, len(nums)):
results.append(nums[i] ** 2)
return results
双向指针
左右各一个指针进行遍历,直接比较获得数组。
注意由于出现在两端的都是(平方)最大值,所以输出的数组应该从后往前更新。
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
left_idx = 0
right_idx = len(nums) - 1
results = [0] * len(nums)
i = len(nums) - 1
while (left_idx <= right_idx):
if nums[left_idx]**2 > nums[right_idx]**2:
results[i] = nums[left_idx]**2
left_idx += 1
else:
results[i] = nums[right_idx]**2
right_idx -= 1
i -= 1
return results
创建长度为 n 的数组:
a = [0] * n
209. 长度最小的子数组
处理滑动区间的基础方法,解题时需明确
- 区间:某一段连续子数组(subarray),由
left_idx
和right_idx
标记起始 - 何时改变区间首尾 index
- 区间和 >= target:将区间起始向右移,尝试获得更小的区间是否同样能满足条件
- 区间和 < target:将区间终点向右移,加入更多元素以满足条件
注意到暴力解法实质是对每一个区间起点left_idx
都穷举right_idx
,所以是
O
(
n
2
)
O(n^2)
O(n2)的复杂度。
滑动区间(特殊版本的双指针)利用了left_idx
只会右移的特点,只遍历right_idx
,得到了
O
(
n
)
O(n)
O(n)的复杂度。
自己的解法(本质相同)
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
best_length = len(nums) + 1
curr_sum = 0
left_idx = 0
right_idx = -1
while (right_idx < len(nums)):
if curr_sum >= target:
# update the window size if necessary
best_length = min(right_idx - left_idx + 1, best_length)
# to see whether a smaller window can also work
curr_sum -= nums[left_idx]
left_idx += 1
else: # need more elements to meet target
right_idx += 1
if right_idx < len(nums):
curr_sum += nums[right_idx]
if best_length == len(nums) + 1:
return 0
return best_length
标准思路
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
best_length = len(nums) + 1
curr_sum = 0
left_idx = 0
for right_idx in range(len(nums)):
curr_sum += nums[right_idx]
while (curr_sum >= target): # notice that use "while" to go over all the subarrays with current right_idx
best_length = min(best_length, right_idx - left_idx + 1)
curr_sum -= nums[left_idx]
left_idx += 1
if best_length == len(nums) + 1:
return 0
return best_length
904. 水果成篮
74. 最小覆盖子串
59. 螺旋矩阵II
这道题没有复杂的算法思路,本质是能分清楚循环中每个 case 的边界条件,考验思路是否清晰 + 能否实现。
Recursion
暴力解法,直接通过 recursion 得到 n − 2 n-2 n−2 的矩阵,然后手动加上最外面的一圈
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
if n == 1:
return [[1]]
if n == 2:
return [[1, 2],
[4, 3]]
temp_results = self.generateMatrix(n - 2)
results = []
first_line = []
for i in range(n):
first_line.append(i+1)
last_line = []
for i in range(3*n-2, 2*n-2, -1):
last_line.append(i)
results.append(first_line)
for i in range(1, n-1):
temp = [4*(n-1) - i + 1]
for j in range(1, n-1):
temp.append(temp_results[i-1][j-1] + 4*(n-1))
temp.append(n+i)
results.append(temp)
results.append(last_line)
return results
Naive 解法
主要的难点在于每个变量对应的含义以及边界条件:
loop_offset
:记录当前在整个矩阵第几圈(自外而内)curr_row
,curr_col
:记录当前元素的行和列,注意要在每个 outer while iteration 开始时设置为对应的loop_offset
counter
:记录当前填入的值是多少
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
results = [[0] * n for i in range(n)]
loop_offset = 0 # denote which loop around the square we are at
curr_row = curr_col = 0
counter = 1 # record which value to fill in
while (loop_offset < n//2):
curr_row = curr_col = loop_offset
# first fraction: upper
for j in range(loop_offset, n - loop_offset - 1): # not include the last element in this row
results[curr_row][j] = counter
counter += 1
curr_col += 1
print(curr_row)
# curr_col = n - loop_offset - 1
# second fraction: right
for i in range(loop_offset, n - loop_offset - 1):
results[i][curr_col] = counter
counter += 1
curr_row += 1
# curr_row = n - loop_offset - 1
# third fraction: below
for j in range(n - loop_offset - 1, loop_offset, -1):
results[curr_row][j] = counter
counter += 1
curr_col -= 1
# curr_col = 0
# last fraction: left
for i in range(n - loop_offset - 1, loop_offset, -1):
results[i][curr_col] = counter
counter += 1
curr_row -= 1
# curr_row = 0
loop_offset += 1
if n % 2:
results[loop_offset][loop_offset] = n**2
return results
创建一个2d数组:
results = [[0] * n for i in range(n)]
不要使用results = [[0] * n] * n
,会有 copy 的问题