Talentd
FleetCode
Make and follow sheets.Sign in

Design an Ordered Stream solution and explanation

EasyArrayData StreamDesignHash Table6 min read82.6% acceptanceUpdated 9 Apr 2026
1656. Design an Ordered Stream (Leetcode Easy)Programming Live with Larry · 5:17 · 7K viewsWatch on YouTube
3 more videos on this problem
  1. 1656. Design an Ordered Stream (Leetcode Easy)Programming Live with Larry · 5:17 · 7K views
  2. Weekly Contest 215 | Problem 1656 , 1657 , 1658 | LEETCODEcode Explainer · 16:27 · 3K views
  3. LeetCode 1656 | Design an Ordered Stream | Design | JavaSleepy Cracker · 2:49 · 1K views
  4. 1656 Design an Ordered StreamLogN · 15:01 · 622 views

The problem

There is a stream of n (idKey, value) pairs arriving in an arbitrary order, where idKey is an integer between 1 and n and value is a string. No two pairs have the same id.

Design a stream that returns the values in increasing order of their IDs by returning a chunk (list) of values after each insertion. The concatenation of all the chunks should result in a list of the sorted values.

Implement the OrderedStream class:

  • OrderedStream(int n) Constructs the stream to take n values.
  • String[] insert(int idKey, String value) Inserts the pair (idKey, value) into the stream, then returns the largest possible chunk of currently inserted values that appear next in the order.

Example:

Input
["OrderedStream", "insert", "insert", "insert", "insert", "insert"]
[[5], [3, "ccccc"], [1, "aaaaa"], [2, "bbbbb"], [5, "eeeee"], [4, "ddddd"]]
Output
[null, [], ["aaaaa"], ["bbbbb", "ccccc"], [], ["ddddd", "eeeee"]]

Explanation
// Note that the values ordered by ID is ["aaaaa", "bbbbb", "ccccc", "ddddd", "eeeee"].
OrderedStream os = new OrderedStream(5);
os.insert(3, "ccccc"); // Inserts (3, "ccccc"), returns [].
os.insert(1, "aaaaa"); // Inserts (1, "aaaaa"), returns ["aaaaa"].
os.insert(2, "bbbbb"); // Inserts (2, "bbbbb"), returns ["bbbbb", "ccccc"].
os.insert(5, "eeeee"); // Inserts (5, "eeeee"), returns [].
os.insert(4, "ddddd"); // Inserts (4, "ddddd"), returns ["ddddd", "eeeee"].
// Concatentating all the chunks returned:
// [] + ["aaaaa"] + ["bbbbb", "ccccc"] + [] + ["ddddd", "eeeee"] = ["aaaaa", "bbbbb", "ccccc", "ddddd", "eeeee"]
// The resulting order is the same as the order above.

Constraints:

  • 1 <= n <= 1000
  • 1 <= id <= n
  • value.length == 5
  • value consists only of lowercase letters.
  • Each call to insert will have a unique id.
  • Exactly n calls will be made to insert.

Approach overview

Problem Overview: You design a data structure that stores (id, value) pairs arriving in arbitrary order. Each call to insert(idKey, value) stores the value and returns the longest ordered chunk of values starting from the current pointer. If the next expected id is missing, the stream returns an empty list.

Approach 1: Array-Based Stream with Pointer (O(1) amortized time, O(n) space)

This approach stores incoming values in a fixed array of size n + 1. A pointer ptr tracks the smallest id that has not been returned yet. When you call insert(idKey, value), place the value directly at stream[idKey]. If idKey equals the current pointer, iterate forward while consecutive positions are filled, collecting values and advancing the pointer. Each element is processed at most once, which gives O(1) amortized time per operation and O(n) total extra space. This design works well because ids are bounded and sequential, making array indexing faster than lookups in other structures. It’s the most common implementation when practicing array based design problems.

Approach 2: Map-Based Storage (O(log n) or O(1) average per insert, O(n) space)

Another option stores incoming values in a hash map keyed by id. Each insertion records map[idKey] = value. After inserting, repeatedly check whether the current pointer exists in the map. If it does, append the value to the output list and advance the pointer. Hash maps provide O(1) average lookup time, so each check is constant on average. The total runtime across all operations remains O(n) because each id is processed once. This approach works even if the ids are sparse or not strictly bounded by a small range, which makes it useful when implementing generic hash table or data stream systems.

The key insight behind both approaches is maintaining a moving pointer representing the next expected id in the ordered stream. Once a contiguous segment appears, you release it immediately and move the pointer forward. This prevents rescanning previously processed elements and keeps the implementation efficient.

Recommended for interviews: The array + pointer approach. It shows you understand how to exploit the bounded id range and maintain state efficiently. Interviewers typically expect this solution because it achieves O(1) amortized insertion with simple logic. Mentioning the map-based alternative demonstrates you understand the generalization when sequential indexing is not guaranteed.

Approach 1: Array-Based Approach

