LeetCode:24. 两两交换链表中的节点
初看比较绕,但是把链表交换的过程在草稿纸上模拟一遍就清晰不少。
关键在于要理解两两交换时,交换的是cur指针的后两个节点(引入虚拟头节点统一交换方式,让头节点也遵循此方式),交换后cur指针往后走两个节点。那么对于偶数长度的链表来说,cur.next为空时停止循环;奇数长度的链表,cur.next.next为空停止循环。
每次交换要修改两个节点的指向(如1-2-3-4,2指向1,1指向3),为了避免修改指向后,链表断链,需要在修改指向前先用temp1缓存1,temp2缓存3,以此类推。
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode(0, head)
cur = dummy
while cur.next != None and cur.next.next != None:
temp = cur.next
temp1 = cur.next.next.next
cur.next = cur.next.next
cur = cur.next
cur.next = temp
cur = temp
temp.next = temp1
return dummy.next
LC 19.删除链表的倒数第N个节点
思路:涉及删除操作,引入虚拟头节点。
想找到倒数第n个节点,可以使用快慢指针。一开始两指针都指向dummy,然后fast先走N步,之后快慢指针同时往后走,直到快指针为空停止,那么此时慢指针所指即为待删除节点。
但是像上一题一样,想操作某个节点(无论是删除还是改变指针指向),都必须获取这个节点的前一个节点,然后在进行操作。那么一开始fast先走n+1步,之后同时走,快指针为空时停止,此时慢指针指向的就是待删除节点的前一个节点。这里很巧妙,多想几遍才懂。
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy = ListNode(next = head)
fast , slow = dummy ,dummy
for i in range(n+1):
fast = fast.next
while fast:
fast = fast.next
slow = slow.next
slow.next = slow.next.next
return dummy.next
当然,一个更容易想到的方法(也是我一开始做的办法)是先计算出链表的长度,直接for _ in range(size-n)就找到了待删除的节点。不过这个方法时间复杂度更高,计算长度以及执行删除时都要遍历链表,而双指针只需一次遍历。
class Solution:
def get_size(self,head):
temp = head
size = 0
while temp:
size += 1
temp = temp.next
return size
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy = ListNode(next = head)
temp = dummy
for i in range(self.get_size(head)-n):
temp = temp.next
temp.next = temp.next.next
return dummy.next
LC 160.链表相交
链表相交,本质是两个链表有共同的节点K,即链表A中的节点K=链表B中的节点K。
为了逐个比较链表的结点,需要先让两个链表尾部对齐,如图,再分别从节点6、节点11开始逐一比较。也就是长度大的那个链表,指针先往前走两链表长度之差步,再开始比较。
class Solution:
def get_size(self,head):
temp = head
size = 0
while temp:
size += 1
temp = temp.next
return size
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
size_A = self.get_size(headA)
size_B = self.get_size(headB)
curA ,curB = headA , headB
if size_A > size_B:
for _ in range(size_A - size_B):
curA = curA.next
while curA:
if curA == curB:
return curA
else:
curA = curA.next
curB = curB.next
return None
else:
for _ in range(size_B - size_A):
curB = curB.next
while curB:
if curA == curB:
return curA
else:
curA = curA.next
curB = curB.next
return None
总结下,本题关键:一是理解相交的那个节点就是链表A和B中都相等(值和指针)的那个节点,二是逐个比较时,先把两链表尾部对齐,长的那个链表先走个单位再开始比对
LC 142 环形链表
实在理解不了快慢指针,我选择哈希表。。
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
cur = head
s = set()
while cur:
if cur not in s:
s.add(cur)
cur = cur.next
else:
return cur
return None