代码随想录算法训练营Day4 | | 24. 两两交换链表中的节点 ,19.删除链表的倒数第N个节点 , 面试题 02.07. 链表相交

24. 两两交换链表中的节点

力扣题目链接

class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
        dummy_head = ListNode(next=head)
        current = dummy_head
        
        # 必须有cur的下一个和下下个才能交换,否则说明已经交换结束了
        while current.next and current.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

这段代码的目标是交换链表中相邻节点的值,实现链表的两两节点交换。它通过迭代的方式来实现这个目标:

- 创建一个虚拟头节点 `dummy_head`,并将其 `next` 指向原始链表的头节点 `head`。
- 创建一个指针 `current` 并初始化为虚拟头节点,用于遍历链表。
- 使用 `while` 循环来遍历链表,确保至少有两个节点可供交换。
- 在循环中,暂存当前节点 `current` 和需要交换的两个相邻节点的引用,以便后续修改节点的连接。
- 交换相邻节点的值,将 `current` 的 `next` 指向下一个节点,同时将原第二个节点的 `next` 指向原第一个节点,完成交换。
- 保持链表连接,将原第一个节点的 `next` 指向原第三个节点。
- 移动 `current` 到已交换节点的下一个位置,准备进行下一轮交换。
- 最终,返回 `dummy_head.next`,即交换后链表的头节点。

19.删除链表的倒数第N个节点

力扣题目链接

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

这段代码是用于删除单链表中倒数第 n 个节点的实现。以下是代码的逐行解释:

1. `dummy_head = ListNode(0, head)`:创建一个虚拟头节点 `dummy_head`,并将其 `next` 指针指向链表的头部 `head`。这个虚拟头节点的目的是简化处理链表头部的情况。

2. 创建两个指针 `slow` 和 `fast`,并将它们都初始化为虚拟头节点 `dummy_head`。这两个指针将在后续遍历链表中发挥作用。

3. `for i in range(n+1):`:这是一个循环,其中 `fast` 指针比 `slow` 指针快 `n+1` 步。这个循环的目的是将 `fast` 移动到距离 `slow` 恰好相隔 `n` 个节点的位置,以便后续删除倒数第 `n` 个节点。

4. `while fast:`:这是另一个循环,用于同时移动 `slow` 和 `fast` 指针,直到 `fast` 指针到达链表的末尾。此时,`slow` 指针将位于要删除的节点的前一个节点上。

5. `slow.next = slow.next.next`:通过这行代码,删除了第 `n` 个节点。具体来说,它将 `slow` 节点的 `next` 指针指向了 `slow.next.next`,跳过了第 `n` 个节点。

6. 最后,返回 `dummy_head.next`,即删除倒数第 `n` 个节点后的新链表的头节点。

这个算法通过使用两个指针,`slow` 和 `fast`,实现了删除倒数第 `n` 个节点的目标,同时避免了多次遍历链表。

面试题 02.07. 链表相交

同:160.链表相交

力扣题目链接

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        dis = self.getLength(headA) - self.getLength(headB)
        
        # 通过移动较长的链表,使两链表长度相等
        if dis > 0:
            headA = self.moveForward(headA, dis)
        else:
            headB = self.moveForward(headB, abs(dis))
        
        # 将两个头向前移动,直到它们相交
        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

这段代码是用于查找两个单链表的交点的实现。以下是代码的逐行解释:

1. `dis = self.getLength(headA) - self.getLength(headB)`:首先,计算两个链表的长度差,存储在变量 `dis` 中。这将帮助我们使两个链表的长度相等。

2. 如果 `dis > 0`,说明链表 A 较长,于是通过调用 `self.moveForward(headA, dis)` 将链表 A 的头节点向前移动 `dis` 步,以使两个链表的长度相等。

3. 如果 `dis <= 0`,说明链表 B 较长,于是通过调用 `self.moveForward(headB, abs(dis))` 将链表 B 的头节点向前移动 `abs(dis)` 步,以使两个链表的长度相等。

4. 接下来,使用循环遍历两个链表,同时移动它们的头节点,直到它们相交。如果在遍历过程中发现 `headA` 和 `headB` 相等,说明找到了交点,返回 `headA` 或 `headB`。

5. 如果循环结束后还没有找到交点,说明两个链表不相交,返回 `None`。

6. `getLength(self, head: ListNode) -> int`:这个方法用于计算链表的长度。通过遍历链表,每访问一个节点,增加计数器 `length`,最终返回链表的长度。

7. `moveForward(self, head: ListNode, steps: int) -> ListNode`:这个方法用于将链表头节点向前移动指定步数 `steps`。通过遍历链表,每移动一步,减少 `steps`,直到 `steps` 为 0,然后返回当前节点。

总的来说,这段代码通过计算链表长度差,使两个链表的头节点对齐,然后遍历链表找到交点。如果链表有交点,它会返回交点节点;如果没有,它会返回 `None`。

Java版,放进来是单纯被这个题解标题吸引。。。

代码随想录算法训练营Day4 | | 24. 两两交换链表中的节点 ,19.删除链表的倒数第N个节点 , 面试题 02.07. 链表相交_第1张图片

 `while` 循环内部的这两行代码:

```java
curA = (curA == null? headB : curA.next);
curB = (curB == null? headA : curB.next);
```

这两行代码是为了在两个链表中移动指针 `curA` 和 `curB`,并处理两个链表长度不同但有交点的情况。

1. `curA = (curA == null? headB : curA.next);`:这行代码的作用是移动 `curA` 指针。它首先检查 `curA` 是否为 `null`,也就是是否已经到达链表 `headA` 的末尾。如果 `curA` 是 `null`,说明链表 `headA` 已经走完了,此时将 `curA` 设置为链表 `headB` 的头节点,表示将 `curA` 跳到链表 `headB` 上。如果 `curA` 不是 `null`,则将 `curA` 向前移动一步,即 `curA.next`。

2. `curB = (curB == null? headA : curB.next);`:同样的逻辑,这行代码的作用是移动 `curB` 指针。它首先检查 `curB` 是否为 `null`,也就是是否已经到达链表 `headB` 的末尾。如果 `curB` 是 `null`,说明链表 `headB` 已经走完了,此时将 `curB` 设置为链表 `headA` 的头节点,表示将 `curB` 跳到链表 `headA` 上。如果 `curB` 不是 `null`,则将 `curB` 向前移动一步,即 `curB.next`。

这两行代码的目的是使 `curA` 和 `curB` 在两个链表中移动,并且在需要的情况下跳到对方的链表上,以处理两个链表长度不同但有交点的情况。通过这种方式,它们最终要么相遇在交点处,要么都到达链表的末尾,从而退出 `while` 循环。

142.环形链表II

力扣题目链接

lass Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        slow = head
        fast = head
        
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            
            # If there is a cycle, the slow and fast pointers will eventually meet
            if slow == fast:
                # Move one of the pointers back to the start of the list
                slow = head
                while slow != fast:
                    slow = slow.next
                    fast = fast.next
                return slow
        # If there is no cycle, return None
        return None
        

你可能感兴趣的:(leetcode,leetcode)