Re[2]: Заполнить массив
От: _DAle_ Беларусь  
Дата: 03.02.10 13:20
Оценка:
Здравствуйте, frogkiller, Вы писали:

F>Здравствуйте, andrey.desman, Вы писали:


AD>>Вот такую задачку получил недавно на собеседовании:

AD>>Есть неинициализированный массив из 100 чисел. Дана функция rand(n), которая генерирует случайное число в диапазоне [0, n].

AD>>Заполнить массив числами [0, 99] в случайном порядке так, чтобы числа не повторялись.


AD>>Как это можно сделать?


F>Посмотри, как работает типичная реализация std::random_shuffle. И мы точно знаем, что на i-м месте будет стоять число i, поэтому перемешивание можно совместить с инициализацией. Получится как-то так:


F>
for (int i = 1; i < n - 1; ++i ) {
F>   int j = rand(i);
F>   a[i] = a[j];
F>   a[j] = i;
F>}


Дело в том, что необязательно на i-ом месте будет стоять число i после свопов. Поэтому не настолько просто получается.

F>ЗЫ. твоё решение с 50-ти индексами, кстати, не будет обладать свойством равномерности распределения
Re[3]: Заполнить массив
От: andrey.desman  
Дата: 03.02.10 13:27
Оценка: +1
Здравствуйте, _DAle_, Вы писали:

F>>
for (int i = 1; i < n - 1; ++i ) {
F>>   int j = rand(i);
F>>   a[i] = a[j];
F>>   a[j] = i;
F>>}


_DA>Дело в том, что необязательно на i-ом месте будет стоять число i после свопов. Поэтому не настолько просто получается.


rand(i) генерирует число от 0 до i, так что будет.
Re[4]: Заполнить массив
От: _DAle_ Беларусь  
Дата: 03.02.10 13:43
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Здравствуйте, _DAle_, Вы писали:


F>>>
for (int i = 1; i < n - 1; ++i ) {
F>>>   int j = rand(i);
F>>>   a[i] = a[j];
F>>>   a[j] = i;
F>>>}


_DA>>Дело в том, что необязательно на i-ом месте будет стоять число i после свопов. Поэтому не настолько просто получается.


AD>rand(i) генерирует число от 0 до i, так что будет.


Да, я одной особенности в коде не заметил ). Интересно, а при такой реализации равномерное распределение будет?
Re[5]: Заполнить массив
От: Caracrist https://1pwd.org/
Дата: 03.02.10 14:18
Оценка:
Здравствуйте, _DAle_, Вы писали:

_DA>Здравствуйте, andrey.desman, Вы писали:


AD>>Здравствуйте, _DAle_, Вы писали:


F>>>>
for (int i = 1; i < n - 1; ++i ) {
F>>>>   int j = rand(i);
F>>>>   a[i] = a[j];
F>>>>   a[j] = i;
F>>>>}


_DA>>>Дело в том, что необязательно на i-ом месте будет стоять число i после свопов. Поэтому не настолько просто получается.


AD>>rand(i) генерирует число от 0 до i, так что будет.


_DA>Да, я одной особенности в коде не заметил ). Интересно, а при такой реализации равномерное распределение будет?


нет

если rand(i) => [0,i)
как минимум, шанс a[n-1] (с нуля) быть не на своём месте 100%

если rand(i) => [0,i]
то шанс a[i] (с нуля) быть на своём месте:
1/(i+1) + i/(i+1) * (i+1)/(i+2) * (i+2)/(i+3) * ... * (n-1)/(n) = 1/(i+1) + i/n

~~~~~
~lol~~
~~~ Single Password Solution
Re: Заполнить массив
От: Caracrist https://1pwd.org/
Дата: 03.02.10 14:39
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Есть неинициализированный массив из 100 чисел. Дана функция rand(n), которая генерирует случайное число в диапазоне [0, n].


Моя rand(n) даёт результат в диапазоне [0, n) == [0, n-1]
Прибавь 1 для преобразования.

AD>Как это можно сделать?


