24. 两两交换链表中的节点
【状态】:这道题一定要画个图,而且确定循环里面,cur到底传给谁很重要。然后循环条件,cur.next和cur.next.next都要不为空。最后自己磕磕绊绊,看了思路也写出来了,还需要多练习!!【如果想要改动当前节点,把指针就放在上一个节点,调用next】
题目:
思路: 涉及到局部动头结点,需要立马想到dummy_head虚拟头结点。
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
dummy_head = ListNode(next=head)
current = dummy_head
# 必须有cur的下一个和下下个才能交换,否则说明已经交换结束了【要回判断终止情况!!!!】
while current.next and current.next.next: #一个next控制偶数情况,两个next控制奇数节点情况
#!!!!一定要先判断next为空,然后在判断next.next为空,否则如果next为空,next.next先判断,就会报错
temp = current.next # 防止节点修改,下面存一个临时节点指针
temp1 = current.next.next.next
current.next = current.next.next
current.next.next = temp
temp.next = temp1
current = current.next.next #【一下子移动两位】
return dummy_head.next
19. 删除链表的倒数第N个节点
【状态】:
- 在写的时候,因为可能会删掉头结点,所以我里面考虑使用虚拟头结点
- 但是这一题,与构造链表不一样的是,没有self.size返回链表的有效节点数。看了题目思路,快慢指针,让快指针先走n步,快指针走到末尾,慢指针刚好就在倒数n个位置上。
- 删除某个节点,跑到这个要删节点的前面,操作!
题目:
思路:双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。
- fast指针和slow指针:开始都指向虚拟头结点
- fast先走,然后两个指针一起走,直至fast指针指向末尾
- 删除slow指针指向的下一个节点
时间复杂度 O(n) ,空间复杂度O(1)
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
# 创建一个虚拟节点,并将其下一个指针设置为链表的头部
dummy_head = ListNode(0, head)
# 创建两个指针,慢指针和快指针,并将它们初始化为虚拟节点
slow = fast = dummy_head
# 快指针比慢指针快 n+1 步
for i in range(n+1):
fast = fast.next
# 移动两个指针,直到快速指针到达链表的末尾
while fast:
slow = slow.next
fast = fast.next
# 通过更新第 (n-1) 个节点的 next 指针删除第 n 个节点
slow.next = slow.next.next
return dummy_head.next
面试题02.07 链表相交
【状态】:
- 刚开始没思路,看了思路以后,去写了代码;然后代码超时,估计哪里(调用函数self方法)写错了,很重要的是,是让两个链表的指针一样的时候返回,
不是值一样的时候返回 - 然后我又去看了一遍代码,尝试着自己写,又因为while循环的边界条件没理清楚,出现报错。
【题目】
【思路】
1.类似于那个倒数第n个节点的想法。(快指针先走n步,然后慢指针走)
链表A的长度-链表B的长度,然后让多出来的那部分先走,然后在一起走(这样确保末位对齐)。最后在headA和headB指针一样,返回指针就行。
注意:
1.while循环结束的临界点
2.类里面的方法调用 self.函数名
3.两个链表指针一样,才返回,不是数值
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
lenA = self.getLength(headA)
lenB = self.getLength(headB)
# 通过移动较长的链表,使两链表长度相等
if lenA > lenB:
headA = self.moveForward(headA, lenA - lenB)
else:
headB = self.moveForward(headB, lenB - lenA)
# 将两个头向前移动,直到它们相交
while headA and headB:
if headA == headB:
return headA
headA = headA.next
headB = headB.next
return None
def getLength(self, head: ListNode) -> int:
length = 0
while head:
length += 1
head = head.next
return length
def moveForward(self, head: ListNode, steps: int) -> ListNode:
while steps > 0:
head = head.next
steps -= 1
return head
2.等比例法:这个方法很巧妙
链表的长度,当两个链表都跑a+b+c这个长度,肯定会在交点/终点null相遇。
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
if not headA or not headB:# 处理边缘情况
return None
# 在每个链表的头部初始化两个指针
pointerA = headA
pointerB = headB
# 遍历两个链表直到指针相交
while pointerA != pointerB:
# 将指针向前移动一个节点
pointerA = pointerA.next if pointerA else headB
pointerB = pointerB.next if pointerB else headA
# 如果相交,指针将位于交点节点,如果没有交点,值为None
return pointerA
142. 环形链表
【状态】自己写没写出来,看了思路和代码,才把题目写出来。
【题目】
【思路】
1.快慢指针
(1)用快指针(两倍速)和慢指针(一倍数)跑,如果有环,找到相遇节点。(2)然后一个指针从相遇节点走,一个指针从头结点走,直至指针相同,返回。【如果三倍速跑,快指针相对于慢指针一次跳两步,有可能越过慢指针,可能永远错过!】
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
slow = head
fast = head
while fast and fast.next: #注意循环临界条件,要不然fast.next.next不得报错
slow = slow.next
fast = fast.next.next #null是没有next
if slow == fast: #这个时候说肯定是有环的,fast=slow=相遇节点
slow = head #一个节点指向头结点
while slow != fast:
slow = slow.next
fast = fast.next
return slow #返回相交节点
#while执行完,
return None
2.集合法: 集合.add(元素)
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
visited = set()
while head:
if head in visited:
return head
visited.add(head)
head = head.next
return None