leetcode
leetcode 2651 ~ 2700
循环有序列表的插入

循环有序列表的插入

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 44 ms, 内存: 15.6 MB


/*
 * 问题思路:
 * 1. 将链表转换为ArrayList。
 * 2. 使用Stream API找到合适的插入点。
 * 3. 插入新值并将ArrayList转回循环链表。
 */
import java.util.ArrayList;
import java.util.stream.IntStream;

public class SolutionStream {
    static class Node {
        public int val;
        public Node next;
        public Node() {}
        public Node(int _val) {
            val = _val;
        }
        public Node(int _val, Node _next) {
            val = _val;
            next = _next;
        }
    }

    public Node insert(Node head, int insertVal) {
        if (head == null) {
            Node newNode = new Node(insertVal);
            newNode.next = newNode;
            return newNode;
        }

        ArrayList<Node> nodes = new ArrayList<>();
        Node current = head;
        do {
            nodes.add(current);
            current = current.next;
        } while (current != head);

        int size = nodes.size();
        int insertIndex = IntStream.range(0, size)
            .filter(i -> (nodes.get(i).val <= insertVal && insertVal <= nodes.get((i + 1) % size).val)
                    || (nodes.get(i).val > nodes.get((i + 1) % size).val &&
                        (insertVal >= nodes.get(i).val || insertVal <= nodes.get((i + 1) % size).val)))
            .findFirst()
            .orElse(size - 1);

        Node newNode = new Node(insertVal, nodes.get((insertIndex + 1) % size));
        nodes.get(insertIndex).next = newNode;
        return head;
    }
}

解释

方法:

本题解的核心思路是在一个循环单调非递减列表中插入一个新元素,同时保持列表的循环单调非递减特性。首先,如果列表为空(head为None),则创建一个新节点并使其成为循环列表。如果列表中只有一个节点,直接在此节点后插入新节点并更新指针。对于多节点的情况,遍历列表寻找插入位置:1. 直接找到两个相邻节点,使得前一个节点的值小于等于插入值且插入值小于等于后一个节点的值;2. 如果遍历一圈后未找到这样的相邻节点,说明插入值应当插入在最大值节点的后面。这种情况下,需要维护一个最大值节点的引用,在遍历过程中更新。最后,将新节点插入到合适的位置。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在循环列表中,如果`insertVal`的值比所有节点的值都要大或都要小,你是如何处理这种情况的?
在这种情况下,`insertVal`无法直接找到一个符合条件的插入位置(即不存在一个区间使得前一个节点的值小于等于`insertVal`且`insertVal`小于等于后一个节点的值)。因此,我们需要找到列表中的最大节点,然后将新节点插入到这个最大节点的后面。这样做能保证列表的循环单调非递减的特性不被破坏。在遍历过程中,我会维护一个引用指向当前遍历过的最大值节点,一旦完成一圈的遍历且没有找到合适的插入点,就将新节点插入到这个最大节点的后面。
🦆
为什么在找到合适的插入位置后要立即返回头节点,这样做有什么特别的意义吗?
在找到合适的插入位置后立即返回头节点是为了保持链表的引用不变,这对于调用者来说是重要的。在循环链表中,头节点通常作为整个链表的访问入口,若改变头节点的位置可能会导致引用混乱或不一致,特别是在多次插入操作时。此外,返回头节点后,调用者可以继续使用原有的头节点引用进行其他操作,如遍历、查找等,这提高了代码的可用性和一致性。
🦆
你提到了维护一个`最大值节点的引用`,这是出于什么考虑?是否有可能存在多个最大值,如果是,你是如何选择其中一个作为插入点的?
维护`最大值节点的引用`是为了处理插入值不处于任何两个相邻节点值之间的情形,特别是当插入值大于所有现有节点的值或小于所有现有节点的值的情况。如果存在多个具有相同最大值的节点,我的实现选择了在遍历过程中遇到的第一个最大值节点作为插入点。这是因为在单次完整的遍历中,第一个遇到的最大值节点之后的位置是维持循环单调非递减顺序的合适位置。这种方法简化了插入逻辑,同时保持了列表的结构和顺序的正确性。

相关问题