24. 两两交换链表中的节点
# 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_head = ListNode(next,head)
cur = dummy_head
while (cur.next != None and cur.next.next != None):
temp1 = cur.next # 存储节点防止断链
temp2 = cur.next.next.next
cur.next = cur.next.next # 开始交换节点
cur.next.next = temp1
temp1.next = temp2
cur = cur.next.next
return dummy_head.next
总结:本题依然要用到虚拟头节点。使用temp1和temp2把第一次交换的第二个节点和第二次交换的第二个节点保存下来。防止断链。需要注意的是,循环的判断条件。每次处理cur后面的两个节点。当节点总数量为偶数时,cur指针会被更新到最后一个节点,此时如果下个节点为空,则停止循环,奇数时cur指向倒数第二个节点。还要注意的是必须先判断cur.next然后再判断cur.next.next,反过来的话发生指针异常。
19.删除链表的倒数第N个节点
# 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_head = ListNode(next, head)
quick = dummy_head
slow = dummy_head
for _ in range(n+1):
quick = quick.next
while quick != None:
quick = quick.next
slow = slow.next
slow.next = slow.next.next
return dummy_head.next
总结:本题重点要想到使用双指针找到倒数第N个节点,即快指针先走N步,然后快慢指针再同步移动,当快指针为空时,慢指针指向倒数第N个节点。因为需要进行删除链表节点,所以需要拿到被操作节点的前一个节点,所以我们让快指针走N+1步,那么当循环结束时,慢指针指向的就是被操作节点的前一个节点。
160. 链表相交
# 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) -> ListNode:
lenA, lenB = 0, 0
cur = headA
while cur:
cur = cur.next
lenA += 1
cur = headB
while cur:
cur = cur.next
lenB += 1
curA, curB = headA, headB
if lenA > lenB: # 让curB始终为最长链表的头
curA, curB = curB, curA
lenA, lenB = lenB, lenA
for _ in range(lenB - lenA):
curB = curB.next
while curA:
if curA == curB:
return curA
else:
curA = curA.next
curB = curB.next
return None
总结:本题主要是让两条链靠墙站着,链表尾部对齐。思想和上一题的快慢指针有点类似。先求出两个链表的长度,让长的链接先走两个链表长度的差值。这时判断指针是否相等,相等的话就可以返回了,不相等再进行后移。需要注意:交点不是数值相等,而是指针相等。
142.环形链表II
# 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 = head
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
总结:这题有两个重点。
怎么判断有环:利用快慢指针,快指针一次走两步,慢指针一次走一步。如果有环的话,那么快慢指针一定会相遇。
怎么找环的入口处:假设从头结点到环形入口节点 的节点数为x。 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。 从相遇节点 再到环形入口节点节点数为 z。那么有(x + y) * 2 = x + y + n (y + z)。整理得x = (n - 1) (y + z) + z。n一定是大于等于1的,因为 fast指针至少要多走一圈才能相遇slow指针。n=1那么公式就为x=z。从头结点出发一个指针,从相遇节点也出发一个指针,这两个指针每次只走一个节点,那么当这两个指针相遇的时候就是环形入口的节点。n大于1时情况相同,不过是快指针在环里多转了几圈