This approach maintains an array of size n to store the values with their respective idKey indices. We also keep track of the current pointer that indicates the next position of expected insertion, starting at 1. When an element is inserted, we store it in the appropriate index. Then, we traverse from the current pointer and extract all consecutive non-null values as a chunk, updating the pointer position accordingly.

class OrderedStream:
    def __init__(self, n: int):
        self.stream = [None] * n
        self.ptr = 0

    def insert(self, idKey: int, value: str) -> list:
        self.stream[idKey - 1] = value
        chunk = []
        while self.ptr < len(self.stream) and self.stream[self.ptr] is not None:
            chunk.append(self.stream[self.ptr])
            self.ptr += 1
        return chunk
import java.util.*;

class OrderedStream {
    private String[] stream;
    private int ptr;
    
    public OrderedStream(int n) {
        stream = new String[n];
        ptr = 0;
    }
    
    public List<String> insert(int idKey, String value) {
        stream[idKey - 1] = value;
        List<String> chunk = new ArrayList<>();
        while (ptr < stream.length && stream[ptr] != null) {
            chunk.add(stream[ptr]);
            ptr++;
        }
        return chunk;
    }
}
#include <vector>
#include <string>

class OrderedStream {

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

private:
    std::vector<std::string> stream;
    int ptr;
};
class OrderedStream {
    constructor(n) {
        this.stream = new Array(n);
        this.ptr = 0;
    }

    insert(idKey, value) {
        this.stream[idKey - 1] = value;
        let chunk = [];
        while (this.ptr < this.stream.length && this.stream[this.ptr] !== undefined) {
            chunk.push(this.stream[this.ptr]);
            this.ptr++;
        }
        return chunk;
    }
}
#include <stdlib.h>
#include <string.h>

typedef struct {
    char **stream;
    int n;
    int ptr;
} OrderedStream;

OrderedStream* orderedStreamCreate(int n) {
    OrderedStream* obj = (OrderedStream*) malloc(sizeof(OrderedStream));
    obj->stream = (char**) calloc(n, sizeof(char*));
    obj->n = n;
    obj->ptr = 0;
    return obj;
}

char **orderedStreamInsert(OrderedStream* obj, int idKey, char *value, int* retSize) {
    obj->stream[idKey - 1] = strdup(value);
    int start = obj->ptr;
    while (start < obj->n && obj->stream[start] != NULL) {
        start++;
    }
    *retSize = start - obj->ptr;
    char **chunk = (char**) malloc((*retSize) * sizeof(char*));
    for (int i = 0; i < *retSize; i++) {
        chunk[i] = obj->stream[obj->ptr + i];
    }
    obj->ptr = start;
    return chunk;
}

void orderedStreamFree(OrderedStream* obj) {
    for (int i = 0; i < obj->n; i++) {
        if (obj->stream[i]) {
            free(obj->stream[i]);
        }
    }
    free(obj->stream);
    free(obj);
}
using System;
using System.Collections.Generic;

public class OrderedStream {
    private string[] stream;
    private int ptr;

    public OrderedStream(int n) {
        stream = new string[n];
        ptr = 0;
    }

    public IList<string> Insert(int idKey, string value) {
        stream[idKey - 1] = value;
        List<string> chunk = new List<string>();
        while (ptr < stream.Length && stream[ptr] != null) {
            chunk.Add(stream[ptr]);
            ptr++;
        }
        return chunk;
    }
}

In Python, we use a list to simulate the stream. The insert method fills the list at the correct position, gathers sequential filled values from the pointer position into a list, which gets returned.

Complexity

Time Complexity: O(n) in worst case per insertion. Space Complexity: O(n) for the array storage.

Try this approach in the editor

Approach 2: Map-Based Approach

Alternatively, this approach employs a map (or dictionary) to store the values indexed by their idKey. We maintain a pointer for the current position. Each insertion updates the map, and values are extracted using the pointer to gather all consecutive keys that have values in the map.

class OrderedStream:
    def __init__(self, n: int):
        self.stream = {}
        self.ptr = 1
        self.n = n

    def insert(self, idKey: int, value: str) -> list:
        self.stream[idKey] = value
        chunk = []
        while self.ptr <= self.n and self.ptr in self.stream:
            chunk.append(self.stream[self.ptr])
            self.ptr += 1
        return chunk
#include <unordered_map>
#include <vector>
#include <string>

class OrderedStream {
private:
    std::unordered_map<int, std::string> stream;
    int ptr;
    int n;

public:
    OrderedStream(int n) : ptr(1), n(n) {}

    std::vector<std::string> insert(int idKey, std::string value) {
        stream[idKey] = value;
        std::vector<std::string> chunk;
        while (ptr <= n && stream.count(ptr)) {
            chunk.push_back(stream[ptr]);
            ptr++;
        }
        return chunk;
    }
};

In this Python solution, we use a dictionary to store the inserted values, providing an efficient way to check for existence and extract ordered elements starting from the pointer location.

Complexity

