代码随想录算法训练营第4天 | 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交

47 阅读2分钟

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

本题并没有什么特别的算法技巧,主要考察链表断链和重新链接,直接想的话会有些绕,使用虚拟头节点并且画图更好理解:

image-20240127115714379.png

image-20240127120047249.png

image-20240127120231339.png

image-20240127120325358.png

image-20240127120458697.png

    class Solution {
        public ListNode swapPairs(ListNode head) {
            if (head == null || head.next == null) return head;
    ​
            ListNode dummyHead = new ListNode(0,head);
            ListNode prev = dummyHead;
            while(prev.next != null && prev.next.next != null)
            {
                ListNode cur = prev.next;
                ListNode next = cur.next;
                //交换
                cur.next = next.next;
                next.next = cur;
                prev.next = next;
    ​
                prev = cur;
            }
            return dummyHead.next;
        }
    }

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

这道题是双指针在链表中的应用,想要找到倒数第n个节点,那么可以先让fast指针先走n步(从1计步),再与slow指针一起走,当fast到达末尾,则slow指向的就是倒数第n个节点。但是要注意的是,要执行链表的删除操作,需要找到待删除的节点的前一个节点,即走n+1步(从1计步)。

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

面试题 02.07. 链表相交

这道题迷惑的点在于输入案例有一点难理解,但是只看题目就行。它本质不难,是找两个链表的公共节点。我们找到解决方法的关键在于,如果能把两个链表从尾部对其,那么公共节点就一目了然。而要实现这一步,我们可以让长链表先走n步(两链表的差值),再一起遍历,那么就相当于对其了。

public class Solution {
        public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
            ListNode curA = headA;
            ListNode curB = headB;
            int lenA = 0;
            int lenB = 0;
            while(curA != null)
            {
                curA = curA.next;
                lenA++;
            }
            while(curB != null)
            {
                curB = curB.next;
                lenB++;
            }
            //遍历后归位
            curA = headA;
            curB = headB;
            int diff = 0;
            //判断哪个链表更长,就先走。
            if(lenA > lenB)
            {
                diff = lenA - lenB;
                while(diff-- > 0)
                {
                    curA = curA.next;
                }
            }
            else
            {
                diff = lenB - lenA;
                while(diff-- > 0)
                {
                    curB = curB.next;
                }
            }
            //同时移动
            while(curA != null )
            {
                if(curA == curB)
                {
                    return curA;
                }
                else
                {
                    curA = curA.next;
                    curB = curB.next;
                }
            }
            return null;
        }
    }

反思

这道题最开始思路不清晰,虽然知道长链表要先走差值步数,但是在写代码的时候忽略了,要判断哪条链表更长。不过,按照代码随想录的思想,其实可以多做一次交换判断,让A链表始终为最长的。

142.环形链表II

这道题的难点不是单纯的处理方法,而是涉及到一些数学运算。刚拿到的时候,完全没有优解的思路。多写几次记住思路,并且能自己复述出来就是目标。方法就是双指针,fast每次走2步,slow每次走1步。

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