задачка для программистов
Feb. 21st, 2007 12:12 pmЗнакомый рассказал, ему на интервью задали. Красивая задачка, но совсем не подходящая для интервью, по-моему.
Есть некий поток элементов. Вызывая снова и снова функцию getnext(), вы получаете каждый раз следующий элемент из потока, и так до тех пор, пока функция не вернет EOF, что означает, что поток закончился. Гарантировано, что все элементы, полученные таким образом, будут отличаться друг от друга. Вернуться к началу потока, или получать элементы в каком-то другом порядке, кроме как один за другим с помощью getnext(), невозможно.
Известно, что поток когда-нибудь кончается, но заранее про количество элементов ничего не известно.
Требуется: написать функцию, которая, когда ее вызывают (а вызывают ее один раз), возвращает выбранный случайным образом один из элементов потока, притом у каждого из элементов потока одинаковая вероятность быть возвращенным этой функцией.
Функция должна использовать фиксированное количество памяти (иными словами, O(1) памяти).
Update: учтите, что в комментариях уже есть правильные ответы.
next , собственно, не будет достаточно случайным? ;)
Date: 2007-02-21 10:16 am (UTC)no subject
Date: 2007-02-21 10:17 am (UTC)no subject
Date: 2007-02-21 10:18 am (UTC)Классика
Date: 2007-02-21 10:19 am (UTC)no subject
Date: 2007-02-21 10:19 am (UTC)no subject
Date: 2007-02-21 10:20 am (UTC)no subject
Date: 2007-02-21 10:21 am (UTC)Element ret = getnext();
assert( ret != EOF );
Element cur = ret;
int n = 1;
while ( cur != EOF )
{
if ( MakeRandomNumber(n) == 0 )
ret = cur;
cur = getnext();
++n;
}
return ret;
Re: Классика
Date: 2007-02-21 10:25 am (UTC)no subject
Date: 2007-02-21 10:25 am (UTC)no subject
Date: 2007-02-21 10:25 am (UTC)Re: next , собственно, не будет достаточно случайным? ;)
Date: 2007-02-21 10:26 am (UTC)no subject
Date: 2007-02-21 10:27 am (UTC)no subject
Date: 2007-02-21 10:30 am (UTC)Последствия тервера в университете, где интуитивная оценка вероятности слишком часто оказывалась неверной :-)
no subject
Date: 2007-02-21 10:31 am (UTC)no subject
Date: 2007-02-21 10:32 am (UTC)1. Пишем вспомогательную функцию ВЫБОР типа ЭЛЕМЕНТ, аргументы: c1, c2 типа ЭЛЕМНТ, n - целое
Возвращает элемент c1 с вероятностью (n - 1) / n или c2 с вероятностью 1 / n (скажем, генерит случайной число от 1 до n, если выпало n - возвращает c2, иначе - c1; если n = 1 - возвращает с2)
2. В основной функции:
d1, d2 типа элемент; n типа целое
n = 1
ПОЛУЧИТЬ ИЗ ПОТОКА В d2
d1 := d2
ПОКА НЕ EOF ДЕЛАТЬ
d1 := ВЫБОР (d1, d2, n)
ПОЛУЧИТЬ ИЗ ПОТОКА В d2
КОНЕЦ ДЕЛАТЬ
ВЕРНУТЬ d1
Обоснование:
На втором шаге у нас первый элемент с вероятностью 1/2, второй - с вероятностью 1/2
На n шаге:
Первый элемент с вероятностью 1 * (1/2) * (2/3) * ... * ((n-1)/n) = 1 / n
Второй элнмент с вероятностью (1/2) * (2/3) * ... * ((n-1)/n) = 1 / n
Третий элемент с вероятностью (1/3) * (3/4) * (4/5) * (5/6) * ... * ((n-1)/n) = 1/n
...
k-й элемент с вероятностью (1/k) * (k/(k+1)) * ((k+1)/(k+2)) * ... * ((n-1)/n) = 1/n
...
n-й элемент с вероятностью 1/n
Вопрос:
1) Куда интервьюировали ? На какую должность ?
2) Знакомый решил ?
no subject
Date: 2007-02-21 10:32 am (UTC)Я считаю, что на интервью задачи, для решения которых необходимо найти "изюминку", неправильно - потому что то, что кандидат не догадался, практически ничего не означает. Кому-то пришло в голову, кому-то не пришло. Это все равно, что оценивать знание математики по умению решать олимпиадные задачки. Гораздо лучше давать вопросы, в которых "изюминка" позволяет сделать что-то лучше и качественнее, но и без нее, просто грамотно используя свои знания и умения, можно придти к достойному ответу.
no subject
Date: 2007-02-21 10:32 am (UTC)2avva: А почему по вашему она не подходит для интервью? Мне кажется - как раз на проверку "работающей соображалки" и знаний элементарной математики, именно то, что и должны на интервью проверять...
no subject
Date: 2007-02-21 10:35 am (UTC)no subject
Date: 2007-02-21 10:45 am (UTC)Но в этой задаче, мне кажется, этого даже не требуется. "Догадаться, что следует хранить один элемент в качестве текущего кандидата, которого мы выдаем, если поток в сей момент кончился" очень просто. Я именно с конца ее и решил. Т.е. вот мы встретили EOF, значит, надо что-то выдать, но что? Значит, есть некий Element res. Инициализируем его первым значением (потому что больше просто нечем). И он должен по каким-то правилам меняться; по каким?
no subject
Date: 2007-02-21 10:47 am (UTC)Но ведь фраза условия "Функция должна использовать фиксированное количество памяти (иными словами, O(1) памяти)." уже подразумевает под собой хранение одного элемента. До этого не нужно догадываться, это условие. А дальше нужно думать, как именно хранить его так, чтобы сохранять равную вероятность.
Вот если бы этой фразы в задаче не было, тогда другое дело. Тогда действительно, "просто свои используя знания" можно было бы придти к лобовому ответу (сохранять всё по мере поступления), а до "изюминки" надо было бы додумываться.
no subject
Date: 2007-02-21 10:50 am (UTC)по-моему она подозревает конечное поличество эелементов, а не один. если я еще что-то помню из того, что учила. но от конечного до одного - один шаг.
no subject
Date: 2007-02-21 10:52 am (UTC)no subject
Date: 2007-02-21 10:53 am (UTC)думаю, привльнее использовать то, что ты предложил.
или что-то достаточно большое, чтоб требовать не результат, а как бы просить человека, чтоб он рассуждал вслух.
no subject
Date: 2007-02-21 10:53 am (UTC)Впрочем, чего тут считать… Обратная индукция на пальцах [действительно на пальцах, причём :-)] подтверждает.
не глядя в комменты
Date: 2007-02-21 10:57 am (UTC)2. для потока из двух элементов - выбираем второй элемент с вероятностью 1/2, а с вероятностью 1/2 оставляем первый элемент
3. для потока из 3-х - выберем третий элемент с вероятностью 1/3, а с вероятностью 2/3 - один из первых двух, полученный на шаге 2
Таким образом вероятность выбора 1-го элемента - 2/3 * 1/2 = 1/3 и то же самое для 2-го
4. из 4-х - последний - 1/4, три первых - 3/4. Из них каждый выбирается с вероятностью 1/3 как следует из шага 3. Значит вероятность выбора каждого из них - 3/4 * 1/3 = 1/4
и так далее - т.е. надо выбирать N-ный элемент с вероятностью 1/N и возвращать последний выбранный элемент при приходе EOF
А почему для интервью не подходит. Хорошая и простая задачка IMHO