Time Complexity: O(n) overall. Space Complexity: O(n) for dictionary use.

Try this approach in the editor

Approach 3: Array Simulation

We can use an array data of length n + 1 to simulate this stream, where data[i] represents the value of id = i. At the same time, we use a pointer ptr to represent the current position. Initially, ptr = 1.

When inserting a new (idKey, value) pair, we update data[idKey] to value. Then, starting from ptr, we sequentially add data[ptr] to the answer until data[ptr] is empty.

The time complexity is O(n), and the space complexity is O(n). Where n is the length of the data stream.

class OrderedStream {
    private ptr: number;
    private data: string[];

    constructor(n: number) {
        this.ptr = 1;
        this.data = Array(n + 1);
    }

    insert(idKey: number, value: string): string[] {
        this.data[idKey] = value;
        const ans: string[] = [];
        while (this.data[this.ptr]) {
            ans.push(this.data[this.ptr++]);
        }
        return ans;
    }
}

/**
 * Your OrderedStream object will be instantiated and called as such:
 * var obj = new OrderedStream(n)
 * var param_1 = obj.insert(idKey,value)
 */
type OrderedStream struct {
	ptr  int
	data []string
}

func Constructor(n int) OrderedStream {
	return OrderedStream{
		ptr:  1,
		data: make([]string, n+1),
	}
}

func (this *OrderedStream) Insert(idKey int, value string) []string {
	this.data[idKey] = value
	var ans []string
	for this.ptr < len(this.data) && this.data[this.ptr] != "" {
		ans = append(ans, this.data[this.ptr])
		this.ptr++
	}
	return ans
}

/**
 * Your OrderedStream object will be instantiated and called as such:
 * obj := Constructor(n);
 * param_1 := obj.Insert(idKey,value);
 */
struct OrderedStream {
    ptr: usize,
    data: Vec<Option<String>>,
}

impl OrderedStream {
    fn new(n: i32) -> Self {
        OrderedStream {
            ptr: 1,
            data: vec![None; (n + 1) as usize],
        }
    }

    fn insert(&mut self, id_key: i32, value: String) -> Vec<String> {
        self.data[id_key as usize] = Some(value);
        let mut ans = Vec::new();
        while self.ptr < self.data.len() && self.data[self.ptr].is_some() {
            ans.push(self.data[self.ptr].take().unwrap());
            self.ptr += 1;
        }
        ans
    }
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Array-Based Approach

Time Complexity: O(n) in worst case per insertion. Space Complexity: O(n) for the array storage.

Map-Based Approach

Time Complexity: O(n) overall. Space Complexity: O(n) for dictionary use.

Array Simulation–

Complexity analysis

ApproachTimeSpaceWhen to Use
Array-Based Stream with PointerO(1) amortized per insert, O(n) totalO(n)Best choice when ids are sequential and bounded from 1..n
Hash Map Based StreamO(1) average per insertO(n)Useful when ids are sparse or array indexing is not practical

Frequently asked questions

Is Design an Ordered Stream easy or hard?

Design an Ordered Stream is classified as an Easy problem on LeetCode with a high acceptance rate around 80%+. The challenge mainly tests basic data structure design, pointer tracking, and handling sequential output from unordered input.

How to solve Design an Ordered Stream in O(n)?

Use an array of size n+1 and maintain a pointer to the next expected id. Insert values directly into the array using the provided id. When the inserted id equals the pointer, iterate forward while elements exist and return that contiguous segment. Since each element is visited once, the overall complexity is O(n).

Design an Ordered Stream Python or Java solution

In Python or Java, implement a class with an array (or list) and an integer pointer initialized to 1. The insert method stores the value at index idKey, then iterates forward while the pointer position is filled, collecting results. This keeps each operation constant on average and uses O(n) space.

What is the best approach for Design an Ordered Stream?

The array-based approach with a moving pointer is the most efficient and commonly expected solution. Store values in an array indexed by id and track the next expected position with a pointer. When the inserted id matches the pointer, release consecutive values until a gap appears. This achieves O(1) amortized time per insert and O(n) space.

Is Design an Ordered Stream asked at Google/Amazon/Meta?

Ordered stream and data stream design questions appear in interviews at companies like Amazon, Google, and Meta in various forms. The exact problem may vary, but the pattern of maintaining ordered output from out-of-order input is common in system design and coding interviews.

What data structure is used in Design an Ordered Stream?

The optimal solution uses an array combined with a pointer that tracks the next expected index. A hash map can also be used to store inserted values and check for contiguous ids dynamically. Both structures support efficient lookup and ordered release of elements.

What is the time complexity of Design an Ordered Stream?

Each insert operation runs in O(1) amortized time. Although a single call may output multiple values, every element in the stream is processed only once when the pointer advances. Across all operations, the total time is O(n) with O(n) additional space.

Comments

Now write it yourselfClose this page and solve Design an Ordered Stream in the editor, without looking.
Practise Design an Ordered Stream