代码随想录算法训练营第四天: 24.两两交换链表中的节点 19.删除链表的倒数第N个节点 160(面试题).链表相交 142.环形链表II

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

要点 : 把要操作的节点单独用指针标出来, 思路会更清晰

class Solution {
    public ListNode swapPairs(ListNode head) {
        //普通方法
        ListNode dummy = new ListNode(0,head);
        ListNode cur = dummy;
        while(cur.next != null && cur.next.next != null){
            ListNode node1 = cur.next;
            ListNode node2 = cur.next.next;
            cur.next = node2;
            node1.next = node2.next;
            node2.next = node1;
            cur = cur.next.next;
        }
        return dummy.next;
    }
}

递归 :

第一步 : 假设后面已经处理好,如何处理当前节点

第二步 : 分析什么条件下终止

第三步 : 标出有关返回值的操作节点如head , head.next ; 后面一团看作整体标出返回值对应节点,逐步分析操作

class Solution {
    public ListNode swapPairs(ListNode head) {
        //递归
        if(head == null || head.next == null){
            return head;
        }

        head.next.next = swapPairs(head.next.next);
        ListNode temp = head.next;
        head.next = head.next.next;
        temp.next = head;
        head = temp;
        return head;
    }
}

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

双指针:利用相对位置 , 得到倒数第n个节点的前一个节点的位置

屡次犯错 : 有dummy的返回不是head而是dummy.next

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head);
        ListNode fast = dummy;
        ListNode slow = dummy;
        for(int i = 0; i <= n; i++){
            fast = fast.next;
        }
        while(fast != null){
            fast = fast.next;
            slow = slow.next;
        }
        //注意判断空指针
        if(slow.next != null){
        slow.next = slow.next.next;
        }
        return dummy.next;
    }
}

160(面试题).链表相交

  • 假设链表A的长度为a,链表B的长度为b,相交部分的长度为c
  • 指针p1走过的总路径长度为a + (b - c),指针p2走过的总路径长度为b + (a - c)
  • 由于a + (b - c) = b + (a - c),两个指针最终会在相交节点相遇。
  • 若不相交, c = 0, 则总路径为 a + b, 即会在null相遇
(版本二) 合并链表实现同步移动
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
		// p1 指向 A 链表头结点,p2 指向 B 链表头结点
		ListNode p1 = headA, p2 = headB;
		while (p1 != p2) {
			// p1 走一步,如果走到 A 链表末尾,转到 B 链表
			if (p1 == null) p1 = headB;
			else            p1 = p1.next;
			// p2 走一步,如果走到 B 链表末尾,转到 A 链表
			if (p2 == null) p2 = headA;
			else            p2 = p2.next;
		}
		return p1;
    }
}

142.环形链表II

两个问题 : 是否有环 and 入口在哪

**是否有环 : **快慢指针法 : 快指针和慢指针一定会在环中相遇

**入口在哪 : **根据公式 (x + y) * 2 = x + y + n (y + z) 可以得出 x = (n - 1) (y + z) + z

​ 说明如果有关指针从头出发,另一个指针从相遇的位置出发 , 他们一定会在入口相遇

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

                while(p1 != p2){
                    p1 = p1.next;
                    p2 = p2.next;
                }
                return p1;
            }
        }
        return null;
    }
}