代码随想录day04:24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、160.链表相交、142.环形链表II

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

题目链接
代码随想录讲解
思路:主体是三个指针:例如:0—>1—>2—>3—>4,交换2,3:temp指向1,left和fast指向2
fast指向3;
left.next指向4即2—>4;
fast.next指向left,即3—>2;
temp.next指向fast,即1–>3;
交换完成:1—>3—>2—>4;
最后移动指针,temp指向left也就是2,right指向left.next也就是4,left指向right。
加入虚拟头节点,从virhead开始可以让交换原头节点和第二个节点的过程和后面的一样。
我写的时候因为有virhead,所以直接将head作为left了

class Solution {
    public ListNode swapPairs(ListNode head) {
        //如果只有一个节点或者没有节点则直接返回
        if(head==null||head.next==null)return head;
        //创建虚拟头节点
        ListNode virHead=new ListNode(-1);
        virHead.next=head;
        //通过三个节点指针交换
        ListNode temp=virHead;
        ListNode right=head;
        
        while(head!=null&&head.next!=null){
            right=head.next;
            head.next=right.next;
            right.next=head;
            temp.next=right;
            temp=head;
            right=head.next;
            head=right;
        }
        return virHead.next;

    }
}

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

题目链接
代码随想录讲解
思路:
删除倒数第n个节点,因为链表是单向的,所以只能从头遍历,定义两个指针,快指针先移动n次,再同步移动慢指针,最后慢指针指向的是需要删除节点的前一个节点。
代码随想录中说fast移动n+1步,其实和fast最后判断有关,假如fast指向null为终止条件,就是n+1步,假如fast.next==null为终止条件,就是n步,fast最后指向链表最后一个节点。

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if(head==null||head.next==null)return null;
        //需要虚拟头节点
        ListNode virhead=new ListNode();
        virhead.next=head;
        ListNode left=virhead;
        ListNode right=virhead;
        int k=0;
        //快指针移动n次
        while(right.next!=null&&k!=n){
            right=right.next;
            k++;
        }
        if(k==n){
            //同步移动
            while(right.next!=null){
                right=right.next;
                left=left.next;
            }
            //删除节点
            left.next=left.next.next;
        }
        return virhead.next;
    }
}

160.链表相交

题目链接
代码随想录
思路:
三种情况:1、A,B等长有公共部分;2、A,B不等长有公共部分;3、A,B没有公共部分
情况一:从headA和headB同时出发,每走一步判定是否为同一个节点;
情况二:假如A比B长n个节点,则A先走n个节点后,B再同时走,回到情况一;
情况三:因为情况二会回到情况一,即情况一走完都没有公共节点。
代码:从headA和headB同时走,若等长,则同时到达公共节点,或者同时到达尾节点;若不等长,一定有一个先到尾节点,假设是tempA先到达尾节点,则B比A长,此时让tempA转向headB,在tempB到达尾节点时,tempA在B上已经移动了B-A的次数,此时让tempB转向headA,则tempA和tempB在相同长度链表上移动,一定同时到达公共节点或者尾节点。

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //为空就不可能有公共节点
        if(headA==null||headB==null)return null;
        ListNode tempA=headA;
        ListNode tempB=headB;
        //判断是否为同一节点
        while(tempA!=tempB){
            if(tempA.next==null){
                tempA=headB;
            }else{
                tempA=tempA.next;
            }
            if(tempB.next==null){
                tempB=headA;
            }else{
                tempB=tempB.next;
            }
            //两个节点同时走到尾节点也没找到公共节点
            if(tempA.next==null&&tempB.next==null&&tempA!=tempB)return null;
       }
       return tempA;
    }
}

142.环形链表II

题目链接
代码随想录
思路:没想出来,看的卡哥的题解。之前在牛客网上刷过类似的题,但那道可以修改链表,通过创建一个空链表作为标记,当找到next指向空链表的节点时,即为入口。这道题不允许修改链表。就只能通过快慢指针的方式了。
判断链表是否环
如果有环,如何找到这个环的入口

判断链表是否有环:
可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
为什么fast 走两个节点,slow走一个节点,有环的话,一定会在环内相遇呢,而不是永远的错开呢
首先第一点:fast指针一定先进入环中,如果fast指针和slow指针相遇的话,一定是在环中相遇,这是毋庸置疑的。
因为fast是走两步,slow是走一步,其实相对于slow来说,fast是一个节点一个节点的靠近slow的,所以fast一定可以和slow重合。
如果有环,如何找到这个环的入口:
(建议直接看curl哥的讲解,配上图好理解一些)
fast指针一步走两个节点,slow指针一步走一个节点, 所以 fast指针走过的节点数 = slow指针走过的节点数 * 2:
(x + y) * 2 = x + y + n (y + z)
两边消掉一个(x+y): x + y = n (y + z)
因为要找环形的入口,那么要求的是x,因为x表示 头结点到 环形入口节点的的距离。
所以要求x ,将x单独放在左面:x = n (y + z) - y ,
再从n(y+z)中提出一个 (y+z)来,整理公式之后为如下公式:x = (n - 1) (y + z) + z 注意这里n一定是大于等于1的,因为 fast指针至少要多走一圈才能相遇slow指针。
主要理解为什么slow是x+y,fast是x+n*(y+z);
slow入环时,fast一定在环内某个位置,其实可以用两个环来表示,slow周期为2T,fast周期为T,在2T内一定会相遇一次。

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode slow=head;
        ListNode fast=head;
        //判断是否有环
        while(fast!=null&&slow.next!=null&&fast.next!=null){
            slow=slow.next;
            fast=fast.next.next;
            //环存在
            if(slow==fast){
                fast=head;
                while(slow!=fast){
                    slow=slow.next;
                    fast=fast.next;
                }
                return slow;
            }
        }
        return null;
        
    }
}

链表总结

虚拟头节点:让循环操作一致,而不用对原头节点作单独处理。
链表的基本操作:(虽然自己写出来了,但是第一遍bug很多,主要是根据索引插入和删除,怎么找到索引的位置,当索引非法怎么处理)
获取链表第index个节点的数值
在链表的最前面插入一个节点
在链表的最后面插入一个节点
在链表第index个节点前面插入一个节点
删除链表的第index个节点的数值
反转链表、删除倒数第N个节点、链表相交、环形链表:虚拟头节点以及双指针的运用。
环形链表中的数学方法还需要后面再理一理。

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值