算法打卡Day04(补卡) | 链表篇-两两交换链表中的节点、删除链表的倒数第 N 个结点、链表相交、环形链表II

54 阅读2分钟

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

题目链接:leetcode.cn/problems/sw…

关键词:两两交换相邻节点、不改变内部值

不修改节点内部的值的情况下,就是改变链表的下一指向

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dumyHead = new ListNode();
        dumyHead.next = head;
        ListNode cur = dumyHead;
        //奇偶两种情况判断逻辑不同
        while(cur.next!=null && cur.next.next!=null){
            ListNode temp = cur.next;
            ListNode temp1 = cur.next.next.next;
            cur.next = temp.next;
            cur.next.next = temp;
            temp.next = temp1;
            cur = cur.next.next;
        }
        return dumyHead.next;
    }
}

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

题目链接:leetcode.cn/problems/re…

关键词:倒数的n用正数得到,快慢指针移动

关键:如何操作倒数第n个(无法得知链表的size),使用快慢指针,相隔n个节点

操作链表第n个节点时,要遍历到n-1位置的节点,再去操作第n个节点(比如设计链表中的删除某个index节点和在index添加节点的操作)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dumyHead = new ListNode();
        dumyHead.next = head;
        //此处要指向虚拟头节点dumyHead,这样fast和slow之间差n+1
        ListNode slow = dumyHead;
        ListNode fast = dumyHead;
        for(int i = 0; i<=n; i++){
            fast = fast.next;
        }
        while(fast!=null){
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return dumyHead.next;
        
    }
}

面试题02.07. 链表相交

题目链接:leetcode.cn/problems/in…

关键点:求相交,从后面往前看,所以让size小的后移

在没有n的情况下遍历链表while(cur!=null){cu = cur.next}

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //求相交的地方,前面没有重复的,后面必然有重复的
        int lenA = 0;
        int lenB = 0;
        ListNode curA = headA;
        ListNode curB = headB;
        while(curA!=null){
            lenA++;
            curA = curA.next;
        }
        while(curB!=null){
            lenB++;
            curB = curB.next;
        }
        //⏰此处记得将cur改为头节点
        curA = headA;
        curB = headB;
        //哪个长?无法判断哪个长,就指定lenA为最长
        if(lenB>lenA){
            int temp = lenA;
            lenA = lenB;
            lenB = temp;
            ListNode temp1 = curA;
            curA = curB;
            curB = temp1;
        }
        int gap = lenA-lenB;
        //⏰此处i<gap,不理解就举个例子
        for(int i=0; i<gap; i++){
            curA =curA.next;
        }
        //如何判断二者是否相交?当前的两个cur指针相等 相等则说明指向同一个
        while(curA!=null){
            if(curA==curB){
                return curA;
            }
            curA = curA.next;
            curB = curB.next;
        }
        return null;
    }
}

142.环形链表II

题目链接:leetcode.cn/problems/li…

关键点:数学思维

详解链接:programmercarl.com/0142.%E7%8E…

关键点

  1. 快慢指针相遇时的节点到环形链表入口的距离=头节点到环形链表入口的距离
  2. slow=x+y;fast=x+y+n(y+z); slow:fast=1:2
  3. slow!=x+y+n(y+z)的原因是fast和slow相遇必定是在第一圈完成的

image-20240918232950233

代码

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        //快指针不为null的情况下,慢指针必然不为null
        while(fast!=null &&fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){
                ListNode index1 = fast;
                ListNode index2 = head;
                while(index1!=index2){
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        return null;
​
    }
}