双指针很多是数学问题的推导:
19.删除链表的倒数第N个节点
- 破题点:删除倒数第N个节点,那么找到该节点,向后走N步为None;
- 从头节点走N步,距离头节点的步长是N。
- 从该节点到末尾None节点,距离为N。
- 从头节点前一个节点走N步,走到了该节点前一个节点。
- 添加dummyhead虚拟节点:防止删除第一个节点,及删除的是head需要特殊处理;dummyhead.next = head
- 使用前后指针距离N的移动,而不是前后指针同步移动:可以找到该节点的位置,也防止删除的是最后一个节点,pre.next.next为空;
链表相交:
- 破题点:注意审题,相交部分位于链表的中尾部;
- 数学公式,a+c+b = b+c+a;循环遍历总会同时相遇,或者同时到达总终点;
- 两个指针分别遍历,遍历完A遍历B一定会在公共点相遇(或者终点None)
142.环形链表II
所以此时head和slow一起走,相遇的点正好是a步,也是环的入口.
- 数学题,这类题目一般是双指针法,两指针再次"相遇"。寻找距离尾部第
K
个节点、寻找环入口、寻找公共尾部入口等 -
f=2s (快指针每次2步,路程刚好2倍)
f = s + nb (相遇时,刚好多走了n圈)
推出:s = nb
设k为相遇点,k = a+nb, 联立s = nb,得 k = a + s(s为第一次相遇的slow节点所走的路)
根据2: - 此时从slow出发走a步就是入环点
- 此时从head出发走a步就是入环点
第15题. 三数之和
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
res = []
for i in range(len(nums)-2):
if nums[i] > 0:
return res
##第一个元素有重复的不需要重复遍历 【a,b,c】【a,b,c】
if i > 0 and nums[i] == nums[i-1]:
continue
left = i+1
#要把right写进for循环里面,因为每次从头for循环可以更新right,不然right接着上 一次的值已经固定。
right = len(nums)-1
while left < right:
if nums[left] + nums[right] > -nums[i]:
right -= 1
elif nums[left] + nums[right] < -nums[i]:
left += 1
else:
res.append([nums[i],nums[left],nums[right]])
#第二个第三个元素有重复的 【-4,2,2】【-4,2,2】
while left < right and nums[right] == nums[right-1]:
right -= 1
while left < right and nums[left] == nums[left+1]:
left += 1
right -= 1
left += 1
return res