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

题目链接:24.两两交换链表中的结点

 

思路:此题通过观看卡老师的视频讲解,理解的很透彻,直接上链接,下面我把观看视频做的笔记放出来

视频链接:帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点_哔哩哔哩_bilibili《代码随想录》视频讲解开讲啦!快来打卡!代码随想录刷题网站:programmercarl.com, 视频播放量 34807、弹幕量 552、点赞数 993、投硬币枚数 775、收藏人数 212、转发人数 31, 视频作者 代码随想录, 作者简介 我是Carl,哈工大师兄,先后在腾讯和百度从事一线技术研发的程序员,公众号「代码随想录」,相关视频:两两交换链表中的节点,【LeetCode 每日一题】24. 两两交换链表中的节点 | 手写图解版思路 + 代码讲解,程序员必刷算法题:交换链表中的节点,帮你把KMP算法学个通透!(理论篇),1721. Swapping Nodes in a Linked List 单链表交换节点 0263,链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点,【小白学算法】交换链表中的节点,24.两两交换链表中的节点,手把手带你学会操作链表 | LeetCode:203.移除链表元素,队列的基本操作! | LeetCode:225. 用队列实现栈https://www.bilibili.com/video/BV1YT411g7br

笔记:

 代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummyhead=new ListNode(0);//设置一个虚拟头结点
        dummyhead.next=head;//将虚拟头结点指向head,这样方面后面做的删除操作
        ListNode cur=dummyhead;//初始化
        //临时结点,保存两个结点后面的结点(例如2、4……)
        ListNode temp;
        ListNode temp1;
        //循环条件里面的先后顺序不能变,否则会发生空指针异常
        while(cur.next!=null&&cur.next.next!=null){
            temp=cur.next;
            temp1=cur.next.next.next;
            cur.next=cur.next.next;
            cur.next.next=temp;
            temp.next=temp1;
            cur=cur.next.next;
        }
        return dummyhead.next;
    }
}

时间复杂度:O(n)

空间复杂度:O(1)

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

思路:本题的难点在于如何找到倒数第n个节点(待删除元素) 的前一个节点的位置,通过观看卡老师的视频,可以:

1、首先定义虚拟头结点,然后定义fast指针和slow指针指向虚拟头结点

2、fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作)

3、fast和slow同时移动,直到fast指向null。此时慢指针所在的位置便是待删除元素的前一个

4、删除slow指向的下一个节点

视频链接:链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点_哔哩哔哩_bilibili《代码随想录》视频讲解开讲啦!快来打卡!代码随想录刷题网站:programmercarl.com, 视频播放量 26947、弹幕量 441、点赞数 681、投硬币枚数 503、收藏人数 147、转发人数 34, 视频作者 代码随想录, 作者简介 我是Carl,哈工大师兄,先后在腾讯和百度从事一线技术研发的程序员,公众号「代码随想录」,相关视频:男同胞们,请放弃对女程序员的所有幻想,当男程序员和女程序员开始交往后.....,不喜欢写代码怎么办???还有救么?,童锦程被终极粉丝线下强吻,单杀祖师爷。,4年级神童自学编程,每天刷leetcode上的编程题目,只为了长大后能进大公司工作,太厉害了,Leetcode力扣 1-300题视频讲解合集|手画图解版+代码【持续更新ing】,【LeetCode 每日一题】19. 删除链表的倒数第 N 个结点 | 手写图解版思路 + 代码讲解,删除链表重复节点【基础算法精讲 08】,手把手带你学会操作链表 | LeetCode:203.移除链表元素,帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点https://www.bilibili.com/video/BV1vW4y1U7Gf

代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //首先定义一个虚拟头节点
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = head;
        //然后给其初始化,定义两个快慢指针指向虚拟头节点,定义其目的是为了方便找到倒数第n个节点的前一个节点的那个位置,因为前一个节点才能对后面要删除的节点进行操作
        ListNode fastIndex = dummyHead;
        ListNode slowIndex = dummyHead;
        //核心思路就是题目给定倒数第n个节点,然后让快指针先移动n+1个节点,然后再同时移动快慢指针直到快指针指向Null,此时,慢指针所在的位置就是倒数第n个节点前一个节点的位置
        for(int i=0; i<=n; i++){
            fastIndex=fastIndex.next;
        }
        //上一步快指针已经到了n+1的位置了,下一步就需要同时移动快慢指针了,将慢指针移动到指定位置
        while(fastIndex!=null){
            fastIndex = fastIndex.next;
            slowIndex = slowIndex.next;
        }
        //此时slowIndex的位置就是待删除元素的前一个位置,接下来进行对倒数第n个元素删除的操作
        slowIndex.next = slowIndex.next.next;
        return dummyHead.next;
    }
}

