Two Sigma Interview Question
Software Engineer / DevelopersCountry: United States
Interview Type: Phone Interview
Idea: We keep a buffer of elements from the fast queue that may be required in future pairs. We examine the items in the slow Queue one by one, we first "trim" off the elements of the buffer that can no longer be in an output pair, then we examine the items in the buffer and finally we pop new elements off of the fast queue if they form a pair and place them in the buffer.
We arrange the loops this way so the accesses to the "slow" queue are more spread out.
Complexity analysis, O(nm) where n and m are the number of elements in the slow and fast queues, respectively. We will get achieve this complexity when all time stamps and all queues are within one second, for example.
#include <vector>
#include <queue>
#include <cassert>
#include <deque>
#include <iostream>
using price_t = unsigned int;
using Time_t = double;
struct data_t
{
price_t price;
Time_t time;
data_t(price_t p, Time_t t)
: price {p}
, time {t}
{}
};
std::vector<std::pair<price_t, price_t> >
twoQueues(std::queue<data_t> & Qfast,
std::queue<data_t> & Qslow)
{
std::vector<std::pair<price_t,price_t> > result;
std::deque<data_t> buffer;
while(!Qslow.empty()){
auto head = Qslow.front();
Qslow.pop();
const auto time_min = head.time - 1.0;
const auto time_max = head.time + 1.0;
while(!buffer.empty() && buffer.front().time < time_min){
buffer.pop_front();
}
for(const auto val : buffer){
assert(val.time >= time_min);
assert(val.time <= time_max);
result.emplace_back(head.price, val.price);
}
while(!Qfast.empty() && Qfast.front().time <= time_max){
const auto temp = Qfast.front();
result.emplace_back(head.price, temp.price);
buffer.push_back(temp);
Qfast.pop();
}
}
return result;
}
int
main()
{
std::queue<data_t> Q1, Q2;
data_t elem = {1,.11};
Q1.push(elem);
elem = {23,.21};
Q1.push(elem);
elem = {1000,.1};
Q2.push(elem);
elem = {2000,.2};
Q2.push(elem);
elem = {1234,100.0};
Q2.push(elem);
const auto something = twoQueues(Q1,Q2);
for(const auto& val : something){
std::cout << val.first << ',' << val.second << std::endl;
}
return 0;
}
I'm going to assume that the queues are sorted by timestamp. If not, then just sort each queue before starting for O(n log n).
- cgj May 11, 2017General strategy is to peek the lowest element from both of the queues. Then peek the other queue for entries < 1 second away. If no elements such elements exist, dequeue the lowest element and try again.
I don't understand the 'one queue is slow' portion, I'll leave that unaddressed.