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

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

时间:2023-12-18 14:57:23浏览次数:45  
标签:结点 ListNode 随想录 fast next 链表 节点 指针

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

● 今日学习的文章链接和视频链接

代码随想录 (programmercarl.com)

题目链接

24. 两两交换链表中的节点 - 力扣(LeetCode)

● 自己看到题目的第一想法

主要是把这个过程想清楚,链表交换的题目主要想明白要动几个指针,指针改变的顺序也要注意,如果有需要就要提前要保存一些指针

public ListNode swapPairs3(ListNode head) {
        //交换两个结点到底要改变几个指针?
        //两个结点之间的指针要反向,并且这对节点的前一个结点要重新指向新结点,这对结点指向后一个结点的指针也会改变
        //所以要提前保存前一个结点和后一个结点
        //既然涉及到前一个结点的操作了,那么就可以构造一个虚拟头节点
        ListNode tmpHead = new ListNode(0, head);
        ListNode cur = head;
        ListNode pre = tmpHead;
        ListNode next;
        while (cur != null && cur.next != null) {
            next = cur.next.next;
            //指针一个一个改
            pre.next = cur.next;
            cur.next.next = cur;
            cur.next = next;
            pre = cur;
            cur = cur.next;//交换之后指针的位置已经相当于往后挪动了
        }
        return tmpHead.next;
    }

● 看完代码随想录之后的想法

我的cur指针指向的是当前pairs中的第一个,所以保存的是前后的指针,卡尔用的是pairs前一个指针作为当前指针,保存的是pairs中的第一个后pairs后的一个结点。我还尝试了一下别的改指针顺序,发现至少还是要保存两个结点的

● 自己实现过程中遇到哪些困难

● 今日收获,记录一下自己的学习时长

1h

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

● 今日学习的文章链接和视频链接

 代码随想录 (programmercarl.com)

题目链接

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

● 自己看到题目的第一想法

    public ListNode removeNthFromEnd2(ListNode head, int n) {
        //怎么删除倒数第n个结点,关键在于如何判断当前结点是倒数第n个,倒数第n个就是从尾巴往回走n步
        //一般来说,正数第n个很好判断,倒数第n个就需要两个指针了
        //慢指针和快指针之间相差n步,让快指针走到头,慢指针所在的位置就是倒数第n个
        ListNode fast = head;
        ListNode slow=head;
        while (n > 1) {
            fast = fast.next;
            n--;
        }
        ListNode tmpHead = new ListNode(0, head);
        ListNode pre = tmpHead;
        while (fast.next != null) {
            fast = fast.next;
            slow = slow.next;
            pre = pre.next;//保存前一个指针
        }
        pre.next = slow.next;
        return tmpHead.next;
    }

● 看完代码随想录之后的想法

指针冗余了,直接让快慢指针相差n+1步就行,快指针走到头,慢指针正好是要删除结点的前一个

         ListNode fast = head;
        // ListNode slow=head;
        while (n > 1) {
            fast = fast.next;
            n--;
        }
        ListNode tmpHead = new ListNode(0, head);
        ListNode pre = tmpHead;
        while (fast.next != null) {
            fast = fast.next;
            // slow = slow.next;
            pre = pre.next;//保存前一个指针
        }
        // pre.next = slow.next;
        pre.next = pre.next.next;
        return tmpHead.next;

● 自己实现过程中遇到哪些困难

对于n个步长的理解,其实就是指针往后移动n次,然后倒数第几个是从倒数第一个开始算的,所以n=1时步长为0;让快指针挪动n步时的循环条件怎么写,还是具体带入两个数值检验一下

● 今日收获,记录一下自己的学习时长

0.5h

 

 LeetCode面试题02.07. 链表相交

● 今日学习的文章链接和视频链接

 代码随想录 (programmercarl.com)

题目链接

 面试题 02.07. 链表相交 - 力扣(LeetCode)

