代码随想录Day4 | 24. 两两交换链表中的节点 、19. 删除链表的倒数第N个节点 、160. 链表相交、142.环形链表II | 链表操作、双指针

530 阅读3分钟

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

题目链接:24. 两两交换链表中的节点 - 力扣(LeetCode)

思路: 基本的链表操作,注意链表的操作顺序,以及使用temp来存储需要存储的节点。

我的代码:

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode pre = dummy, cur = head;
        while (cur != null && cur.next != null) {
            ListNode temp = cur.next.next;
            pre.next = cur.next;
            pre.next.next = cur;
            cur.next = temp;
            pre = cur;
            cur = temp;
        }
        return dummy.next;
    }
}

问题:

总结:

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

题目链接:19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

思路: 刚开始的思路是先遍历得到链表的长度,然后可以知道需要删除的节点的索引,找到需要删除的节点的前一个节点,做相应操作即可。但是这样比较麻烦。 比较好的方法是通过快慢指针即可确认待删除节点的位置,fast先走n步,紧接着slow和fast同时向前走,每次一步,这样当fast == null时,slow会到达链表长度-n的位置,即倒数第n。为了方便删除,slow需要在删除的节点前一个停下,因此fast需要多走一步。

我的代码:

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if (head == null) return null;
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode slow = dummy;
        ListNode fast = dummy;
        while (n-- >= 0) {
            fast = fast.next;
        }
        while (fast != null) {
            slow = slow.next;
            fast = fast.next;
        }
        slow.next = slow.next.next;
        return dummy.next;
    }
}

问题: 写双指针解法的时候,把slow和fast初始为head,而不是dummy,这样导致如果要删除的节点是头节点,头节点之前的节点将无法访问到,无法删除。因此slow和fast的初始值要设为虚拟头节点。

总结:

设计删除链表节点的操作时,一定要考考虑到头节点是需要虚拟头节点来删除的!

160. 链表相交

题目链接:160. 相交链表 - 力扣(LeetCode)

思路: 用两个指针 p1 和 p2 分别在两条链表上前进,我们可以让 p1 遍历完链表 A 之后开始遍历链表 B,让 p2 遍历完链表 B 之后开始遍历链表 A,这样相当于「逻辑上」两条链表接在了一起。如果这样进行拼接,就可以让 p1 和 p2 同时进入公共部分,也就是同时到达相交节点。

我的代码:

class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode p1 = headA;
        ListNode p2 = headB;
        while (p1 != p2) {
            p1 = p1 == null ? headB : p1.next;
            p2 = p2 == null ? headA : p2.next; 
        }
        return p1;
    }
}

问题:

总结:

复习了判断两个链表是否相交。

142.环形链表II

题目链接:142. 环形链表 II - 力扣(LeetCode)

思路: 以前做过,(x + y) * 2 = x + y + n (y + z)想不起来了。关于判断是否成环:fast slow双指针。如果相等,说明成环,通过等式可以推出 x = z, 此时新建一个节点 = head, 和slow/fast一起每次前进一步,会在环的入口相遇。

我的代码:

class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        while (fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                ListNode p1 = head;
                while (p1 != slow) {
                    slow = slow.next;
                    p1 = p1.next;
                }
                return p1;
            }
        }
        return null; 
    }
}

问题:

  1. while (fast.next != null && fast.next.next != null) 这一步有问题,fast.next.next = null的情况 fast 是可以前进的,应该改为 while (fast != null && fast.next != null)。

正确代码:

class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                ListNode p1 = head;
                while (p1 != slow) {
                    slow = slow.next;
                    p1 = p1.next;
                }
                return p1;
            }
        }
        return null; 
    }
}

总结:

复习了判断两个链表是否成环。