海智算法训练营第四天 | 第二章 链表part02 | 24两两交换链表中的节点 19删除链表的倒数第N个节点 面试题02.07.链表相交 142环形链表ll

 学习目标:

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

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

3.面试题02.07.链表相交

4.142环形链表ll

5.总结

1.24两两交换链表中的节点

两两交换链表中相邻节点,需要设置虚拟头节点dummyhead,用这张图做类比,因为先让dummyhead指向2节点,再让2节点指向1节点,这时候需要将1节点和3节点用temp保存下来,因为当dummyhead指向2节点的时候1节点就丢失了,同理,当2节点指向1节点的时候3节点也丢失了,所以需要保存这两个位置上的节点。

题目:两两交换链表中的节点

代码如下:


class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummyhead = new ListNode(0,head);
        ListNode cur = dummyhead;
        while(cur.next!=null && cur.next.next!=null){
            //两两交换
            ListNode temp = cur.next;//保存第一个节点
            ListNode temp1 = cur.next.next.next;//保存第二个节点后面一个
            cur.next = cur.next.next;
            cur.next.next = temp;
            temp.next = temp1;
            cur = cur.next.next;
        }
        return dummyhead.next;
    }
}

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

此题的技巧就是通过两个指针,当快指针指向n位置的时候,将快慢指针同时往后移,当块指针指向null的时候慢指针也就指向了倒数第n个数,但在这里要注意先让fast指针先走一步,因为删除操作必须要在删除节点的前一位进行操作。

题目:删除链表的倒数第N个节点


class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummyhead = new ListNode(0, head);
        // 定义快慢指针,先让快指针n+1步,为了让慢指针指向要删除的前一位
        ListNode fast = dummyhead;
        ListNode slow = dummyhead;
        n++;
        while (n-- > 0) {
            fast = fast.next;
        }

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

        slow.next = slow.next.next;
        return dummyhead.next;
    }
}

3.面试题02.07.链表相交

这题主要思路是将两个链表的尾巴对齐,同时让两个指针从短的链表的头指针的位置一起向后遍历,也就是让指针所处位置相同。当两个指针的值一样的时候,则就是相交的点。

题目:链表相交

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode a = headA;
        ListNode b = headB;
        int lenA=0,lenB=0;
        while(a!=null){
            a =a.next;
            lenA++;
        }

        while(b!=null){
            b =b.next;
            lenB++;
        }
        
        a = headA;b=headB;
        //方便计算,以A为长的一条
        if(lenA < lenB){
            //记录临时a长度
            int tempLen = lenA;
            lenA = lenB;
            lenB = tempLen;
            //记录临时a节点
            ListNode tempNode = a;
            a = b;
            b = tempNode;
        }
        int len = lenA-lenB;
        while(len-->0){
            a = a.next;
        }

        while(a!=null){
            if(a == b){
                return a;
            }
            a= a.next;
            b= b.next;
        }

        return null;
    }
}

此题还有需要注意的点:a = headA;b=headB;这一段代码需要在交换a,b位置之前执行,因为在前面求链表长度的时候a,b节点已经移到了链表末尾,需要还原到头节点,当然创造两个新节点也可以但没必要。

4.142环形链表ll

这道题目涉及的数学知识比较多,需要画图解释。

​首先定义了快慢指针,快指针以每次移动两个点的速度移动,慢指针则以一个点一次的速度移动,当它们可以相遇的时候一定有环,有人会问了,那有环的情况下慢指针会遇不上快指针吗,答案是不会,因为他们的相对速度是一次一个节点,所以一定会遇上。

所以就延申出了这么一张图,令x为起点到环入口的距离,y为环入口到相遇点的距离,z为相遇点到环出口的距离,因为肯定是在环中相遇的,快指针的速度又是慢指针的两倍,所以就有了以上的公式,2(x+y) = x+y + n(z+y),n是快指针转的圈数。        这时我们可以忽略转的圈数,因为最终的相对位置跟转的圈数无关,所以可以得到x = z的结论。

问题:为什么慢指针的公式是移动的距离是(x+y),而不是(x+y)+n(y+z)呢,因为在慢指针刚刚进入环的时的第一圈就能和慢指针遇上,可以看下面这张图:

当慢指针在刚进入入口的时候,假设快指针在后面,在慢指针到达下一个出口的时候,快指针一定已经超过了下一个出口,所以在此期间快慢指针一定会遇上。

所以,最后的结论是通过 x=z 来找到环的入口,使两个指针分别在起点和相遇点以相同的速度移动,最后相遇的点就是环的入口。

题目:环形链表||

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 (fast == slow) {
                ListNode meetNode = fast;
                ListNode beginNode = head;
                while (meetNode != beginNode) {
                    meetNode = meetNode.next;
                    beginNode = beginNode.next;
                }
                return meetNode;
            }
        }
        return null;
    }
}

代码比较简单就不细琐了,主要是思路。

学习时长:共5h,早上2h学习dfs,晚上3h学习链表第二章。

总结:这次学习了如何交换链表中的相邻节点,并且学习到了查找倒数第n个节点和寻找相交节点的技巧,还学习了环形链表的相关知识。这次的学习让我加深了对链表章节的理解,我会常常回头复习,为之后的链表更深的题打下了更牢固的基础。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值