● 自己看到题目的第一想法

    public ListNode getIntersectionNode2(ListNode headA, ListNode headB) {
        //两个链表在一个地方相交,那么链表A的长度假设是a+c,链表B的长度假设是b+c
        //那么A走到头之后再走b步,B走到头之后再走a步;两个指针走的距离一定是相等的,妙不妙
        //妙啊
        if (headA == null || headB == null) {
            return null;
        }
        ListNode a = headA;
        ListNode b = headB;
        int count = 0;
        while (count < 2) {
            if (a == b) {                 break;             }             a = a.next;             b = b.next;             if (a == null) {                 a = headB;                 count++;             }             if (b == null) {                 b = headA;             }
        }
        if (count == 2) {
            return null;
        }
        return a;
    }

● 看完代码随想录之后的想法

卡尔的做法是让两个链表尾端对齐,然后开始移动指针,这样也挺直观的。可以用前面那道题找到链表的倒数第n个结点,不过要先遍历两个链表看哪个更长,长度短的那个链表长度为size,长度长的链表的快指针走size-1步。

● 自己实现过程中遇到哪些困难

我写的时候通过debug,才发现判断条件是有先后顺序的。第一,如果先移动指针再判断两个结点是否相等,就会漏掉头指针。第二,如果先判断指针是否为null再移动到另一个链表头部,再移动指针,这就相当于指针跳过了一个结点;因此需要先移动指针,再判断是否为null,为null就跳到另一个链表的头节点,这样才不会漏掉任何一个结点

总结要点是不能漏掉链表中每个要遍历的结点。

● 今日收获,记录一下自己的学习时长

 1h

 

 LeetCode142.环形链表II

● 今日学习的文章链接和视频链接

 代码随想录 (programmercarl.com)

题目链接

 142. 环形链表 II - 力扣(LeetCode)

● 自己看到题目的第一想法

记得这道题是用快慢指针,但是不知道为什么快慢指针一定会相遇

● 看完代码随想录之后的想法

public ListNode detectCycle2(ListNode head) {
        //这道题的主要思路是用快慢指针,一个指针每次走两步,一个指针每次走一步
        //如果有环的话,这两个指针一定会相遇,为什么呢?
        // 因为快指针先进入环中,慢指针后进入环内,那么快指针相对于慢指针的移动速度是一步,快指针一定会追上慢指针
        // 慢指针遍历完一圈环的时候,快指针一定走了两圈了,由于我们应该考虑相对运动速率
        //所以在这个过程中快指针一定会经过慢指针
        //综上,慢指针走过的路程=2(x+y)=快指针走过的路程=x+y+n(y+z)
        //化简一下:x+y=n(y+z)=> x=n(y+z)-y=> x=(n-1)(y+z)+z
        //这说明,一个指针从环内相遇的位置出发,另一个指针从头出发,两者一定会在环的入口相遇
        //我们这里判断的依据就是指针走过的距离一定相等,所以此时指针移动的速率一定要保持一致
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next!=null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                slow = head;
                while (slow != fast) {
                    fast = fast.next;
                    slow = slow.next;
                }
                return fast;
            }
        }
        return null;
    }

● 自己实现过程中遇到哪些困难

主要是要想明白相遇的道理,以及为什么找到相遇点之后,从相遇的地方出发,两个指针一定会在结点的入口相遇

● 今日收获,记录一下自己的学习时长

 1.5h

 

总结

 

  • 链表的存储形式

链表与数组不同,在内存中不是连续的,因此每个结点都有一块区域用来存储下一块结点的地址

  • 链表的增删改查

链表的增删都有需要注意的地方,也即要保留一些指针,并且经常涉及到对于目标位置的前一个结点的指针的改变

因此,对于头结点这种没有前置结点的处理还需要额外进行判断,为了让操作具有统一性,我们在头结点之前保留一个虚拟头结点。

  • 设计链表

这里依旧是为了操作统一,增加一个虚拟头结点作为成员变量。否则增删的操作不统一。而且进行头插法尾插法还要判断当前是不是第一个结点,因为我们需要知道链表的头到底是哪个

  • 反转链表

把链表每一个结点的指针都反向,指向前一个,所以要有前置结点,也要保存后一个结点

  • 两两交换链表

主要要想清楚这个断开指针然后重连的过程

  • 删除倒数第n个

