算法修炼day04|● 24. 两两交换链表中的节点 ● 19.删除链表的倒数第N个节点 ● 面试题 02.07. 链表相交 ● 142.环形链表II

82 阅读2分钟

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

定义虚拟头节点起到忽略头节点的作用,定义临时节点指向虚拟头节点起到定位的作用,采用双指针的方法交换临时节点后两个节点,进行更新用于循环交换。

代码实现:

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode pre = new ListNode(0, head); // 虚拟头节点
        ListNode temp = pre; // 临时节点
        while (temp.next != null && temp.next.next != null) {
            ListNode start = temp.next; // 双指针 1
            ListNode end = temp.next.next; // 双指针 2
            temp.next = start.next; // 顺畅体现在这里!!!!!!!!(这里可以有掌声)
            start.next = end.next;
            end.next = start;
            temp = start;
        }
        return pre.next;
    }
}

题目:

删除倒数第n个节点,属于双指针的应用扩展,让前指针先移动n个节点。此后双指针start和end同时向后移动,直到start移动到尾部null时,此时end对应的就是要删除的节点。但要删除end处的节点,就应该将end到达要删除节点的前一节点位置,则循环判断条件设置为start.next != null

代码实现:

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummyHead = new ListNode(0, head); // 虚拟头节点
        ListNode start = dummyHead; // 双指针 1
        ListNode end = dummyHead; // 双指针 2
        for (int i = 0; i < n; i++) { // 两指针间隔为 n
            start = start.next;
        }
        while (start.next != null) {
            start = start.next;
            end = end.next;
        }
        end.next = end.next.next; // 这里用 start 不合适,存在一种特殊情况:删除倒数第一个节点,返回的结果包含start节点
        return dummyHead.next;
    }
}

题目:

两链表相交的特性是尾部对其,因此可以围绕链表长度来做。遍历获取两链表长度,指定较为长的一条为基准,先遍历差值长度保证两遍历起始点相同,之后进行循环判等就行。没有相等的结果则输出null。

代码实现:

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        // 两个链表相交之后尾部是对齐的
        // 求两链表的长度,分别计算起始位置,从各自起始位置依次向后遍历,判断两链表节点值是否相同
        ListNode curA = new ListNode(0, headA);
        ListNode curB = new ListNode(0, headB);
        int lenA = 0;
        int lenB = 0;
        while (curA.next != null) {
            curA = curA.next;
            lenA++;
        }
        while (curB.next != null) {
            curB = curB.next;
            lenB++;
        }
        curA = headA;
        curB = headB;
        if (lenB > lenA) {
            int temp = lenA;
            lenA = lenB;
            lenB = temp;
            ListNode tempNode = curA;
            curA = curB;
            curB = tempNode;
        }
        int diff = lenA - lenB;
        while (diff-- > 0) {
            curA = curA.next;
        }
        while (curA != null) {
            if (curA == curB) {
                return curA;
            }
            curA = curA.next;
            curB = curB.next;
        }
        return null;
    }
}

题目:

双指针的拓展。前指针走两步,后指针走一步。如果链表有环则一定会相遇,需要知道一个结论:如果两节点相遇,则从相遇节点到环形入口和从头节点到环形入口的节点数是相同的。进行循环判断即可。

代码实现:

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


public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head, slow = head;
        while (true) {
            if (fast == null || fast.next == null) {
                return null;
            }
            fast = fast.next.next;
            slow = slow.next;
            if (slow == fast) break;
        }
        fast = head;
        while (fast != slow) {
            fast = fast.next;
            slow = slow.next;
        }
        return fast;
    }
}