вариант 1:
for (int i = 0; i < n; ++i) a[i] = i;
for (int i = 0; i < n-1; ++i)
{
int j = rand(n-i) + i;
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}



вариант 2:
memset(a, -1, sizeof(int)*n);
for (int i = 0; i < n-1; ++i)
{
int j = rand(n-i) + i;
if (a[j] == -1) a[j] = j; 
int temp = a[i];
if (temp == -1) temp = i; 
a[i] = a[j];
a[j] = temp;
}
~~~~~
~lol~~
~~~ Single Password Solution
Re[6]: Заполнить массив
От: frogkiller Россия  
Дата: 03.02.10 15:14
Оценка: 6 (1) +2
Здравствуйте, Caracrist, Вы писали:

F>>>>>
for (int i = 1; i < n - 1; ++i ) {
F>>>>>   int j = rand(i);
F>>>>>   a[i] = a[j];
F>>>>>   a[j] = i;
F>>>>>}


_DA>>>>Дело в том, что необязательно на i-ом месте будет стоять число i после свопов. Поэтому не настолько просто получается.


AD>>>rand(i) генерирует число от 0 до i, так что будет.


_DA>>Да, я одной особенности в коде не заметил ). Интересно, а при такой реализации равномерное распределение будет?


C>нет


C>если rand(i) => [0,i)

C>как минимум, шанс a[n-1] (с нуля) быть не на своём месте 100%

C>если rand(i) => [0,i]

C>то шанс a[i] (с нуля) быть на своём месте:
C>1/(i+1) + i/(i+1) * (i+1)/(i+2) * (i+2)/(i+3) * ... * (n-1)/(n) = 1/(i+1) + i/n

C>


Что-то ты путаешь, по-моему. У тебя для (n-1)-го (т.е. последнего) вероятность остаться будет равна 1

Если рассуждать по индукции: для n=1 и n=2 — алгоритм очевидно работает.
Дальше, пусть на k-ом шаге итерации на [0 .. k-1] всё распределено равномерно. k-ая перестановка (если rand(k) выдаёт равномерное число на [0 .. k]) приведёт к тому, что число k с вероятностью 1/(k+1) может оказаться на любой позиции из [0 .. k]. Аналогично, на k-ом месте может оказаться любое число из [0 .. k] с той же вероятностью. Т.е. на каждой итерации поддерживаетяс равномерность распределения на [0 .. k].

В любом случае посмотри на реализацию random_shuffle от SGI
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re: Заполнить массив
От: Sinus Россия  
Дата: 03.02.10 15:37
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Всем привет!


AD>Вот такую задачку получил недавно на собеседовании:

AD>Есть неинициализированный массив из 100 чисел. Дана функция rand(n), которая генерирует случайное число в диапазоне [0, n].

AD>Заполнить массив числами [0, 99] в случайном порядке так, чтобы числа не повторялись.


AD>Мое решение:

AD>Заполнить массив числами в порядке возрастания: a[i] = i, 0 <= i <= 99.
AD>В цикле на 50 повторений сгенерировать два случайных индекса и поменять значения по этим индексам местами.
AD>Уникальность и случайность есть, работает.

AD>Но экзаменатор ( ) утверждал, что можно сделать это за один проход. То есть каким-то образом сделать так, чтобы сразу получить последовательность уникальных чисел, при том, что rand в общем случае таких чисел не генерирует.

AD>Как это можно сделать?

По-моему, все вообще элементарно.
Берем число 1 и определяем его номер в массиве вызовом rand(99). Перенумеровываем СВОБОДНЫЕ позиции массива от 0 до 98.
Берем число 2 и определяем его номер в массиве вызовом rand(98). Перенумеровываем СВОБОДНЫЕ позиции массива от 0 до 97.
........................................................................................................................
Берем число n и определяем его номер в массиве вызовом rand(100-n). Перенумеровываем СВОБОДНЫЕ позиции массива от 0 до 100-n-1.
................................................................................................................................
Re[2]: Заполнить массив
От: frogkiller Россия  
Дата: 03.02.10 15:41
Оценка:
Здравствуйте, Sinus, Вы писали:

