Задачка
От: fearless Россия http://www.lit.msu.ru/
Дата: 30.09.01 08:39
Оценка:
Здравствуйте, уважаемые. Хочу предложить вам поразмяться :-)

Есть массив длинны N. Известно, что больше половины элементов
этого массива равны друг другу. Требуется за один (!) проход по
массиву выяснить чему же они равны.

Ходят слухи, что если массив целочисленный, то существует математическое
решение задачи. Но есть решение и в общем виде.

Что скажете?

17.01.03 00:43: Перенесено из 'Алгоритмы'
С уважением
fearless
Re: Задачка
От: Lexey Россия  
Дата: 01.10.01 07:18
Оценка:
Здравствуйте fearless, вы писали:

F>Здравствуйте, уважаемые. Хочу предложить вам поразмяться :-)


F>Есть массив длинны N. Известно, что больше половины элементов

F>этого массива равны друг другу. Требуется за один (!) проход по
F>массиву выяснить чему же они равны.

F>Ходят слухи, что если массив целочисленный, то существует математическое

F>решение задачи. Но есть решение и в общем виде.

Ну с целочисленным тут вроде все понятно. Создаешь массив счетчиков встречаемости конкретных чисел и запоминаешь текущий максимальный счетчик. Правда массив может получиться немерянного размера (2^32 для int, если нет никаких априорных ограничений на диапазон чисел). :)

Для произвольных элементов для счетчиков можно использовать хеш-таблицу. Добавляются накладные расходы на хеширование и на разрешение коллизий.
Re[2]: Задачка
От: Vitalische  
Дата: 01.10.01 19:45
Оценка: 18 (2)
Вроде бы так:


int cnt = 0;
int num;

for ( int i = 0; i < a.size(); ++i )
{
  if ( cnt > 0 && a[i] != num )
    --cnt;
  else
    ++cnt;

  if ( cnt == 1 )
    num = a[i];
}


ответ: num
Re[3]: Задачка
От: Vitalische  
Дата: 01.10.01 19:48
Оценка:
Конечно, num не обязательно int. Можно поставить любой тип ( который можно сравнивать :) ).
Re[3]: Задачка
От: Lexey Россия  
Дата: 02.10.01 08:17
Оценка:
Здравствуйте Vitalische, вы писали:

V>Вроде бы так:


V>int cnt = 0;

V>int num;

V>for ( int i = 0; i < a.size(); ++i )

V>{
V> if ( cnt > 0 && a[i] != num )
V> --cnt;
V> else
V> ++cnt;

V> if ( cnt == 1 )

V> num = a[i];
V>}

V>ответ: num


По-моему, это лажа.
1) Чем ты "num" инициализировать будешь?
2) Имеем такую картину: всего есть 3k+1 элементов, принимающих всего 3 значения 0 — k+1 штук,1 — k штук,2 — k-штук.
В начале идут k нулей, затем k единиц, затем k двоек и в конце один 0. Такой алгоритм выдаст в итоге 2, а должен давать 0.
Re[4]: Задачка
От: Vitalische  
Дата: 02.10.01 11:25
Оценка:
L>По-моему, это лажа.
L>1) Чем ты "num" инициализировать будешь?
L>2) Имеем такую картину: всего есть 3k+1 элементов, принимающих всего 3 значения 0 — k+1 штук,1 — k штук,2 — k-штук.
L>В начале идут k нулей, затем k единиц, затем k двоек и в конце один 0. Такой алгоритм выдаст в итоге 2, а должен давать 0.

Что то я не понял. Читаем условие задачи: "...Известно, что больше половины элементов
этого массива равны друг другу...". И какая "больше половины" элементов равны друг другу в твоём примере? Нулей вроде бы около одной трети.

num проинициализируется внутри цикла, т.к. кол-во элементов массива > 0.
Re[5]: Задачка
От: Lexey Россия  
Дата: 02.10.01 13:13
Оценка:
Здравствуйте Vitalische, вы писали:

L>>По-моему, это лажа.

L>>1) Чем ты "num" инициализировать будешь?
L>>2) Имеем такую картину: всего есть 3k+1 элементов, принимающих всего 3 значения 0 — k+1 штук,1 — k штук,2 — k-штук.
L>>В начале идут k нулей, затем k единиц, затем k двоек и в конце один 0. Такой алгоритм выдаст в итоге 2, а должен давать 0.

V>Что то я не понял. Читаем условие задачи: "...Известно, что больше половины элементов


