算法训练Day4|链表

63 阅读1分钟

24 两两交换链表中的节点

public ListNode swapPairs(ListNode head) {
    if (head == null || head.next == null) {
        return head;
    }
    ListNode next = head.next;
    head.next = swapPairs(next.next);
    next.next = head;
    return next;
}

终止条件为只剩一个或者没有

public ListNode swapPairs(ListNode head) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode temp = dummy;

    while (temp.next != null && temp.next.next != null) {
        ListNode start = temp.next;
        ListNode end = temp.next.next;

        temp.next = end;
        start.next = end.next;
        end.next = start;
        temp = start;
    }

    return dummy.next;
}

新建虚拟头节点dummy

start为相邻的左,end为相邻的右

19 删除链表的倒数第N个节点 比较简单的双指针

public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;

    ListNode slow = dummy;
    ListNode fast = dummy;
    for (int i = 0; i < n; i++) {
        fast = fast.next;
    }

    while (fast.next != null) {
        slow = slow.next;
        fast = fast.next;
    }

    slow.next = slow.next.next;
    return dummy.next;
}

因为是倒数第n个 所以想到快慢指针 让他们之间间隔n-1,

链表相交

if (headA == null || headB == null) {
        return null;
    }
    ListNode pA = headA, pB = headB;
    while (pA != pB) {
        pA = pA == null ? headB : pA.next;
        pB = pB == null ? headA : pB.next;
    }
    return pA;
}

题没怎么读懂

142 环形链表II

自己想到的是哈希表,遍历每个节点,放到哈希表中, 如果该节点的next节点在表中,那么该点就是入口

public ListNode detectCycle(ListNode head) {
    ListNode dummy = head;
    Set<ListNode> listNodeSet = new HashSet<>();

    while (dummy != null) {
        if (listNodeSet.contains(dummy)) {
            return dummy;
        } else {
            listNodeSet.add(dummy);
        }

        dummy = dummy.next;
    }
    return null;
}

如下图所示,设链表中环外部分的长度为 a。slow 指针进入环后,又走了 b 的距离与 fast 相遇。此时,fast 指针已经走完了环的 n 圈,因此它走过的总距离为 a+n(b+c)+b=a+(n+1)b+nc。

双指针法,没想到,需要数学推导

fig1

根据题意,任意时刻,fast 指针走过的距离都为 slow 指针的 2 倍。因此,我们有

a+(n+1)b+nc=2(a+b)⟹a=c+(n−1)(b+c)

有了 a=c+(n−1)(b+c) 的等量关系,我们会发现:从相遇点到入环点的距离加上 n−1 圈的环长,恰好等于从链表头部到入环点的距离。

因此,当发现 slow 与 fast 相遇时,我们再额外使用一个指针 ptr。起始,它指向链表头部;随后,它和 slow 每次向后移动一个位置。最终,它们会在入环点相遇。

if (head == null) {
    return null;
}
ListNode slow = head, fast = head;
while (fast != null) {
    slow = slow.next;
    if (fast.next != null) {
        fast = fast.next.next;
    } else {
        return null;
    }
    if (fast == slow) {
        ListNode ptr = head;
        while (ptr != slow) {
            ptr = ptr.next;
            slow = slow.next;
        }
        return ptr;
    }
}
return null;