day04两两交换链表结点_删除链表倒数第n个结点_链表相交_环形链表2_总结

力扣24.两两交换链表结点

题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/

难点

搞清楚两个结点交换的过程,temp应该存哪个结点的值。

https://programmercarl.com/0024.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.html#%E6%80%9D%E8%B7%AF

自身实现遇到的困难

1.没有用head结点,导致转换指针经常进入死胡同。

2.指针交换顺序错误。对于这方面应该多找题看看。

3.temp值存错。

完整代码

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=head.next.next;
            cur.next=head.next;
            head.next.next=head;
            head.next=temp;
            cur=head;
            head=head.next;
        }
        return dummyhead.next;
    }
}

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

题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/

要点

如何找到倒数第N个结点。

快慢指针

1.令快慢指针同时指向虚拟头结点。

2.快指针先移动n步,然后快慢指针同时移动。这样,当快指针指向链表末尾null时,慢指针和快指针差n,就找到了倒数第n个结点。

3.关键是,删除结点需要获取要删除结点的前一个结点。所以,让快指针先走n+1步,这样,当快指针指向null时,慢指针刚好指向要删除结点的前一个结点。

完整代码

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummyhead=new ListNode(0,head);
        ListNode slow=dummyhead;
        ListNode fast=dummyhead;
        for(int i=0;i<n+1;i++){
            fast=fast.next;
        }
        while(fast!=null){
            fast=fast.next;
            slow=slow.next;
        }
        slow.next=slow.next.next;
        return dummyhead.next;
    }
}

力扣160.链表相交

题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/description/

要点

注意,要找的是链表相交的指针,而不是值。题目中为方便理解,把相交结点的值也设为相同。但实际上找的是相交的指针。这也是为什么在if判断语句中直接判断的是cura==curb。

完整代码

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int lena=0;
        int lenb=0;
        ListNode cura=headA;
        ListNode curb=headB;
        //获取A链表长度
        while(cura!=null){
            lena++;
            cura=cura.next;
        }
        //获取B链表长度
        while(curb!=null){
            lenb++;
            curb=curb.next;
        }
        cura=headA;
        curb=headB;
        //指定A链表为较长的那个
        if(lenb>lena){
            //交换链表长度
            int temp=lenb;
            lenb=lena;
            lena=temp;
            //交换两个链表的指向头结点的指针
            ListNode tempnode=cura;
            cura=curb;
            curb=tempnode;
        }
            //把两条链表的末端对齐
            int gap=lena-lenb;
            while(gap-->0){
                cura=cura.next;
            }
            while(cura!=null){
                if(cura==curb){
                    return cura;
                }
                cura=cura.next;
                curb=curb.next;
            }
        return null;
    }
}

力扣142.环形链表2

题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/

完整代码

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

难点

1.如何判断是否有环?

定义快慢指针。快指针一次走两格,慢指针一次走一格。

无环时,快慢指针永远无法相遇。反之,则会相遇。

2.有环为什么快指针一定会和慢指针相遇而不会错过?

快指针一定比慢指针先入环,快指针相对于慢指针来说一次相当于走一格。所以快慢指针一定会相遇。

解题过程

在这里插入图片描述

如图所示。

相遇时慢指针走过的路程:x+y

相遇时快指针走过的路程:x+y+n(y+z),n>=1

x+y=x+y+n(y+z),求得x=(n-1)(y+z)+z.

1.n为什么大于等于1?

n>=1的意思是相遇时快指针已经走了不止一圈。想象以下,快慢指针相遇必须是快指针去追慢指针,因此一定不会在第一圈就追上。

2.为什么慢指针走过的路程不是x+y+k(y+z)?

如图所示。将一圈拉成一条线段。快指针一定先进入环,当慢指针在入口处时,假设想要走一圈即走到下一个入口,那么快指针走的路程是慢指针的两倍,所以一定会在慢指针到达下一个入口前和它相遇。

这道题的数学思路让我感到很奇妙,将圈转换成线段,用变量来证明,值得我反复复习思考。

链表总结

虚拟头结点

让解题以统一的写法写出,省时省事。

链表的基本操作

增删改查

反转链表

和数组的交换有些相似,但要注意要让交换结点的上一个结点指向交换后的结点。例如,需要交换第三个和第四个结点,那么需要将第二个结点指向反转过来的原第四个结点。

链表相交

需要注意的是链表相交的结点是内存地址相同的结点。

环形链表2

如何利用快慢指针判断有环,如何找到环的入口,数学证明和思路值得反复复习。

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值