主要在于如何找到这个结点,两个指针相隔n步,一起往后移动

  • 链表相交

一个指针走到头后走到另一个链表的头,用图纸演示会很容易想明白距离上的等量关系

  • 链表的环

为什么从相遇的地方出发一定能与从头出发的指针在环的入口相遇?这道题还比较复杂,所以需要多复习,主要是要想明白一些数学推理的过程

 

总的来说,前半部分的题主要是基础操作,后半部分的题目有两种,一种是只要想清楚链表的断开重联过程就好了,例如反转链表和交换链表的两个结点,另一种是要进行一些数学计算的过程推算,找到等量关系

标签:结点,ListNode,随想录,fast,next,链表,节点,指针
From: https://www.cnblogs.com/xiaoni2023/p/17911205.html

相关文章

  • 【反转子链表】模拟题
    leetcode92.反转链表II题意:反转链表的[left,right],返回链表表头题解:直接模拟删除的过程即可定义重要节点记录left位置的节点为lnode,right位置的节点为rnodelnode的前驱节点为pre,right位置的后继节点为suc初始化pre=suc=lnode=rnode=原链表表头前的虚拟节点......
  • 链表
    1.链表概念使用数组存储数据的缺陷:插入和删除需要移动数据复杂度为O(N)不好那么,是否有一种存储结构可以在插入删除数据时不需要移动数据?答案是链表什么是链表?链表是一种在逻辑上连续存储但是在物理上(内存空间)中不一定连续的存储结构,如下图链表中的每一个元......
  • k8s集群从一千节点增加到五千台节点遇到的瓶颈
    Kubernetes自从1.6起便号称可以承载5000个以上的节点,但是从数十到5000的路上,难免会遇到问题。在kubernetes5000之路上的经验,包括遇到的问题、尝试解决问题以及找到真正的问题。1、问题一:1~500个节点之后问题:kubectl有时会出现timeout(p.s.kubectl-v=6可以显示所......
  • 链表递归题型
    递归的定义在定义一个过程或函数时出现调用本过程或本函数的成分,称之为递归。若调用自身,称之为直接递归。若过程或函数p调用过程或函数q,而q又调用p,称之为间接递归。递归算法的设计递归的求解过程均有这样的特征:先将整个问题划分为若干个子问题,通过分别求解子问题,最后获......
  • 链表面试题解析
    链表面试题解析1.删除链表中=val的所有节点/***Definitionforsingly-linkedlist.*publicclassListNode{*intval;*ListNodenext;*ListNode(){}*ListNode(intval){this.val=val;}*ListNode(intval,ListNodenext){......
  • [LeetCode138-链表-中等] 复制带有随机指针的链表
    这道题是这样的,就是说有一个链表LindedNode,通常我们链表包含2个属性,一个是它的值val,另一个是它指向的下一个结点nextNode,但是这个题目中的链表还有一个属性,就是它还有个随机指针,这个随机指针可能指向链表中的任意结点(包括链表的结尾null结点,或者是自己)也就是说这个链表Lin......
  • 141.环形链表
    给你一个链表的头节点head,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪next指针再次到达,则链表中存在环。如果链表中存在环,则返回true。否则,返回false。示例输入:head=[3,2,0,-4];输出:true思路:循环遍历链表,检查是否存在重复的节点,可以使用......
  • 代码随想录算法训练营第四天 | 24. 两两交换链表中的节点,19.删除链表的倒数第N个节点,
    一、24.两两交换链表中的节点题目链接:LeetCode24.两两交换链表中的节点学习前:思路:未新增虚拟结点。节点数为0,1,2需要另外讨论。当节点数>=2时,返回的head值为第2个节点,需要3个指针first、second、prev,分别是第一个节点和第二个节点,以及第一个节点的前节点。while(first......
  • 142. 环形链表 II
    1.题目介绍给定一个链表的头节点 \(head\) ,返回链表开始入环的第一个节点。 如果链表无环,则返回 \(null\)。如果链表中有某个节点,可以通过连续跟踪\(next\)指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数\(pos\)来表示链表尾连接到链表中的......
  • 142.环形链表II
    题目142.环形链表II要求给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中......