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
解题思路
这是一个流处理的设计题,核心思路是维护一个有序的数据结构来存储键值对,并跟踪下一个应该输出的位置。
解题思路:
数据结构设计:使用一个数组来存储值,数组下标对应 ID(注意 ID 从 1 开始,所以需要减 1)。同时维护一个指针
ptr,指向下一个期待的 ID 位置。插入操作:
- 将值存储到对应的数组位置
- 从当前指针位置开始,检查是否有连续的已插入值
- 如果有连续的值,将它们收集到结果列表中,并更新指针
关键观察:只有当我们插入的值恰好填补了从当前指针开始的连续序列时,才能返回这些值。例如,如果指针指向位置 1,我们插入了 ID 为 3 的值,那么无法返回任何值,因为位置 1 和 2 还是空的。
算法流程:
- 初始化时创建大小为 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) |
| insert | O(k) | O(1) |
其中:
- n 是流的容量
- k 是单次 insert 操作返回的元素个数
- 总的时间复杂度:所有 insert 操作的时间复杂度总和为 O(n),因为每个位置最多被访问一次
相关题目
- . Longest Uploaded Prefix (Medium)