Блин, посыпаю голову пеплом. Про больше половины я и не заметил. :(((

V>этого массива равны друг другу...". И какая "больше половины" элементов равны друг другу в твоём примере? Нулей вроде бы около одной трети.


V>num проинициализируется внутри цикла, т.к. кол-во элементов массива > 0.


Тоже логично.
Re[6]: Задачка
От: fearless Россия http://www.lit.msu.ru/
Дата: 02.10.01 16:50
Оценка:
А теперь и я посыпаю голову пеплом. :-)
В условии также сказано, что не разрешается создавать вспомогательные массивы.
С уважением
fearless
Re[7]: Задачка
От: Lexey Россия  
Дата: 02.10.01 17:14
Оценка:
Здравствуйте fearless, вы писали:

F>А теперь и я посыпаю голову пеплом. :-)

F>В условии также сказано, что не разрешается создавать вспомогательные массивы.

Ну, в общем-то, то, что предложил Vitalische, не использует дополнительных массивов и действительно является требуемым решением. :)
Re[3]: Задачка
От: Андрей Тарасевич Беларусь  
Дата: 03.10.01 23:55
Оценка:
Здравствуйте Vitalische, вы писали:

V>Вроде бы так:


V>int cnt = 0;

V>int num;

V>for ( int i = 0; i < a.size(); ++i )

V>{
V> if ( cnt > 0 && a[i] != num )
V> --cnt;
V> else
V> ++cnt;

V> if ( cnt == 1 )

V> num = a[i];
V>}

V>ответ: num


Бессмыслица. Что-то вороде поиска самой длинной последовательности с лирическими отступлениями. Пойдет разве что как очень приближенный алгоритм. Не работает на { 3, 3, 1, 3, 3, 1, 3, 3, 2, 2, 2 }.
Best regards,
Андрей Тарасевич
Re[8]: Задачка
От: Андрей Тарасевич Беларусь  
Дата: 03.10.01 23:56
Оценка:
L>Ну, в общем-то, то, что предложил Vitalische, не использует дополнительных массивов и действительно является требуемым решением. :)

Не является он требуемым решением, ибо не работает.
Best regards,
Андрей Тарасевич
Re[2]: Задачка
От: Андрей Тарасевич Беларусь  
Дата: 04.10.01 00:01
Оценка:
Здравствуйте Lexey, вы писали:

F>>Есть массив длинны N. Известно, что больше половины элементов

F>>этого массива равны друг другу. Требуется за один (!) проход по
F>>массиву выяснить чему же они равны.

F>>Ходят слухи, что если массив целочисленный, то существует математическое

F>>решение задачи. Но есть решение и в общем виде.

L>Ну с целочисленным тут вроде все понятно. Создаешь массив счетчиков встречаемости конкретных чисел и запоминаешь текущий максимальный счетчик. Правда массив может получиться немерянного размера (2^32 для int, если нет никаких априорных ограничений на диапазон чисел). :)


Не удовлетворяет условию задачи. Когда говорят "за один проход" имеется в виду — за O(N) операций. В твоем варианте понадобится порядка O(N) + O(M) операций, где M — длина массива счетчиков.
Best regards,
Андрей Тарасевич
Re[3]: Задачка
От: Андрей Тарасевич Беларусь  
Дата: 04.10.01 00:12
Оценка:
L>>Ну с целочисленным тут вроде все понятно. Создаешь массив счетчиков встречаемости конкретных чисел и запоминаешь текущий максимальный счетчик. Правда массив может получиться немерянного размера (2^32 для int, если нет никаких априорных ограничений на диапазон чисел). :)

АТ>Не удовлетворяет условию задачи. Когда говорят "за один проход" имеется в виду — за O(N) операций. В твоем варианте понадобится порядка O(N) + O(M) операций, где M — длина массива счетчиков.


Хм... Можно, конечно возразить, что O(M) — константа. В общем, теоретически ты прав. Полученный алгоритм действительно работает за O(N) и решает задачу. Но практически там вроде уже есть дополнительное условие о том, что дополнительные массивы заводить нельзя :)
Best regards,
Андрей Тарасевич
Re[3]: Задачка
От: Lexey Россия  
Дата: 04.10.01 07:31
Оценка:
Здравствуйте Андрей Тарасевич, вы писали:

АТ>Не удовлетворяет условию задачи. Когда говорят "за один проход" имеется в виду — за O(N) операций. В твоем варианте понадобится порядка O(N) + O(M) операций, где M — длина массива счетчиков.


