额外题目汇总2-链表

链表

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

力扣题目链接(opens new window)

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

24.两两交换链表中的节点-题意

思路

使用虚拟头结点会很方便,要不每次针对头结点(没有前一个指针指向头结点),还要单独处理。

链表:听说用虚拟头节点会方便很多? (opens new window)。

接下来就是交换相邻两个元素

初始时,cur指向虚拟头结点,然后进行如下三步:

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

操作之后,链表如下:

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

看这个可能就更直观一些了:

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

 

public class Swap_Nodes_in_Pairs {
    public static class ListNode {//ListNode 是一个静态内部类,用于表示链表中的节点。
        int val;//存储节点的值。
        ListNode next;//指向下一个节点的引用。
        public ListNode(int val) {//构造函数,用于创建一个新的节点,并将其值初始化为传入的参数 val。
            this.val = val;
        }
    }
 public ListNode swapPairs3(ListNode head) {
        ListNode dummy = new ListNode(0);//创建一个值为 0 的虚拟头节点 dummy。虚拟头节点的引入能够统一处理链表头节点的交换情况,避免了对头节点进行特殊处理的复杂性。
        dummy.next = head;//把虚拟头节点的 next 指针指向原链表的头节点 head,从而将虚拟头节点接入到原链表中。
        ListNode cur = dummy;//创建一个指针 cur 并初始化为虚拟头节点,后续会使用这个指针来遍历链表。
        while (cur.next != null && cur.next.next != null) {//保证了当前 cur 节点后面至少存在两个节点,这样才能进行节点的两两交换。
            ListNode node1 = cur.next; //要交换的两个节点中的第一个节点。
            ListNode node2 = cur.next.next;//要交换的两个节点中的第二个节点。
            cur.next = node2;//实现了当前节点跳过 node1 直接指向 node2。
            node1.next = node2.next;//第 1 个节点指向第 2 个节点的下一个节点
            node2.next = node1; //把 node2 的 next 指针指向 node1,完成了 node1 和 node2 两个节点的交换。
            cur = cur.next.next;//将 cur 指针移动到当前交换完成的节点对的下一个节点对的前一个节点位置,为下一轮的节点交换做准备。
        }
        return dummy.next;//当循环结束后,链表中所有相邻的节点对都已经完成了交换操作。由于虚拟头节点的 next 指针指向的就是交换后的链表头节点,所以直接返回 dummy.next。
    }
}

时间复杂度

我们遍历链表一次,每次处理两个节点。由于每个节点只被访问一次,因此时间复杂度为 O(n),其中 n 是链表中节点的数量。

 空间复杂度

该方法只使用了常量级别的额外空间来存储指针(如 dummy , cur , node1 , node2 ),并没有使用任何额外的数据结构来存储节点。因此,空间复杂度为 O(1)。

时间复杂度:O(n)

空间复杂度:O(1)

链表 1 -> 2 -> 3 -> 4

1. 初始化

  • 创建一个虚拟头节点 dummy,其值为 0
  • 将 dummy 的 next 指针指向原链表的头节点 head(这里 head 指向节点 1)。
  • 初始化指针 cur 指向虚拟头节点 dummy

此时链表结构如下(dummy 为虚拟头节点):

dummy(0) -> 1 -> 2 -> 3 -> 4
  ^
  cur

2. 第一次交换(处理节点 1 和 2) 

  • 获取要交换的节点
    • ListNode node1 = cur.next;node1 指向节点 1
    • ListNode node2 = cur.next.next;node2 指向节点 2
  • 交换节点
    • cur.next = node2;:让 cur(即 dummy)的 next 指针指向 node2(节点 2)。
    • node1.next = node2.next;:让 node1(节点 1)的 next 指针指向 node2 的下一个节点(节点 3)。
    • node2.next = node1;:让 node2(节点 2)的 next 指针指向 node1(节点 1)。

交换后链表结构变为:

dummy(0) -> 2 -> 1 -> 3 -> 4
              ^
              cur
  • 移动指针cur = cur.next.next;:将 cur 指针移动到当前交换完成的节点对(2 -> 1)的下一个节点对的前一个节点(节点 1)。

3. 第二次交换(处理节点 3 和 4

此时 cur 指向节点 1,继续循环:

  • 获取要交换的节点
    • ListNode node1 = cur.next;node1 指向节点 3
    • ListNode node2 = cur.next.next;node2 指向节点 4
  • 交换节点
    • cur.next = node2;:让 cur(节点 1)的 next 指针指向 node2(节点 4)。
    • node1.next = node2.next;:让 node1(节点 3)的 next 指针指向 node2 的下一个节点(这里为 null)。
    • node2.next = node1;:让 node2(节点 4)的 next 指针指向 node1(节点 3)。

交换后链表结构变为:

dummy(0) -> 2 -> 1 -> 4 -> 3 -> null
                      ^
                      cur
  • 移动指针cur = cur.next.next;:将 cur 指针移动到当前交换完成的节点对(4 -> 3)的下一个节点对的前一个节点,但此时 cur.next == null,不满足循环条件,循环结束。

4. 返回结果

由于 dummy.next 指向节点 2,所以最终返回交换后的链表 2 -> 1 -> 4 -> 3

2.234.回文链表

力扣题目链接(opens new window)

请判断一个链表是否为回文链表。

示例 1:

  • 输入: 1->2
  • 输出: false

示例 2:

  • 输入: 1->2->2->1
  • 输出: true

思路

数组模拟

最直接的想法,就是把链表装成数组,然后再判断是否回文。

反转后半部分链表

分为如下几步:

  • 用快慢指针,快指针有两步,慢指针走一步,快指针遇到终止位置时,慢指针就在链表中间位置
  • 同时用pre记录慢指针指向节点的前一个节点,用来分割链表
  • 将链表分为前后均等两部分,如果链表长度是奇数,那么后半部分多一个节点
  • 将后半部分反转 ,得cur2,前半部分为cur1
  • 按照cur1的长度,一次比较cur1和cur2的节点数值

如图所示:

public class Palindrome_Linked_List {
    public static class ListNode {//ListNode 是一个静态内部类,用于表示链表中的节点。
        int val;//存储节点的值。
        ListNode next;//指向下一个节点的引用。

        public ListNode(int i) {
            this.val = i;
        }
    }
    public boolean isPalindrome1(ListNode head) {
        int len = 0;//初始化一个整型变量 len 用于记录链表的长度,初始值为 0。
        ListNode cur = head;//创建一个指针 cur 并将其指向链表的头节点 head,用于遍历链表。
        while (cur != null) {//while 循环遍历链表,只要 cur 不为 null,就表示还没有遍历到链表的末尾。
            len++;//每遍历一个节点,就将 len 的值加 1。
            cur = cur.next;//将 cur 指针移动到下一个节点。
        }
        cur = head;//将 cur 指针重新指向链表的头节点,为将链表元素存储到数组做准备。
        int[] res = new int[len];//创建一个长度为 len 的整型数组 res,用于存储链表中的元素。
        for (int i = 0; i < res.length; i++){//for 循环遍历数组,将链表中的元素依次存储到数组中。
            res[i] = cur.val;//将当前 cur 指针所指向节点的值存储到数组的第 i 个位置。
            cur = cur.next;//将 cur 指针移动到下一个节点。
        }
        for (int i = 0, j = len - 1; i < j; i++, j--){//使用双指针法,i 从数组的起始位置开始,j 从数组的末尾位置开始,向中间移动。只要 i < j,就表示还没有比较完所有对称位置的元素。
            if (res[i] != res[j]){//如果数组中对称位置的元素不相等,说明链表不是回文链表,直接返回 false。
                return false;
            }
        }
        return true;//如果循环结束后都没有发现不相等的元素,说明链表是回文链表,返回 true。
    }
}

 时间复杂度

1. 计算链表长度:我们遍历链表一次以计算长度,时间复杂度为 O(n),其中 \(n\) 是链表的节点数。

2. 存储链表元素到数组:我们再次遍历链表,将元素存储到数组中,时间复杂度也是 O(n)。

3. 比较数组元素:最后,我们进行一次比较,时间复杂度为 O(n/2)(因为只需比较一半的元素),但在大O表示法中,常数因子通常被省略,因此这部分的时间复杂度也是 O(n)。 综合以上步骤,总的时间复杂度为 O(n)。

空间复杂度

1. 数组存储:我们创建了一个长度为 n 的整型数组来存储链表的元素,因此空间复杂度为 O(n)。 2. 其他变量:除了数组外,使用的其他变量(如指针和整型变量)占用的空间是常数级别的O(1)。 因此,总的空间复杂度为 O(n)。

时间复杂度: O(n)

空间复杂度: O(n)

1 -> 2 -> 2 -> 1

1. 初始化变量

  • len 初始化为 0,用于记录链表的长度。
  • cur 指针初始化为指向链表的头节点 head,这里 head 指向值为 1 的节点。

此时链表结构如下:

1 -> 2 -> 2 -> 1
^
cur

2. 统计链表长度

  • 第一次循环:cur 指向值为 1 的节点,len 加 1 变为 1,cur 移动到下一个节点(值为 2 的节点)。
  • 第二次循环:cur 指向值为 2 的节点,len 加 1 变为 2,cur 移动到下一个节点(另一个值为 2 的节点)。
  • 第三次循环:cur 指向值为 2 的节点,len 加 1 变为 3,cur 移动到下一个节点(值为 1 的节点)。
  • 第四次循环:cur 指向值为 1 的节点,len 加 1 变为 4,cur 移动到 null,循环结束。

此时得到链表长度 len = 4

3. 将链表元素存储到数组中

  • cur 重新指向链表的头节点(值为 1 的节点)。
  • 创建长度为 4 的整型数组 res
  • 第一次循环:i = 0res[0] 赋值为 cur 指向节点的值 1,cur 移动到下一个节点(值为 2 的节点)。
  • 第二次循环:i = 1res[1] 赋值为 cur 指向节点的值 2,cur 移动到下一个节点(另一个值为 2 的节点)。
  • 第三次循环:i = 2res[2] 赋值为 cur 指向节点的值 2,cur 移动到下一个节点(值为 1 的节点)。
  • 第四次循环:i = 3res[3] 赋值为 cur 指向节点的值 1,cur 移动到 null,循环结束。

此时数组 res 中的元素为 [1, 2, 2, 1]

4. 使用双指针法比较数组对称位置的元素

  • 第一次比较:i = 0j = 3res[0] = 1res[3] = 1,两者相等,继续循环。
  • 第二次比较:i = 1j = 2res[1] = 2res[2] = 2,两者相等,继续循环。
  • 此时 i = 2j = 1,不满足 i < j 的条件,循环结束。

5. 返回结果

由于在比较过程中没有发现不相等的元素,所以判断该链表是回文链表,返回 true

3.143.重排链表

力扣题目链接(opens new window)

  • 数组模拟

把链表放进数组中,然后通过双指针法,一前一后,来遍历数组,构造链表。

  • 双向队列模拟

把链表放进双向队列,然后通过双向队列一前一后弹出数据,来构造新的链表。

  • 直接分割链表

将链表分割成两个链表,然后把第二个链表反转,之后在通过两个链表拼接成新的链表。

如图:

public class Reorder_List {
    public static class ListNode {//ListNode 是一个静态内部类,用于表示链表中的节点。
        int val;//存储节点的值。
        ListNode next;//指向下一个节点的引用。
        public ListNode(int i) {
            this.val = i;
        }
    }
    public void reorderList2(ListNode head) {
        Deque<ListNode> de = new LinkedList<>();//双端队列允许在队列的两端进行插入和删除操作
        ListNode cur = head.next;//指针 cur 并将其指向链表头节点的下一个节点,因为头节点 L0 不需要存入队列,后续会作为重排后链表的起始节点。
        while (cur != null){//while 循环遍历链表,只要 cur 不为 null,就表示还未遍历到链表末尾。
            de.offer(cur);//将当前节点 cur 加入到双端队列 de 的尾部。
            cur = cur.next;//将 cur 指针移动到下一个节点。
        }
        cur = head;//重新指向链表的头节点
        int count = 0;//用于记录当前选取节点的次数
        while (!de.isEmpty()){//只要双端队列 de 不为空,说明还有节点需要处理,继续循环。
            if (count % 2 == 0){//当 count 为偶数时,从双端队列 de 的尾部取出一个节点,将 cur 的 next 指针指向该节点,pollLast() 方法会移除并返回队列的最后一个元素。
                cur.next = de.pollLast();
            }else {//当 count 为奇数时,从双端队列 de 的头部取出一个节点,将 cur 的 next 指针指向该节点,poll() 方法会移除并返回队列的第一个元素。
                cur.next = de.poll();
            }
            cur  = cur.next;//将 cur 指针移动到新连接的节点,以便进行下一次连接操作。
            count++;//count 加 1,记录选取节点的次数。
        }
        cur.next = null;//当双端队列 de 为空时,循环结束,此时链表重排基本完成。但最后一个节点的 next 指针可能仍然指向原链表中的某个节点,为了确保链表正确结束,将 cur 的 next 指针置为 null。
    }
}

时间复杂度

1. 构建双端队列: 方法首先遍历链表,将所有节点(除了头节点)加入到双端队列中。这一遍历的时间复杂度为 O(n),其中n是链表中的节点数。

 2. 重排链表: 接下来,方法进入一个循环,直到双端队列为空。在每次迭代中,它从队列的头部或尾部取出一个节点,并将其链接到新的链表中。由于每个节点只处理一次,这部分的时间复杂度也是 O(n)。 综合以上两个步骤,整体的时间复杂度为:O(n) + O(n) = O(n) 

空间复杂度

1. 双端队列的存储: 方法使用一个双端队列来存储所有节点(除了头节点)。在最坏的情况下,这意味着需要存储 n-1个节点,因此空间复杂度为 O(n)。

 2. 其他变量: 方法使用了一些额外的变量(如 curcount ),这些变量占用的空间是常数级别的 O(1)。 因此,总的空间复杂度主要由双端队列的存储决定:O(n)

时间复杂度:O(n)

空间复杂度:O(n)

1 -> 2 -> 3 -> 4 -> 5

1. 初始化双端队列并存储节点

  • de 是一个双端队列,用于存储链表中除头节点外的所有节点。
  • cur 初始化为 head.next,即指向节点 2
  • 开始遍历链表:
    • 第一次循环:cur 指向节点 2,将节点 2 加入双端队列 de 的尾部,然后 cur 移动到节点 3
    • 第二次循环:cur 指向节点 3,将节点 3 加入双端队列 de 的尾部,然后 cur 移动到节点 4
    • 第三次循环:cur 指向节点 4,将节点 4 加入双端队列 de 的尾部,然后 cur 移动到节点 5
    • 第四次循环:cur 指向节点 5,将节点 5 加入双端队列 de 的尾部,然后 cur 移动到 null,循环结束。

此时,双端队列 de 中的元素依次为 [2, 3, 4, 5]

2. 重新定位指针并初始化计数器

  • cur 重新指向链表的头节点,即节点 1
  • count 初始化为 0,用于记录当前选取节点的次数。

3. 按规则重排链表

  • 第一次循环(count = 0,偶数)
    • cur 指向节点 1,从双端队列 de 的尾部取出节点 5,将 cur(节点 1)的 next 指针指向节点 5
    • cur 移动到节点 5count 加 1 变为 1。此时双端队列 de 中的元素为 [2, 3, 4]
  • 第二次循环(count = 1,奇数)
    • cur 指向节点 5,从双端队列 de 的头部取出节点 2,将 cur(节点 5)的 next 指针指向节点 2
    • cur 移动到节点 2count 加 1 变为 2。此时双端队列 de 中的元素为 [3, 4]
  • 第三次循环(count = 2,偶数)
    • cur 指向节点 2,从双端队列 de 的尾部取出节点 4,将 cur(节点 2)的 next 指针指向节点 4
    • cur 移动到节点 4count 加 1 变为 3。此时双端队列 de 中的元素为 [3]
  • 第四次循环(count = 3,奇数)
    • cur 指向节点 4,从双端队列 de 的头部取出节点 3,将 cur(节点 4)的 next 指针指向节点 3
    • cur 移动到节点 3count 加 1 变为 4。此时双端队列 de 为空。

4. 处理链表结尾

此时,双端队列 de 为空,循环结束。将 cur(节点 3)的 next 指针置为 null,确保链表正确结束。

最终重排后的链表为 1 -> 5 -> 2 -> 4 -> 3

4.141. 环形链表

力扣题目链接(opens new window)

给定一个链表,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false 。

思路

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

为什么fast 走两个节点,slow走一个节点,有环的话,一定会在环内相遇呢,而不是永远的错开呢?

首先第一点: fast指针一定先进入环中,如果fast 指针和slow指针相遇的话,一定是在环中相遇。

为什么fast指针和slow指针一定会相遇呢?

可以画一个环,然后让 fast指针在任意一个节点开始追赶slow指针。

会发现最终都是这种情况, 如下图:

fast和slow各自再走一步, fast和slow就相遇了

这是因为fast是走两步,slow是走一步,其实相对于slow来说,fast是一个节点一个节点的靠近slow的,所以fast一定可以和slow重合。

动画如下:

141.环形链表

 

public class Circular_Linked_List {
    public static class ListNode {//ListNode 是一个静态内部类,用于表示链表中的节点。
        int val;//存储节点的值。
        ListNode next;//指向下一个节点的引用。
        public ListNode(int i) {
            this.val = i;
        }
    }
    public boolean hasCycle(ListNode head) {
        ListNode fast = head;//fast 和 slow 指针都初始化为指向链表的头节点 head。fast 指针后续会以每次移动两步的速度遍历链表,slow 指针则以每次移动一步的速度遍历链表。
        ListNode slow = head;
        // 空链表、单节点链表一定不会有环
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) { // 快慢指针相遇,表明有环
                return true;
            }
        }
        return false; // 正常走到链表末尾,表明没有环
    }
}

时间复杂度

在最坏的情况下,快慢指针会遍历整个链表。快指针每次移动两步,慢指针每次移动一步,因此最多会遍历 n 个节点,时间复杂度为 O(n)。

空间复杂度

只使用了常量级别的额外空间(即两个指针 fastslow ),不随输入规模的变化而变化,因此空间复杂度为 O(1)。

总结而言,这段代码的时间复杂度为 O(n),空间复杂度为 O(1)。

无环链表 1 -> 2 -> 3 -> 4

初始化:fast 和 slow 指针都指向节点 1。
第一次循环:
fast 指针移动两步,指向节点 3(1 -> 2 -> 3)。
slow 指针移动一步,指向节点 2(1 -> 2)。
此时 fast 不等于 slow,继续循环。
第二次循环:
fast 指针尝试再移动两步,但由于节点 4 的 next 为 null,fast.next.next 会导致 fast 变为 null,不满足 while 循环条件(fast != null && fast.next != null),循环结束。
返回结果:由于循环正常结束,说明链表没有环,返回 false。
有环链表 1 -> 2 -> 3 -> 4

初始化:fast 和 slow 指针都指向节点 1。
第一次循环:
fast 指针移动两步,指向节点 3(1 -> 2 -> 3)。
slow 指针移动一步,指向节点 2(1 -> 2)。
此时 fast 不等于 slow,继续循环。
第二次循环:
fast 指针移动两步,由于存在环,节点 4 的 next 指向节点 2,所以 fast 指向节点 2(3 -> 4 -> 2)。
slow 指针移动一步,指向节点 3(2 -> 3)。
此时 fast 不等于 slow,继续循环。
第三次循环:
fast 指针移动两步,指向节点 4(2 -> 3 -> 4)。
slow 指针移动一步,指向节点 4(3 -> 4)。
此时 fast 等于 slow,满足 if 条件,返回 true,表示链表有环。

5.面试题 02.07. 链表相交

同:160.链表相交

力扣题目链接(opens new window)

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

示例 1:

示例 2:

示例 3:

思路

求两个链表交点节点的指针。 交点不是数值相等,而是指针相等。

为了方便举例,假设节点元素数值相等,则节点指针相等。

看如下两个链表,目前curA指向链表A的头结点,curB指向链表B的头结点:

面试题02.07.链表相交_1

 

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

面试题02.07.链表相交_2

此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到交点。否则循环退出返回空指针。

public class Intersection_of_Two_Linked_Lists {
    public static class ListNode {//ListNode 是一个静态内部类,用于表示链表中的节点。
        int val;//存储节点的值。
        ListNode next;//指向下一个节点的引用。

        public ListNode(int i) {
            this.val = i;
        }
    }
  public ListNode getIntersectionNode2(ListNode headA, ListNode headB) {
        ListNode p1 = headA, p2 = headB;//p1 初始化为指向链表 headA 的头节点,p2 初始化为指向链表 headB 的头节点。
        while (p1 != p2) {//只要 p1 和 p2 不指向同一个节点,就继续循环。当 p1 和 p2 相等时,有两种情况:一是找到了相交节点,二是两个链表不相交,此时 p1 和 p2 都为 null。
            if (p1 == null) {//如果 p1 为 null,说明 p1 已经遍历完链表 headA,将 p1 重新指向链表 headB 的头节点,开始遍历链表 headB。
                p1 = headB;
            } else {//否则,将 p1 移动到下一个节点,
                p1 = p1.next;
            }
            if (p2 == null) {//如果 p2 为 null,说明 p2 已经遍历完链表 headB,将 p2 重新指向链表 headA 的头节点,开始遍历链表 headA。
                p2 = headA;
            } else {//否则,将 p2 移动到下一个节点
                p2 = p2.next;
            }
        }
        return p1;//当 while 循环结束时,p1 和 p2 相等。如果两个链表相交,p1 指向的就是相交节点;如果两个链表不相交,p1 和 p2 最终都会遍历完两个链表,同时指向 null,所以返回 p1
    }
}

时间复杂度

在最坏的情况下,指针 p1p2 会遍历两个链表的所有节点。这里 n 是链表 A 的长度, m 是链表 B 的长度。因此,时间复杂度为 O(n + m)。

空间复杂度

该算法只使用了固定数量的额外空间,即两个指针 p1p2 ,不随输入规模的变化而变化。因此,空间复杂度为 O(1)。

时间复杂度:O(n + m)

空间复杂度:O(1)

示例 1:两个链表相交
假设存在两个相交链表:
链表 headA:1 -> 2 -> 3 -> 6 -> 7
链表 headB:4 -> 5 -> 6 -> 7
两个链表在节点 6 处相交。

  1. 初始化

    • p1 指向链表 headA 的头节点 1

    • p2 指向链表 headB 的头节点 4

  2. 第一次遍历

    • p1 依次经过节点 12367,然后 p1 变为 null,根据逻辑将 p1 重新指向链表 headB 的头节点 4

    • p2 依次经过节点 4567,然后 p2 变为 null,根据逻辑将 p2 重新指向链表 headA 的头节点 1

  3. 第二次遍历

    • p1 从节点 4 开始,经过节点 5,到达节点 6

    • p2 从节点 1 开始,经过节点 23,到达节点 6。此时 p1 和 p2 相等,while 循环结束。

  4. 返回结果:返回 p1,即节点 6,这就是两个链表的相交节点。

示例 2:两个链表不相交

假设存在两个不相交链表:

  • 链表 headA1 -> 2 -> 3
  • 链表 headB4 -> 5

初始化:
p1 指向链表 headA 的头节点 1。
p2 指向链表 headB 的头节点 4。
第一次遍历:
p1 依次经过节点 1、2、3,然后 p1 变为 null,根据逻辑将 p1 重新指向链表 headB 的头节点 4。
p2 依次经过节点 4、5,然后 p2 变为 null,根据逻辑将 p2 重新指向链表 headA 的头节点 1。
第二次遍历:
p1 从节点 4 开始,经过节点 5,然后 p1 又变为 null。
p2 从节点 1 开始,经过节点 2、3,然后 p2 也变为 null。此时 p1 和 p2 相等且都为 null,while 循环结束。
返回结果:返回 p1,即 null,表示两个链表不相交。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/965879.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Nginx 中启用 Gzip 压缩以优化网页加载速度

&#x1f3e1;作者主页&#xff1a;点击&#xff01; Nginx-从零开始的服务器之旅专栏&#xff1a;点击&#xff01; &#x1f427;Linux高级管理防护和群集专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2025年2月7日17点14分 目录 1. 配置网页压缩 目的 …

《云夹:高效便捷的书签管理利器》

在信息爆炸的时代&#xff0c;我们每天都会浏览大量的网页&#xff0c;遇到许多有价值的内容。如何高效地管理这些网页书签&#xff0c;以便随时快速访问&#xff0c;成为了一个重要的问题。云夹作为一款出色的书签管理工具&#xff0c;为我们提供了完美的解决方案。 强大的功能…

学习数据结构(6)链表OJ

1.移除链表元素 解法一&#xff1a;&#xff08;我的做法&#xff09;在遍历的同时移除&#xff0c;代码写法比较复杂 解法二&#xff1a;创建新的链表&#xff0c;遍历原链表&#xff0c;将非val的节点尾插到新链表&#xff0c;注意&#xff0c;如果原链表结尾是val节点需要将…

MongoDB开发规范

分级名称定义P0核心系统需7*24不间断运行&#xff0c;一旦发生不可用&#xff0c;会直接影响核心业务的连续性&#xff0c;或影响公司名誉、品牌、集团战略、营销计划等&#xff0c;可能会造成P0-P2级事故发生。P1次核心系统这些系统降级或不可用&#xff0c;会间接影响用户使用…

设计模式.

设计模式 一、介绍二、六大原则1、单一职责原则&#xff08;Single Responsibility Principle, SRP&#xff09;2、开闭原则&#xff08;Open-Closed Principle, OCP&#xff09;3、里氏替换原则&#xff08;Liskov Substitution Principle, LSP&#xff09;4、接口隔离原则&am…

STM32的HAL库开发-通用定时器输入捕获实验

一、通用定时器输入捕获部分框图介绍 1、捕获/比较通道的输入部分(通道1) 首先设置 TIM_CCMR1的CC1S[1:0]位&#xff0c;设置成01&#xff0c;那么IC1来自于TI1&#xff0c;也就是说连接到TI1FP1上边。设置成10&#xff0c;那个IC1来自于TI2&#xff0c;连接到TI2FP1上。设置成…

JavaScript 复习

文章目录 语法前置语法组成引入位置内部引入外部引入 基础语法输出变量变量声明规则变量赋值变量的作用范围 数据类型强制类型转换强转为 Number强转为 Boolean强转为 String强转为 整数 | 浮点数 运算符流程控制隐式转换函数常用内置对象String 对象Array 数组对象Math 数学对…

【C】链表算法题5 -- 相交链表

leetcode链接https://leetcode.cn/problems/intersection-of-two-linked-lists/description/https://leetcode.cn/problems/intersection-of-two-linked-lists/description/ 题目描述 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节…

蓝桥杯准备 【入门3】循环结构

素数小算法&#xff08;埃氏筛&&欧拉筛&#xff09; 以下四段代码都是求20以内的所有素数 1.0版求素数 #include<iostream> using namespace std;int main() {int n 20;for(int i2;i<n;i){int j0;for(j2;j<i;j)//遍历i{if(i%j0){break;}}if(ij){cout&l…

寒假2.6--SQL注入之布尔盲注

知识点 原理&#xff1a;通过发送不同的SQL查询来观察应用程序的响应&#xff0c;进而判断查询的真假&#xff0c;并逐步推断出有用的信息 适用情况&#xff1a;一个界面存在注入&#xff0c;但是没有显示位&#xff0c;没有SQL语句执行错误信息&#xff0c;通常用于在无法直接…

Servlet笔记(下)

HttpServletRequest对象相关API 获取请求行信息相关(方式,请求的url,协议及版本) | API | 功能解释 | | ----------------------------- | ------------------------------ | | StringBuffer getRequestURL(); | 获取客户端…

QQ自动发送消息

QQ自动发送消息 python包导入 import time import pandas as pd import pyautogui import pyperclip图像识别函数封装 本程序使用pyautogui模块控制鼠标和键盘来实现QQ自动发送消息&#xff0c;因此必须得到需要点击位置的坐标&#xff08;当然也可以在程序中将位置写死&…

5.1计算机网络基本知识

5.1.1计算机网络概述 目前&#xff0c;三网融合(电信网络、有线电视网络和计算机网络)和宽带化是网络技术的发展的大方向&#xff0c;其应用广泛&#xff0c;遍及智能交通、环境保护、政府工作、公共安全、平安家居等多个领域&#xff0c;其中发展最快的并起到核心作用的则是计…

51单片机之冯·诺依曼结构

一、概述 8051系列单片机将作为控制应用最基本的内容集成在一个硅片上&#xff0c;其内部结构如图4-1所示。作为单一芯片的计算机&#xff0c;它的内部结构与一台计算机的主机非常相似。其中微处理器相当于计算机中的CPU&#xff0c;由运算器和控制器两个部分构成&#xff1b;…

13.PPT:诺贝尔奖【28】

目录 NO1234 NO567 NO8/9/10 NO11/12 NO1234 设计→变体→字体→自定义字体 SmartArt超链接新增加节 NO567 版式删除图片中的白色背景&#xff1a;选中图片→格式→删除背景→拖拉整个图片→保留更改插入→图表→散点图 &#xff1a;图表图例、网格线、坐标轴和图表标题…

RabbitMQ 从入门到精通:从工作模式到集群部署实战(一)

#作者&#xff1a;闫乾苓 文章目录 RabbitMQ简介RabbitMQ与VMware的关系架构工作流程RabbitMQ 队列工作模式及适用场景简单队列模式&#xff08;Simple Queue&#xff09;工作队列模式&#xff08;Work Queue&#xff09;发布/订阅模式&#xff08;Publish/Subscribe&#xff…

DFX(Design for eXcellence)架构设计全解析:理论、实战、案例与面试指南*

一、什么是 DFX &#xff1f;为什么重要&#xff1f; DFX&#xff08;Design for eXcellence&#xff0c;卓越设计&#xff09;是一种面向产品全生命周期的设计理念&#xff0c;旨在确保产品在设计阶段就具备**良好的制造性&#xff08;DFM&#xff09;、可测试性&#xff08;…

【Elasticsearch】diversified sampler

作用就是聚合前的采样&#xff0c;主要是采样 它就是用来采样的&#xff0c;采完样后在进行聚合操作 random_sampler和diversified_sampler是 Elasticsearch 中用于聚合查询的两种采样方法&#xff0c;它们的主要区别如下&#xff1a; 采样方式 • random_sampler&#xff1a…

2月7号.

二叉树是一种特殊的树形数据结构&#xff0c;具有以下特点&#xff1a; 基本定义 节点的度&#xff1a;二叉树中每个节点最多有两个子节点&#xff0c;分别称为左子节点和右子节点。 子树的顺序性&#xff1a;二叉树的子树有左右之分&#xff0c;且顺序不能颠倒。 递归定义&…

openpnp2.2 - 环境搭建 - 编译 + 调试 + 打包

文章目录 openpnp2.2 - 环境搭建 - 编译 调试 打包概述笔记前置任务克隆代码库切到最新的tag清理干净编译工程关掉旧工程打开已经克隆好的openpnp2.2工程将IDEA的SDK配置为openjdk23 切换中英文UI设置JAVA编译器 构建工程跑测试用例单步调试下断点导出工程的JAR包安装install…