题目链接:力扣面试题02.07.链表相交

思路:简单来说,就是求两个链表交点节点的指针 这里要注意,交点不是数值相等,而是指针相等。 因为一个节点不可能有两个next指针。这里和val值没啥直接关系,两个val相同不一定就相交,但是如果相交,那么从这个相交节包括之后的所有节点val值都是相同的。

1、首先有两个链表,目前curA指向链表A的头结点,curB指向链表B的头结点

2、我们求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 对齐的位置

3、此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB(⚠️注意,实际比较的是指针相同,不是val),则找到交点

代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode curA = headA;
        ListNode curB = headB;
        int lenA = 0, lenB = 0;
        while (curA != null) { 
            // 求链表A的长度
            lenA++;
            curA = curA.next;
        }
        while (curB != null) { 
            // 求链表B的长度
            lenB++;
            curB = curB.next;
        }
        //为什么还要初始化一次?因为前面让curA和B去遍历了一遍链表统计长度  结束之后它们走到空指针去了,所以要把它们放回链表头去执行后面的下一次遍历
        curA = headA;
        curB = headB;
        // 让curA为最长链表的头,lenA为其长度
        if (lenB > lenA) {
            //1. swap (lenA, lenB);
            int tmpLen = lenA;
            lenA = lenB;
            lenB = tmpLen;
            //2. swap (curA, curB);
            ListNode tmpNode = curA;
            curA = curB;
            curB = tmpNode;
        }
        // 求长度差
        int gap = lenA - lenB;
        // 让curA和curB在同一起点上(末尾位置对齐)
        while (gap-- > 0) {
            curA = curA.next;
        }
        // 遍历curA 和 curB,遇到相同则直接返回(首先要知道如果相交,一个节点不可能有两个next指针。这里和val值没啥直接关系,两个val相同不一定就相交,但是如果相交,那么从这个相交节包括之后的所有节点val值都是相同的)
        while (curA != null) {
            if (curA == curB) {
                return curA;
            }
            curA = curA.next;
            curB = curB.next;
        }
        return null;
    }
}

题目链接:142.环形链表II

思路:建议观看卡老师的视频,下面是观看视频做的笔记:

视频链接:把环形链表讲清楚! 如何判断环形链表?如何找到环形链表的入口? LeetCode:142.环形链表II_哔哩哔哩_bilibili《代码随想录》视频讲解开讲啦!快来打卡!代码随想录刷题网站:programmercarl.com, 视频播放量 34268、弹幕量 588、点赞数 1257、投硬币枚数 1076、收藏人数 286、转发人数 74, 视频作者 代码随想录, 作者简介 我是Carl,哈工大师兄,先后在腾讯和百度从事一线技术研发的程序员,公众号「代码随想录」,相关视频:公司新来00后写的代码,看到这段话我差点笑出猪叫,男同胞们,请放弃对女程序员的所有幻想,当你过度准备了一场代码面试时……,C语言__Leetcode_142题环形链表II,数据结构-单链表-判断单链表是否有环,如果有,找出环的入口,一周刷爆LeetCode,算法大神左神(左程云)耗时100天打造算法与数据结构基础到高级全家桶教程,直击BTAJ等一线大厂必问算法面试题真题详解,帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点,判断链表是否有环,『教程』哈希表是个啥?,链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点https://www.bilibili.com/video/BV1if4y1d7ob

 

主要考察两知识点:

  • 判断链表是否环
  • 如果有环,如何找到这个环的入口

1、判断链表是否有环

可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环

2、如果有环,如何找到这个环的入口

假设从头结点到环形入口节点 的节点数为x。 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。 从相遇节点 再到环形入口节点节点数为 z。正如上图笔记中:

因为上述推断出x=z, 这就意味着,从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点

代码如下:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
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){
                //如果相等,证明有环,接下来要判断入环的第一个节点,因为在卡老师的视频里讲过(看个人笔记),x=z,即从相遇的那个节点的位置到环入口位置的这段距离和从头节点head到环入口的这段距离是相等的,接下来创建两个指针,一个指向头节点,一个指向相遇的位置(此时fast/slow的位置),让这两个指针不断向后移动,直到两者相等,也就是入环的那个节点的位置(此时index1/index2的位置)
                ListNode index1=fast;
                ListNode index2=head;
                //  两个指针,从头节点和相遇节点,各走一步,直到相遇。相遇点即为环入口
                while(index1!=index2){
                    index1=index1.next;
                    index2=index2.next;
                }
                return index1;
            }
        }
        return null;
    }
}

时间复杂度: O(n),快慢指针相遇前,指针走的次数小于链表长度,快慢指针相遇后,两个index指针走的次数也小于链表长度,总体为走的次数小于 2n

空间复杂度: O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ethan_lwh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值