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

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


想法:今天开始上难度了,哈哈,很有收获,温习了很多遗忘的知识点。

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

题目描述:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

在这里插入图片描述

想法:使用虚拟头节点,进行节点交换。

大致做法就是:先设置一个指针cur指向虚拟头节点,然后再设置三个指针f,s,t,分别指向cur.next,cur.next.next,cur.next.next.next,然后进行移动操作。最后要注意:我们要返回的是虚拟头节点的next
如下图所示:
在这里插入图片描述

    // 设置虚拟头节点,便于操作
    public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null)
            return head;
        ListNode dummyNode = new ListNode(-1);
        dummyNode.next = head;
        ListNode cur = dummyNode;
        // 分别是cur的next,next.next,next.next.next
        // 用于交换节点的连接
        ListNode first;
        ListNode second;
        ListNode third;
        // cur != null 可以不加,因为cur.next != null表明了cur不为null
        while (cur.next != null && cur.next.next != null) {
            third = cur.next.next.next;
            first = cur.next;
            second = cur.next.next;
            // 节点操作
            cur.next = second;
            second.next = first;
            first.next = third;
            // 关键点:移动cur,为下一次移动准备
            cur = first;
        }

        return dummyNode.next;
    }
}

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

题目描述:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
在这里插入图片描述

做法:学习的代码随想录的做法,如下所示:

定义fast指针和slow指针,初始值为虚拟头结点,如图:
在这里插入图片描述

fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作),如图:
在这里插入图片描述

fast和slow同时移动,直到fast指向末尾,如图:
在这里插入图片描述

删除slow指向的下一个节点,如图:
在这里插入图片描述

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if(head==null)
            return head;
        
        //设置虚拟头节点
        ListNode dummyNode=new ListNode(-1);
        dummyNode.next=head;
        //fast指针先走n+1步,然后fast和slow再一起走。
        //直到fast为null,表示slow走到了倒数第n个节点的前面,然后进行删除操作
        ListNode fast=dummyNode;
        ListNode slow=dummyNode;
        for(int i=0;i<=n;i++)
            fast=fast.next;
        
        while(fast!=null) {
            fast=fast.next;
            slow=slow.next;
        }
        slow.next=slow.next.next;
        //返回时注意,dummyNode是虚拟节点,真正的节点是dummyNode.next
        return dummyNode.next;
    }
}

面试题 02.07. 链表相交link

题目描述:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
在这里插入图片描述

想法:看着代码比较好理解,原理就是每次a或b指针交换指向的节点时就会抵消中间的差值,可以画个图感受一下;对于不相交时,两个会共同指向null值,返回null。
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA==null || headB==null)
            return null;

        ListNode a=headA;
        ListNode b=headB;
        while(a!=b) {
        //若a走到headA的尾部,然后就指向headB
        //b同理
            a=a==null?headB:a.next;
            b=b==null?headA:b.next;
        }
        return a;
    }
}

142.环形链表II link

题目:给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

在这里插入图片描述

别看代码长,其实比较好理解😂

思路:
// 先求出链表中环形链表节点的个数len(使用快慢指针,相遇的地方为环形链表内,然后让一个指针停下,另一个指针接着走,计算遇到停下指针的步数,即为len)
然后设置两个指针指向头节点,让其中一个先走len步,然后一起走,相遇的地方为入环的第一个节点。

public class Solution {
    
    public ListNode detectCycle(ListNode head) {
        if(head==null || head.next==head) {
            return head;
        }
        ListNode fast=head;
        ListNode slow=head;
        //fast与slow相遇
        while(fast!=null && fast.next!=null) {
            fast=fast.next.next;
            slow=slow.next;
            if(fast==slow) {
                break;
            }
        }
        //注意:这里要判断一下,判断fast是避免环不存在
        //为什么不是判断slow,因为fast=fast.next.next;可以导致fast为null,如果fast都没问题,那么slow也没问题
        if(fast==null || fast.next==null)
            return null;
        //fast指针停止,slow指针移动,寻找环形节点的长度
        int len=1;
        while(true) {
            slow=slow.next;
            if(slow==fast) {
                break;
            }
            len++;
        }
        ListNode a=head;
        ListNode b=head;
        //b先走len步
        for(int i=0;i<len;i++) {
            b=b.next;
        }
        while(true) {
            if(a==b) {
                return a;
            }
            a=a.next;
            b=b.next;
        }
    }
}

希望对您有帮助,谢谢观看!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值