Easy

题目描述

有一个包含 n 个 (idKey, value) 对的流,按任意顺序到达,其中 idKey 是 1 到 n 之间的整数,value 是字符串。没有两对具有相同的 id。

设计一个流,通过在每次插入后返回值的块(列表)来按 ID 的递增顺序返回值。所有块的串联应该产生排序值的列表。

实现 OrderedStream 类:

  • OrderedStream(int n) 构造一个能接收 n 个值的流。
  • String[] insert(int idKey, String value) 将 (idKey, value) 对插入到流中,然后返回当前插入值中按顺序出现的最大可能块。

示例:

输入
["OrderedStream", "insert", "insert", "insert", "insert", "insert"]
[[5], [3, "ccccc"], [1, "aaaaa"], [2, "bbbbb"], [5, "eeeee"], [4, "ddddd"]]
输出
[null, [], ["aaaaa"], ["bbbbb", "ccccc"], [], ["ddddd", "eeeee"]]

解释
OrderedStream os = new OrderedStream(5);
os.insert(3, "ccccc"); // 插入 (3, "ccccc"),返回 []。
os.insert(1, "aaaaa"); // 插入 (1, "aaaaa"),返回 ["aaaaa"]。
os.insert(2, "bbbbb"); // 插入 (2, "bbbbb"),返回 ["bbbbb", "ccccc"]。
os.insert(5, "eeeee"); // 插入 (5, "eeeee"),返回 []。
os.insert(4, "ddddd"); // 插入 (4, "ddddd"),返回 ["ddddd", "eeeee"]。

提示:

  • 1 <= n <= 1000
  • 1 <= id <= n
  • value.length == 5
  • value 仅由小写字母组成
  • 每次调用 insert 都有唯一的 id
  • 恰好会调用 n 次 insert

解题思路

这是一个流处理的设计题,核心思路是维护一个有序的数据结构来存储键值对,并跟踪下一个应该输出的位置。

解题思路:

  1. 数据结构设计:使用一个数组来存储值,数组下标对应 ID(注意 ID 从 1 开始,所以需要减 1)。同时维护一个指针 ptr,指向下一个期待的 ID 位置。

  2. 插入操作

    • 将值存储到对应的数组位置
    • 从当前指针位置开始,检查是否有连续的已插入值
    • 如果有连续的值,将它们收集到结果列表中,并更新指针
  3. 关键观察:只有当我们插入的值恰好填补了从当前指针开始的连续序列时,才能返回这些值。例如,如果指针指向位置 1,我们插入了 ID 为 3 的值,那么无法返回任何值,因为位置 1 和 2 还是空的。

  4. 算法流程

    • 初始化时创建大小为 n 的数组,指针指向位置 1
    • 插入时,先存储值到对应位置
    • 然后从当前指针位置开始向后扫描,收集所有连续的非空值
    • 更新指针到下一个空位置

这种方法保证了每次返回的都是当前能够形成的最长连续序列,时间复杂度为 O(k),其中 k 是返回的元素个数。

代码实现

class OrderedStream {
private:
    vector<string> stream;
    int ptr;
    
public:
    OrderedStream(int n) {
        stream.resize(n + 1);  // 1-indexed
        ptr = 1;
    }
    
    vector<string> insert(int idKey, string value) {
        stream[idKey] = value;
        vector<string> result;
        
        while (ptr < stream.size() && !stream[ptr].empty()) {
            result.push_back(stream[ptr]);
            ptr++;
        }
        
        return result;
    }
};
class OrderedStream:

    def __init__(self, n: int):
        self.stream = [""] * (n + 1)  # 1-indexed
        self.ptr = 1

    def insert(self, idKey: int, value: str) -> List[str]:
        self.stream[idKey] = value
        result = []
        
        while self.ptr < len(self.stream) and self.stream[self.ptr]:
            result.append(self.stream[self.ptr])
            self.ptr += 1
            
        return result
public class OrderedStream {
    private string[] stream;
    private int ptr;

    public OrderedStream(int n) {
        stream = new string[n + 1];  // 1-indexed
        ptr = 1;
    }
    
    public IList<string> Insert(int idKey, string value) {
        stream[idKey] = value;
        IList<string> result = new List<string>();
        
        while (ptr < stream.Length && !string.IsNullOrEmpty(stream[ptr])) {
            result.Add(stream[ptr]);
            ptr++;
        }
        
        return result;
    }
}
var OrderedStream = function(n) {
    this.stream = new Array(n + 1).fill("");  // 1-indexed
    this.ptr = 1;
};

OrderedStream.prototype.insert = function(idKey, value) {
    this.stream[idKey] = value;
    const result = [];
    
    while (this.ptr < this.stream.length && this.stream[this.ptr]) {
        result.push(this.stream[this.ptr]);
        this.ptr++;
    }
    
    return result;
};

复杂度分析

操作时间复杂度空间复杂度
构造函数O(n)O(n)
insertO(k)O(1)

其中:

  • n 是流的容量
  • k 是单次 insert 操作返回的元素个数
  • 总的时间复杂度:所有 insert 操作的时间复杂度总和为 O(n),因为每个位置最多被访问一次

相关题目