Programmer's Blood Bath ([info]314159265) wrote,
@ 2007-06-30 12:13:00
Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Получил я как-то на интервью такую задачу, есть функция с такой сигнатурой:

const std::vector join(const std::vector& v1, const std::vector& v2) {
    ...
}


В v1 и v2 содержатся простые int'ы, необходимо на выходе получить вектор, который содержит неповторяющиеся числа из v1 и v2. Решение, которое я предложил через 5 секунд - использовать std::set или std::sort было отвергнуто сразу с комментариями, что вот вы мол собираетесь использовать STL контейнеры и алгоритмы, а это очень неэффективно. Не пытался спорить об эффективности, это было бесполезно, просто отправился подумать. Вернулся с простеньким решением на основе binary tree и был послан домой, чтобы не отвлекать больше умных дядек от собеседования с другими кандидатами. Tree им тоже не понравилось, попытки комментировать и предложить более
эффективные решения на основе RB tree были также посланы лесом.

К сожалению не было возможности задать уточняющие вопросы вроде являются ли вектора отсортированными, есть ли повторяющиеся значения в каждом из векторов и т.п. Поэтому мои попытки решить это сводились к наихудшему случаю - вектора неотсортированы, могут быть разной длины, могут содержать повторяющиеся числа. Что важно - расход памяти или скорость, впрочем, тоже не известно.

Вот собственно вопрос - как бы вы ее решили?




(Post a new comment)


[info]vzaliva
2007-06-30 09:29 am UTC (link)
я думаю в задаче предполагалось что входные вектора сортированные.
иначе она не представляет интереса для интервью :)

(Reply to this) (Thread)


[info]plakhov
2007-06-30 01:31 pm UTC (link)
Судя по реакции интервьюирующих, похоже на то.

(Reply to this) (Parent)


[info]some41
2007-06-30 10:53 am UTC (link)
set это и так rbtree, а условие задачи все-таки хорошо бы знать :)

(Reply to this)


[info]ivan_ghandhi
2007-07-01 12:39 am UTC (link)
Я бы сначала задумался о решении другой задачи - надо ли, в 21-м веке, связываться с тормозами из семидесятых? Послать их да и всё. Оба решения правильны - и set, и дерево.

Кстати, для задачи такого сорта не нужно двух векторов. В смысле - какая разница, сольём в один, потом решаем задачу для одного.

(Reply to this) (Thread)


[info]314159265
2007-07-01 11:07 am UTC (link)
Такая уж у них технология, тормозная.

(Reply to this) (Parent)


[info]execve
2007-07-01 09:06 am UTC (link)
Ну да, навскидку - set.
Или sort обоих и слияние с убиранием дублей.

Но на самом деле настораживает нежелание собеседователей общаться.

(Reply to this) (Thread)


[info]314159265
2007-07-01 11:06 am UTC (link)
Угу. Надменность. Нафиг. Просто было интересно - что же я такого мог упустить. Похоже что все было нормально.

(Reply to this) (Parent)


[info]antoxa
2007-07-01 03:08 pm UTC (link)
ну set, честно сказать, перебор, а остальное вполне имхо нормальные варианты, ну и условия задачи да, нумбер ноль :)

(Reply to this)

они хотели увидеть понимание
[info]bravomail
2007-07-03 02:44 pm UTC (link)
глубинных процессов позади API, возможно.
Или у них был готовый ответ из задачника, а сами они в-общем ни бум-бум.
Вариант решения - держать результирующий вектор отсортированным и добавлять значения из N входных векторов с помощью двоичного поиска в результирующем векторе. Задача, таким образом, обобщена для любого числа векторов.

(Reply to this)


[info]justbulat
2007-09-01 05:07 am UTC (link)
я бы поинтересовался, с каких пор это стало неэффективно :)

(Reply to this)


[info]alexeychen
2007-09-09 07:05 pm UTC (link)
Давно STL не пользую =))))

С тривиальным случаем даже не интересно =), но при худших условиях (неотсортированны,с повторениями) - типа так:

vector_t v;
v.reserve(v1.size()+v2.size());

vector_t::iterator ij[2][2] = {{v1.begin(), v1.end()},{v2.begin(), v2.end()}}

for ( int q =0; q < 2; ++q )
for ( vector_t::iterator i = ij[q][0], iE = ij[q][1]; i != iE; ++i )
{
vector_t::iterator j = lower_bound(v.begin(),v.end(),*i);
if ( j == v.end() || *j != i ) v.insert(j,i);
}

return v; // ага!? =)))

Писал с головы, так что могут быть ошибки.

Было бы логично, если бы с тебя просили либо тупой std::merge или что-то типа смеси std::sort,std::unique и std::merge. Однако исходя из задвигов про перформанс могу в этом усомниться.


(Reply to this)


[info]109
2007-10-19 02:01 am UTC (link)
псевдокод.

1. hashtable ht = new hashtable(v1.length + v2.length) // чтобы память не переаллокировать лишний раз

2. foreach (int a in v1, v2) if (!ht.contains(a)) ht.add(a)

и add и contains имеют амортизованную стоимость O(1), так что результат будет O(N), что несколько лучше, чем решение с деревом - O(N log N).

(Reply to this) (Thread)


[info]109
2007-10-19 02:08 am UTC (link)
на самом деле, конечно, понятно, что полная мощь hashtable не нужна, и если нужно экономить каждый бит и каждый такт, то можно использовать ту же идею, но с самодельной имплементацией - то есть, зааллокировать массив двойного размера и пихать каждое число по индексу [value % array_size], не забывая про коллизии.

(Reply to this) (Parent)(Thread)


[info]314159265
2007-10-21 03:06 am UTC (link)
I believe it's overkill, however thank you for idea.

(Reply to this) (Parent)


Create an Account
Forgot your login or password?
Login w/ OpenID
English • Español • Deutsch • Русский…