Ну давай еще поспорим. За один проход, может означать только именно за один проход по исходному массиву. Никаких других требований на сложность это не накладывает.
Re[9]: Задачка
От: Lexey Россия  
Дата: 04.10.01 08:10
Оценка:
Здравствуйте Андрей Тарасевич, вы писали:

L>>Ну, в общем-то, то, что предложил Vitalische, не использует дополнительных массивов и действительно является требуемым решением. :)


АТ>Не является он требуемым решением, ибо не работает.


Действительно не работает, но похоже, что это все-таки ошибка программирования, а не логики :)

Сейчас вот пытаюсь обдумать такой вариант:
int cnt=0;
type num=a[0];
for(int i=0;i<size_of_a;i++)
{
   if(a[i]!=num && cnt>0)
:cnt--;
   if(!cnt)
   {
       num=a[i];
   }
}
Re[10]: Задачка
От: Lexey Россия  
Дата: 04.10.01 08:16
Оценка:
Здравствуйте Lexey, вы писали:

L>Здравствуйте Андрей Тарасевич, вы писали:


L>>>Ну, в общем-то, то, что предложил Vitalische, не использует дополнительных массивов и действительно является требуемым решением. :)


АТ>>Не является он требуемым решением, ибо не работает.


L>Действительно не работает, но похоже, что это все-таки ошибка программирования, а не логики :)


@#$%, блин. отправил раньше времени.


Сейчас вот пытаюсь обдумать такой вариант:
int cnt=0;
for(int i=0;i<size_of_a;i++)
{
   if(!cnt) num=a[i];
   if(a[i]!=num) cnt--;
   else cnt++;
}
Re[11]: Задачка
От: Vitalische  
Дата: 04.10.01 09:26
Оценка:
Sorry, в программе ошибка (писал без компьютера );


int cnt = 0;
for ( int i = 0; i < a.size(); ++i ) 
{ 
  if ( cnt > 0 && a[i] != num ) 
    --cnt; 
  else 
  {
    ++cnt; 
   if ( cnt == 1 ) 
     num = a[i]; 
  } 
}



2 Андрей Тарасевич
>"Когда говорят "за один проход" имеется в виду — за O(N) операций. В твоем варианте понадобится порядка O(N) + O
>(M) операций, где M — длина массива счетчиков.".

Уважаемый "Brainbench C and C++ Programming MVP". Будьте добры разобраться в том, что написано, прежде чем писать о каком-то "массиве счетчиков", которого нет. Дополнительных массивов НЕТ. a[] — исходный массив с числами.

2Lexey.
По-моему, твой вариант будет работать. Решение короче и симпатичнее, чем у меня :)).
Re[12]: Задачка
От: Lexey Россия  
Дата: 04.10.01 09:36
Оценка:
Здравствуйте Vitalische, вы писали:

V>2 Андрей Тарасевич

>>"Когда говорят "за один проход" имеется в виду — за O(N) операций. В твоем варианте понадобится порядка O(N) + O(M) операций, где M — длина массива счетчиков.".
V>Уважаемый "Brainbench C and C++ Programming MVP". Будьте добры разобраться в том, что написано, прежде чем писать о каком-то "массиве счетчиков", которого нет. Дополнительных массивов НЕТ. a[] — исходный массив с числами.

Да ладно, не горячись. Это он про мой исходный вариант с дополнительным массивом написал. :)

V>2Lexey.

V>По-моему, твой вариант будет работать. Решение короче и симпатичнее, чем у меня :)).

Должен. Он получается из твоего, если if разбить на две части. :)
Re[12]: Задачка
От: Vitalische  
Дата: 04.10.01 09:37
Оценка:
2 Андрей Тарасевич

Чёрт, каюсь и посыпаю голову пеплом. Сам не разобрался кто, кому и что написал. Ещё раз извиняюсь.
Re[4]: Задачка
От: Андрей Тарасевич Беларусь  
Дата: 04.10.01 14:27
Оценка:
Здравствуйте Lexey, вы писали:

L>Ну давай еще поспорим. За один проход, может означать только именно за один проход по исходному массиву. Никаких других требований на сложность это не накладывает.


Ну ну ну! Если так подходить к требованию "за один проход", то тогда собственно и решать нечего: скопируй исходный массив в такой же отдельный массив (это делается за один проход), а затем уже делай все что угодно с копией. Хоть сто раз ее просматривай — все равно задача будет решена "за один проход" исходного массива...
Best regards,
Андрей Тарасевич
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.