S>По-моему, все вообще элементарно.

S>Берем число 1 и определяем его номер в массиве вызовом rand(99). Перенумеровываем СВОБОДНЫЕ позиции массива от 0 до 98.
S>Берем число 2 и определяем его номер в массиве вызовом rand(98). Перенумеровываем СВОБОДНЫЕ позиции массива от 0 до 97.
S>........................................................................................................................
S>Берем число n и определяем его номер в массиве вызовом rand(100-n). Перенумеровываем СВОБОДНЫЕ позиции массива от 0 до 100-n-1.
S>................................................................................................................................

И получаем квадратичную сложность
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re[5]: Заполнить массив
От: vdimas Россия  
Дата: 04.02.10 13:34
Оценка: -1
Здравствуйте, _DAle_, Вы писали:

_DA>Да, я одной особенности в коде не заметил ). Интересно, а при такой реализации равномерное распределение будет?


Нет.
Re[6]: Заполнить массив
От: frogkiller Россия  
Дата: 04.02.10 17:01
Оценка:
Здравствуйте, vdimas, Вы писали:

_DA>>Да, я одной особенности в коде не заметил ). Интересно, а при такой реализации равномерное распределение будет?


V>Нет.


Будет. Доказательство см. выше.
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re[3]: Заполнить массив
От: Кодт Россия  
Дата: 04.02.10 17:25
Оценка:
Здравствуйте, Hunta, Вы писали:

H>Ещё куча подходящих (А, С): (21, 49) (41,13)...


А также (1,1), (1,3), (1,7), ... а то как-то уж совсем лишаем себя удовольствия получить все возможные варианты.
Перекуём баги на фичи!
Re[7]: Заполнить массив
От: vdimas Россия  
Дата: 04.02.10 18:12
Оценка:
Здравствуйте, frogkiller, Вы писали:


F>Будет. Доказательство см. выше.


Ну вообще да, если rand(i) вернет от 0 до i включительно, то согласен (посмотрел внимательней разъяснения, из кода этого вовсе не следовало). Просто обычно rand(i) возвращает число от 0-ля до i-1, в этом случае для каждого нового числа с порядковым номером k вероятность перестановки была бы 1, а не 1-(1/k). Хотя, для достаточно большого массива распределение было бы близко к равномерному даже в этом случае.
Re: Заполнить массив
От: arabo_xv Грузия  
Дата: 26.02.10 14:23
Оценка: -2 :)
Здравствуйте, andrey.desman, Вы писали:

AD>Всем привет!


AD>Вот такую задачку получил недавно на собеседовании:

AD>Есть неинициализированный массив из 100 чисел. Дана функция rand(n), которая генерирует случайное число в диапазоне [0, n].

AD>Заполнить массив числами [0, 99] в случайном порядке так, чтобы числа не повторялись.


AD>Мое решение:

AD>Заполнить массив числами в порядке возрастания: a[i] = i, 0 <= i <= 99.
AD>В цикле на 50 повторений сгенерировать два случайных индекса и поменять значения по этим индексам местами.
AD>Уникальность и случайность есть, работает.

AD>Но экзаменатор ( ) утверждал, что можно сделать это за один проход. То есть каким-то образом сделать так, чтобы сразу получить последовательность уникальных чисел, при том, что rand в общем случае таких чисел не генерирует.

AD>Как это можно сделать?


m = 100;
for (int i = 0; i < 100; ++i)
{
a[rand(m - 1)] = i ;
m = m - 1;
}

Тут не совсем случайно, но вы сможете используя этот метод, слегка оптимизировав его, и получите случайный расклад.
PS предполагаю что rand(m — 1) вернёт целое число от 0 до m-1. Если нет, просто приводить к целому
Re[2]: Заполнить массив
От: RadmirT Россия  
Дата: 01.03.10 10:02
Оценка:
Здравствуйте, arabo_xv, Вы писали:

_>
_>m = 100;
_>for (int i = 0; i < 100; ++i)
_>{
_>a[rand(m - 1)] = i ;
_>m = m - 1;
_>}
_>

_>Тут не совсем случайно, но вы сможете используя этот метод, слегка оптимизировав его, и получите случайный расклад.
_>PS предполагаю что rand(m — 1) вернёт целое число от 0 до m-1. Если нет, просто приводить к целому

А какими значениями запольнять "дырки"?
допустим на 1 итерации rand(m — 1) вернет нам значение не равное m-1 что нам записывать в a[m-1] ведь в эту ячейку мы никогда больше не попадем?
Re[2]: Заполнить массив
От: Roman Odaisky Украина  
Дата: 02.03.10 21:40
Оценка:
Здравствуйте, Hunta, Вы писали:

H>Сгенерировать массив, напустить на него Sort со случайным компаратором %-)


Это недавно сделал Майкрософт в своем окне выбора броузера при установке ОС, отчего IE в более, чем 50% случаев, попадал в хвост списка :-).
До последнего не верил в пирамиду Лебедева.
Re[2]: Заполнить массив
От: Mazay Россия  
Дата: 08.03.10 18:11
Оценка:
Здравствуйте, frogkiller, Вы писали:

F>Здравствуйте, andrey.desman, Вы писали:


AD>>Вот такую задачку получил недавно на собеседовании:

AD>>Есть неинициализированный массив из 100 чисел. Дана функция rand(n), которая генерирует случайное число в диапазоне [0, n].

AD>>Заполнить массив числами [0, 99] в случайном порядке так, чтобы числа не повторялись.


AD>>Как это можно сделать?


F>Посмотри, как работает типичная реализация std::random_shuffle. И мы точно знаем, что на i-м месте будет стоять число i, поэтому перемешивание можно совместить с инициализацией. Получится как-то так:


F>
for (int i = 1; i < n - 1; ++i ) {
F>   int j = rand(i);
F>   a[i] = a[j];
F>   a[j] = i;
F>}


Ну а где инициализация-то? Может так:
S = 0;
S +=  rand(n/99); 
a[0] = S;
for (int i = 1; i < 100; ++i ) {
   int j = rand(i); //случайный порядок
   a[i] = a[j];
   S += rand(n/99); // случайные уникальные значения от 0 до n, 
   //S += (100-S)*(-ln(rand(n)/n)) //можно как-то сместить вероятность чтобы получить честное равномерное распределерние
   a[j] = S;
}

Формально один проход. Хотя можно раскидать на два — инициализация уникальными-случайными-упорядочеными и перестановка.
Главное гармония ...
Re[3]: Заполнить массив
От: frogkiller Россия  
Дата: 08.03.10 19:49
Оценка:
Здравствуйте, Mazay, Вы писали:

F>>Посмотри, как работает типичная реализация std::random_shuffle. И мы точно знаем, что на i-м месте будет стоять число i, поэтому перемешивание можно совместить с инициализацией. Получится как-то так:


M>Ну а где инициализация-то?


F>>
for (int i = 1; i < n - 1; ++i ) {
F>>   int j = rand(i);
F>>   a[i] = a[j];
F>>   a[j] = i;    // <--- А вот же она!
F>>}


Тут просто совмещена инициализация числами по порядку от 0 до n и последующая random_shuffle — чтобы получился один проход.


Может так:
M>
M>S = 0;
M>S +=  rand(n/99); 
M>a[0] = S;
M>for (int i = 1; i < 100; ++i ) {
M>   int j = rand(i); //случайный порядок
M>   a[i] = a[j];
M>   S += rand(n/99); // случайные уникальные значения от 0 до n, 
M>   //S += (100-S)*(-ln(rand(n)/n)) //можно как-то сместить вероятность чтобы получить честное равномерное распределерние
M>   a[j] = S;
M>}
M>

M>Формально один проход. Хотя можно раскидать на два — инициализация уникальными-случайными-упорядочеными и перестановка.
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.