24. 两两交换链表中的节点
Swap Nodes in Pairs - LeetCode
解题思路
设置虚拟头节点,一个指针pre从虚拟头结点出发,遍历链表
两两交换节点:
先保存pre.next节点为cur, pre.next.next节点为post
- cur.next 指向post.next, 断开post
- post.next 指向cur,断开之前的
- pre.next 指向post,断开cur
移动pre指针两步 pre = pre.next.next
遇到的问题
-
遍历链接的终止条件还是不完全清楚:
链表节点个数偶数时,刚好全部节点都被两两交换
链表节点个数奇数时,最后一个节点不用交换
-
交换节点的步骤还有点混乱
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode(0, head)
pre = dummy
while pre.next and pre.next.next:
# save cur and post position
cur = pre.next
post = pre.next.next
# change next point one by one, starting from cur.next to post.next
cur.next = post.next
post.next = cur
pre.next = post
pre = pre.next.next
return dummy.next
时间复杂度 O(N)
空间复杂度 O(1)
19.删除链表的倒数第N个节点
https://leetcode.com/problems/remove-nth-node-from-end-of-list/
解题思路
快慢指针,快指针先走n步,然后让快慢指针同时走。等快指针走到最后一个节点,慢指针刚好走到倒数第n -1个节点
要删除倒数第n个节点,慢指针一定要指向它的前一个节点
遇到的问题
遍历终止条件:while fast.next
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy = ListNode(0, head)
slow = fast = dummy
for i in range(n):
fast = fast.next
while fast.next:
slow = slow.next
fast = fast.next
slow.next = slow.next.next
return dummy.next
时间复杂度 O(N)
空间复杂度 O(1)
160. 链表相交
https://leetcode.com/problems/intersection-of-two-linked-lists/
解题思路
两个指针pa, pb分别指向lista和listb的头结点
如果lista和listb长度相等,两个指针相遇的时候,就是相交的节点,或者null(如果没有交点)
当长度不相等时:pa遍历完lista后遍历listb,pb遍历完listb后遍历lista
也是链表拼接的思想
遇到的问题
pa和pb遍历时的终止条件:while pa ≠pb
pa 和pb都要先走到各自原本list的null节点,再去遍历另一个list
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
pa = headA
pb = headB
while pa != pb:
pa = pa.next if pa else headB
pb = pb.next if pb else headA
return pa
时间复杂度 O(M+N)
空间复杂度 O(1)
142.环形链表II
Linked List Cycle II - LeetCode
解题思路
两个问题:
1. 判断链表是否环
2. 如果有环,如何找到这个环的入口
快慢指针解决,快指针每次移动两个节点,慢指针每次一个节点。
如果有环,快慢指针会在环里相遇。
快指针先入环,当慢指针入环后,快指针相当于在追慢指针。
快指针不会跳过慢指针,相对于慢指针,快指针每次一个节点一个节点的靠近慢指针。如果快指针每次移动3步,有可能跳过慢指针。
环的入口:在快慢指针的相遇点,继续让slow一步一步走,同时让指向head的另一个指针开始从头遍历链表,slow和指针相遇的节点,就是入环点。
遇到的问题
遍历链表的终止条件: fast 和fast.next 均不为空,因为fast每次走两步,所以fast.next也需要判断不为空
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
return slow
return None