1. 双指针(leetcode 977 有序数组的平方)
双指针算法是一种在遍历对象时,使用两个或多个指针进行遍历及相应的操作的算法技巧。这种算法利用了数组的连序性特点,常用于降低算法的时间复杂度,因为它可以避免多层循环,从而简化一些运算。双指针算法的核心思想在于使用两个指针进行遍历,这些指针可以是相同方向(快慢指针)或相反方向(对撞指针)的指针,以达到特定的目的。
双指针算法的常见应用包括:
- 在一个序列中,用两个指针维护一段区间。
- 在两个序列中,一个指针指向其中一个序列,另一个指针指向另一个序列,以维护某种次序。
双指针算法的三种关键点包括:
- 指针的起始位置的选取。
- 指针的移动方向。
- 指针的移动速度。
双指针算法的模型包括对撞指针、快慢指针、滑动窗口和归并排序等,这些模型展示了双指针算法在不同场景下的应用。
因为这题数组中的元素有正有负,所以平方后最大的元素只可能出现在头尾两侧,因此这题可以运用相反方向的双指针法,两个指针分别指向头尾,移动速度为一次一个元素,朝中间方向移动,对比两个指针平方后的大小然后进行排序。
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
first = 0
second = len(nums) - 1
new = [0] * len(nums)
count = 0
while first <= second:
if nums[second] ** 2 > nums[first] ** 2:
count -= 1
new[count] = nums[second] ** 2
second -= 1
else:
count -= 1
new[count] = nums[first] ** 2
first += 1
return new
2. 滑动窗口(leetcode 209 长度最小的子数组)
所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
滑动窗口大致分为两类:一类是窗口长度固定的,即left和right可以一起移动;另一种是窗口的长度变化(例如前五道题),即right疯狂移动,left没怎么动,这类题需要观察单调性(即指针)等各方面因素综合思考
在本题中实现滑动窗口,主要确定如下三点:
- 窗口内是什么?
- 如何移动窗口的起始位置?
- 如何移动窗口的结束位置?
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
first = 0
second = 0 #定义两个指针位置
answer = float('inf') #使用inf来初始化窗口长度
cumsum = 0 #使用cumsum来记录总和,避免使用sum浪费时间
while second < len(nums): #loop完成条件为第二个指针遍历完所有元素
cumsum += nums[second]
while cumsum >= target and (second - first >= 0):
answer = min(answer, second - first + 1)
cumsum -= nums[first]
first += 1
second += 1
return answer if answer != float('inf') else 0
#这道的重点在于右侧满足条件时,要对左侧窗口进行微调,所以需要两个while loop
#因为每个元素只被前后两个指针遍历两次,所以是O(n)
这道的重点在于右侧满足条件时,要对左侧窗口进行微调,所以需要两个while loop
虽然有两个while loop,但因为每个元素只被前后两个指针遍历两次,所以是O(n)
3. 转圈(leetcode 59:螺旋矩阵 2)
这道题目可以说在面试中出现频率较高的题目,本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。
在求解本题时一定要注意loop中的loop invariant,要处理好边界条件,才不会出错一直debug。
每个颜色为每次遍历的部分,一定要注意每个拐角边际条件的处理。
loop在这边坚持左闭右开原则。
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
count = 1
for offset in range(1, loop+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:
nums[mid][mid] = count
return nums
参考资料: