leetcode
leetcode 2401 ~ 2450
在链表中插入最大公约数

在链表中插入最大公约数

难度:

标签:

题目描述

Given the head of a linked list head, in which each node contains an integer value.

Between every pair of adjacent nodes, insert a new node with a value equal to the greatest common divisor of them.

Return the linked list after insertion.

The greatest common divisor of two numbers is the largest positive integer that evenly divides both numbers.

 

Example 1:

Input: head = [18,6,10,3]
Output: [18,6,6,2,10,1,3]
Explanation: The 1st diagram denotes the initial linked list and the 2nd diagram denotes the linked list after inserting the new nodes (nodes in blue are the inserted nodes).
- We insert the greatest common divisor of 18 and 6 = 6 between the 1st and the 2nd nodes.
- We insert the greatest common divisor of 6 and 10 = 2 between the 2nd and the 3rd nodes.
- We insert the greatest common divisor of 10 and 3 = 1 between the 3rd and the 4th nodes.
There are no more adjacent nodes, so we return the linked list.

Example 2:

Input: head = [7]
Output: [7]
Explanation: The 1st diagram denotes the initial linked list and the 2nd diagram denotes the linked list after inserting the new nodes.
There are no pairs of adjacent nodes, so we return the initial linked list.

 

Constraints:

  • The number of nodes in the list is in the range [1, 5000].
  • 1 <= Node.val <= 1000

代码结果

运行时间: 40 ms, 内存: 19.3 MB


/*
 * 思路:
 * 1. 使用Stream生成链表的节点值列表。
 * 2. 计算每两个相邻元素的GCD并将其插入到新列表中。
 * 3. 创建新的链表节点,重构链表。
 */

import java.util.*;
import java.util.stream.*;

class ListNode {
    int val;
    ListNode next;
    ListNode(int val) { this.val = val; }
}

public class Solution {
    public ListNode insertGreatestCommonDivisors(ListNode head) {
        if (head == null || head.next == null) return head;

        List<Integer> values = new ArrayList<>();
        for (ListNode curr = head; curr != null; curr = curr.next) {
            values.add(curr.val);
        }

        List<Integer> result = IntStream.range(0, values.size() - 1)
            .flatMap(i -> IntStream.of(values.get(i), gcd(values.get(i), values.get(i + 1))))
            .boxed()
            .collect(Collectors.toList());
        result.add(values.get(values.size() - 1));

        ListNode newHead = new ListNode(result.get(0));
        ListNode current = newHead;
        for (int i = 1; i < result.size(); i++) {
            current.next = new ListNode(result.get(i));
            current = current.next;
        }

        return newHead;
    }

    private int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }
}

解释

方法:

此题解的思路是遍历给定的链表,并在每两个相邻结点之间插入一个新结点。新结点的值是这两个相邻结点的最大公约数(GCD)。为了实现这一点,算法使用Python标凑库中的math.gcd函数来计算两个数的最大公约数。遍历过程中,算法不断更新当前节点,将其指向未处理的下一个节点,直到所有相邻节点都处理完毕。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在处理链表时,如何确保在插入新节点后,原有节点的连接不会丢失或产生环状结构?
在处理链表时,确保原有节点的连接不丢失或不产生环状结构的关键是正确管理节点的 `next` 指针。在插入新节点时,首先应保存当前节点的后继节点(`post = cur.next`),然后将当前节点的 `next` 指向新创建的节点。新节点的 `next` 指针再指向保存的后继节点(`cur.next.next = post`)。这种方法可以保证在插入过程中不会改变原有节点的顺序,也不会创建任何新的循环引用。
🦆
在`ListNode`类中,是否需要考虑异常处理,比如链表只有一个节点或链表为空的情况?
是的,在`ListNode`类中应考虑异常处理。特别是当链表为空(`head` 是 `None`)时,应直接返回 `None`,因为没有节点可以处理。当链表只有一个节点时,由于没有后继节点,因此无需插入任何新节点,可以直接返回原始链表。这种情况下的处理可以防止运行时错误,并确保函数的鲁棒性。
🦆
在插入新节点的过程中,如何处理链表的末尾节点,因为它没有后继节点与之计算GCD?
在链表的末尾节点,由于没有后继节点,因此无法计算GCD。在这种情况下,最简单的处理方式是不进行任何操作。遍历链表时,当当前节点 (`cur`) 的 `next` 指向 `None`(即没有后继节点)时,循环将终止。因此,末尾节点不会有新的节点插入。
🦆
在计算GCD并创建新节点后,代码直接将新节点链接到后继节点,这样的实现方式是否会影响链表的遍历效率?
在计算GCD并创建新节点后,直接将新节点链接到后继节点,这种实现方式本身不会显著影响链表的遍历效率。然而,值得注意的是,由于在原始链表中每两个节点之间插入了一个新节点,因此链表的长度增加了近一倍。这意味着对增加后的链表进行遍历所需的时间将比原始链表长。但这与链表的数据结构性质相符,因为链表的遍历时间通常与节点数量成正比。

相关问题