avva: (Default)
[personal profile] avva
Хорошая программистская задачка:

Дан список с данными. И есть подозрение, что более половины элементов в списке - это один и тот же элемент (число, например). Требуется определить, так ли это, и если так — то что это за элемент и сколько раз он встречается. За линейное время и без дополнительной памяти. (кроме константы).

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

P.S. Есть разные способы решения (я нашёл один из них, но не лучший, как потом узнал). Если из алгоритма неочевидно, что он всегда работает, нужно это доказать, иначе решение неполное.

Date: 2004-07-11 06:30 pm (UTC)
From: [identity profile] flashkot.livejournal.com
можно ли модифицировать список данных (сортировать)?

Date: 2004-07-11 06:36 pm (UTC)
From: [identity profile] avva.livejournal.com
Всё равно ведь невозможно отсортировать за линейное время.
Но в принципе в условии задачи не сказано, можно ли модифицировать список. Ясно, что лучше обойтись без модификации, но я не скажу, можно без неё обойтись или нельзя ;)

(no subject)

From: [identity profile] flashkot.livejournal.com - Date: 2004-07-11 06:49 pm (UTC) - Expand

Date: 2004-07-11 06:44 pm (UTC)
From: [personal profile] alll
Нельзя ли уточнить, что значит "без дополнительной памяти. (кроме константы)." Константным подразумевается число дополнительных переменных или ничем кроме исходного массива и некоей константы нельзя пользоваться? Или нечто иное?

Date: 2004-07-11 06:47 pm (UTC)
From: [identity profile] avva.livejournal.com
Размер дополнительной памяти, которой можно пользоваться - константа, т.е. не зависит от размера исходного списка. Это может быть какое-то фиксированное число дополнительных переменных, или дополнительный массив фиксированного размера, итп.

(no subject)

From: [identity profile] french-man.livejournal.com - Date: 2004-07-11 06:50 pm (UTC) - Expand

(no subject)

From: [identity profile] avva.livejournal.com - Date: 2004-07-11 06:58 pm (UTC) - Expand

(no subject)

From: [identity profile] french-man.livejournal.com - Date: 2004-07-11 06:57 pm (UTC) - Expand

Date: 2004-07-11 06:49 pm (UTC)
From: [identity profile] french-man.livejournal.com
Да, меня это тоже смутило. Уже "сколько раз встречается" - число, для записи которого константы не хватит.

Date: 2004-07-11 07:21 pm (UTC)
From: [identity profile] dmitryle.livejournal.com
Если такое число существует, то оно median (как оно по-русски называется?). Говорят (в сети), что есть линейный метод нахождения median. Находим (за линейное время) и проверяем (также за линейное время).

Date: 2004-07-11 07:33 pm (UTC)
From: [identity profile] avva.livejournal.com
Остроумно! ;-)

Но требует дополнительной памяти, линейной от размера исходного списка (для хранения промежуточных данных во время рекурсивных вызовов алгоритма для нахождения медианы).

(no subject)

From: [identity profile] arbat.livejournal.com - Date: 2004-07-11 09:13 pm (UTC) - Expand

(no subject)

From: [identity profile] avva.livejournal.com - Date: 2004-07-12 03:14 am (UTC) - Expand

(no subject)

From: (Anonymous) - Date: 2004-07-14 01:44 am (UTC) - Expand

Hotja net, ne prav

From: (Anonymous) - Date: 2004-07-14 02:24 am (UTC) - Expand
(deleted comment)

Date: 2004-07-11 07:27 pm (UTC)
From: [identity profile] french-man.livejournal.com
Сумма квадратична, извините.

(no subject)

From: [personal profile] alll - Date: 2004-07-11 07:30 pm (UTC) - Expand

Date: 2004-07-11 07:52 pm (UTC)
From: [personal profile] alll
Еще уточнение, если не затруднит: для элементов списка существуют операции "больше"/"меньше"? или только "равно"?

Date: 2004-07-11 08:35 pm (UTC)
From: [identity profile] avva.livejournal.com
Можно делать больше/меньше при желании.

Date: 2004-07-11 08:02 pm (UTC)
From: [identity profile] dyak.livejournal.com
Для четного количества в списке.
Если разделить список на пары, то если член "х" –– большинство, то, если искомый член "х" есть, то, если пары, где члены разные, повыкидывать, то
число пар, где оба члена –– "х" должно быть больше, чем число пар, где оба члена –– "не х". Как предельный случай можно поиграть со списком их а+1 белых и а–1 черных.

Значит действуем так: игнорируем все смешанные пары и ставим счетчик на 0. Идем до первой одинаковой пары, замечаем ее члены как кандидата на большинство, ставим счетчик на 1. Если следующая одинаковая пара такая же, то увеличиваем счетчик на 1, если она другая, вычитаем из счетчика 1. Если счетчик оказывается на 0, то следующая одинаковая пара дает нам кандидата и 1 в счетчике.

В процессе узнаем сколько членов в списке.

Если в конце процесса имеем не 0 в счетчике и кандидата, то на следующем прогоне считаем сколько найдем кандидата в списке. Если >50%, ура.

На нечетное число членов тривиально распространимо, но писать лень.

Date: 2004-07-11 08:20 pm (UTC)
From: [personal profile] alll
А сколько потребуется "прогонов" в самом худшем случае?

(no subject)

From: [identity profile] dyak.livejournal.com - Date: 2004-07-11 08:23 pm (UTC) - Expand

(no subject)

From: [personal profile] alll - Date: 2004-07-11 08:25 pm (UTC) - Expand

(no subject)

From: [identity profile] dyak.livejournal.com - Date: 2004-07-11 08:30 pm (UTC) - Expand

(no subject)

From: [personal profile] alll - Date: 2004-07-11 08:42 pm (UTC) - Expand

(no subject)

From: [identity profile] dyak.livejournal.com - Date: 2004-07-11 08:49 pm (UTC) - Expand

(no subject)

From: [personal profile] alll - Date: 2004-07-11 08:43 pm (UTC) - Expand

(no subject)

From: [identity profile] dyak.livejournal.com - Date: 2004-07-11 08:50 pm (UTC) - Expand

(no subject)

From: [personal profile] alll - Date: 2004-07-11 08:57 pm (UTC) - Expand

(no subject)

From: [identity profile] dyak.livejournal.com - Date: 2004-07-11 08:59 pm (UTC) - Expand

(no subject)

From: [identity profile] dmitryle.livejournal.com - Date: 2004-07-11 08:44 pm (UTC) - Expand

(no subject)

From: [identity profile] dyak.livejournal.com - Date: 2004-07-11 08:58 pm (UTC) - Expand

(no subject)

From: [personal profile] alll - Date: 2004-07-11 08:58 pm (UTC) - Expand

(no subject)

From: [identity profile] dyak.livejournal.com - Date: 2004-07-11 09:01 pm (UTC) - Expand

(no subject)

From: [personal profile] alll - Date: 2004-07-11 09:53 pm (UTC) - Expand

(no subject)

From: [identity profile] dmitryle.livejournal.com - Date: 2004-07-11 09:01 pm (UTC) - Expand

Ага, уразумел

From: [personal profile] alll - Date: 2004-07-11 09:52 pm (UTC) - Expand

(no subject)

From: (Anonymous) - Date: 2004-07-12 03:08 am (UTC) - Expand

(no subject)

From: [identity profile] avva.livejournal.com - Date: 2004-07-12 03:11 am (UTC) - Expand

(no subject)

From: [identity profile] avva.livejournal.com - Date: 2004-07-12 03:13 am (UTC) - Expand

(no subject)

From: [identity profile] oblomov-jerusal.livejournal.com - Date: 2004-07-12 02:38 am (UTC) - Expand

(no subject)

From: [identity profile] avva.livejournal.com - Date: 2004-07-12 03:10 am (UTC) - Expand

(no subject)

From: [identity profile] oblomov-jerusal.livejournal.com - Date: 2004-07-12 03:45 am (UTC) - Expand

(no subject)

From: [identity profile] avva.livejournal.com - Date: 2004-07-12 04:09 am (UTC) - Expand

(no subject)

From: [identity profile] oblomov-jerusal.livejournal.com - Date: 2004-07-12 04:30 am (UTC) - Expand

(no subject)

From: [identity profile] avva.livejournal.com - Date: 2004-07-12 06:03 am (UTC) - Expand

(no subject)

From: [identity profile] oblomov-jerusal.livejournal.com - Date: 2004-07-12 06:08 am (UTC) - Expand

(no subject)

From: [identity profile] avva.livejournal.com - Date: 2004-07-12 03:13 am (UTC) - Expand

(no subject)

From: [identity profile] dyak.livejournal.com - Date: 2004-07-12 05:38 am (UTC) - Expand

(no subject)

From: [identity profile] dyak.livejournal.com - Date: 2004-07-12 05:55 am (UTC) - Expand

Date: 2004-07-11 10:22 pm (UTC)
From: [identity profile] ex-ilyavinar899.livejournal.com
Я намеренно не смотрю на остальные комментарии.

Одно слово: хэширование.

Date: 2004-07-11 10:46 pm (UTC)
From: [identity profile] dmitryle.livejournal.com
Hash is not deterministic - what if all the values are in the same bucket?

(no subject)

From: [identity profile] wildernesscat.livejournal.com - Date: 2004-07-12 12:52 am (UTC) - Expand

Date: 2004-07-12 01:14 am (UTC)
From: [identity profile] oblomov-jerusal.livejournal.com
Если на элементах задана операция сравнения и разрешается переупорядочивать список, то легко модифицировать стандартный алгоритм поиска элемента. Выбираем случайный элемент a, проходим по списку, составляем 2 списка: больших a и меньших или равных a. Выбираем больший из двух списков и продолжаем с ним работать. Если хотим детерминистский алгоритм, то из каждых 5 элементов выбираем медианный, находим медиану всех выбранных, и найденный элемент используем как a(OK, это уже не постоянная память)

Date: 2004-07-12 01:44 am (UTC)
From: [identity profile] oblomov-jerusal.livejournal.com
Пусть элемент представлен строкой в k бит. Проходим по списку, считаем, сколько раз встречается старший бит 0. Выбираем тот, что встречается чаще. На шагу i мы имеем i-1 старших бит элемента, и мы проходим по списку и считаем, сколько раз встречается 0 и 1 после этих i-1 бит, и определяем на основе подсчета бит i. (естественно, вместо бита можем пользоваться более крупной единицей, напр. байтом).

Date: 2004-07-12 03:09 am (UTC)
From: [identity profile] avva.livejournal.com
Да, так тоже можно.

(no subject)

From: [identity profile] mi-b.livejournal.com - Date: 2004-07-12 03:30 am (UTC) - Expand

(no subject)

From: [identity profile] avva.livejournal.com - Date: 2004-07-12 03:39 am (UTC) - Expand

(no subject)

From: [identity profile] mi-b.livejournal.com - Date: 2004-07-12 04:07 am (UTC) - Expand

(no subject)

From: [identity profile] avva.livejournal.com - Date: 2004-07-12 04:14 am (UTC) - Expand

улучшение, вроде

From: (Anonymous) - Date: 2004-07-13 03:51 pm (UTC) - Expand

(no subject)

From: [identity profile] avva.livejournal.com - Date: 2004-07-13 03:58 pm (UTC) - Expand

Nemnogo drugoe reshenie. Nabrosok idei

Date: 2004-07-12 04:22 am (UTC)
From: (Anonymous)
2 prohoda vdol' spiska.
Voz'mem nebol'shoj massiv (naprimer 10 elementov). Kazhdyj element massiva - para: element-chastota elementa. Budem zapisyvat' v nego elementi po mere postuplenia a zaodno i schitat' ih kolichestvo (chastotu). Kak tol'ko nam vstretit'sja 11-i element, nachnem zapolnjat' vtoroj takoj zhe massiv. Kogda vtoroj massiv okazhetsja zapolnennym, soljem dva massiva v odin, t.e. vyberem iz 20 elementov 10 s maksimal'nymi chastotami. Ochistim vtoroj massiv i stanem zapolnjat' ego snova, poka nam opjat' ne popadetsja 11-i element. Opjat' soljem 2 massiva (ili viberem 10 maksimalnih) i t.d. V konce u nas budet iskomyj element odnim iz 10 v pervom massive. Teper' delaem eshe odin prohod, podschityvaja chastoty tol'ko etih 10 elementov - i togda u nas budet okonchatel'nyj otvet.
Vozmozhno 10 elementov - dazhe bol'she chem nuzhno. Vpolne verojatno 2-3 dostatochno.
Algoritm rabotaet, dazhe esli elementy - ne chisla i predstavit' ih v vide korotkoj stroki ne predstavljaetsja vozmozhnym.
Ne znaju poka kak obosnovat', no dumaju chto esli element zanimaet bol'she poloviny spiska, to ego nevozmozhno raspredeli't po spisku takim obrazom, chtobi on ne popal v okonchatel'nyj massiv.

Date: 2004-07-12 04:23 am (UTC)
From: [identity profile] etonei.livejournal.com
Есть у меня вот какое бездоказательное подозрение.

Для удобства рассмотрим этот список как кольцо (мысленно замкнем начало с концом). Если значение X встречается больше чем в 50% элементов, то в кольце обязательно будут последовательности подряд идущих X-ов, причем длина максимальной такой цепочки будет больше всех других последовательностей подряд идущих одинаковых элементов.

За один проход находим максимальную цепочку одинаковых значений X, за второй - убеждаемся, действительно ли X-ов больше 60% в списке.

Date: 2004-07-12 04:37 am (UTC)
From: [identity profile] etonei.livejournal.com
Ooops, не работает :(

Date: 2004-07-12 05:17 am (UTC)
From: [identity profile] scolar.livejournal.com
Любимая моя задачка про инварианты: если выкинуть два любых различных элемента, то решение новой задачи совпадает с решением исходной.

Date: 2004-07-12 10:55 am (UTC)
From: [identity profile] lom.livejournal.com
ык... упрощeнный коррeляционный фильтр.

Гeнeрируются случайная послeдоватeльность ( можно - по кругу, eсли выборка конeчная - с остатком от дeлeния по модулю N ) с попарным
сравнeниeм номeров, совпали + 1, нe совпали: -1, вeдeм сумму и сравниваeм с заранee выбранной константой...

Date: 2004-07-12 02:26 pm (UTC)
From: [identity profile] ex-ilyavinar899.livejournal.com
У меня есть подозрение, что если одно значение составляет больше половины элементов списка, то у него будут самая длинная последовательность, состоящая из одного значения.

Date: 2004-07-12 02:32 pm (UTC)
From: [identity profile] avva.livejournal.com
У меня есть подозрение, что если одно значение составляет больше половины элементов списка, то у него будут самая длинная последовательность, состоящая из одного значения.

Нет:

1 1 1 2 2 3 2 2 3 2 2 3 2 2 3
(deleted comment)

Date: 2004-07-12 02:31 pm (UTC)
From: [identity profile] avva.livejournal.com
Скоро напишу отдельную запись.

Date: 2004-07-12 02:43 pm (UTC)
From: [identity profile] ex-ilyavinar899.livejournal.com
А! Это же задачка о микрочипах, друг друга тестирующих, из CLR!

(no subject)

From: [identity profile] ex-ilyavinar899.livejournal.com - Date: 2004-07-12 04:10 pm (UTC) - Expand

(no subject)

From: [identity profile] ex-ilyavinar899.livejournal.com - Date: 2004-07-12 04:14 pm (UTC) - Expand

(no subject)

From: [identity profile] french-man.livejournal.com - Date: 2004-07-13 11:16 am (UTC) - Expand

(no subject)

From: [identity profile] avva.livejournal.com - Date: 2004-07-13 11:21 am (UTC) - Expand

(no subject)

From: [identity profile] french-man.livejournal.com - Date: 2004-07-13 11:35 am (UTC) - Expand

(no subject)

From: [identity profile] avva.livejournal.com - Date: 2004-07-13 02:50 pm (UTC) - Expand

Date: 2004-07-12 04:17 pm (UTC)
From: [identity profile] iliat.livejournal.com
Da ya tozhe w etu storonu dumal - ochen soblaznitelno.
Dokazatelstwo otloszhil a tut i kontr-primer nashelsya.
Nedarom avva kogda-to pisal kak ostorozhno nuzno otnsoistsya k swoej intiuicii.

Date: 2004-07-12 04:18 pm (UTC)
From: [identity profile] iliat.livejournal.com
Sorry, hotel zapistit eto w otwet na komment Ilyi.

Date: 2004-07-13 09:46 am (UTC)
From: [identity profile] shulga.livejournal.com
Как ни крути, хоть медианы, хоть побитная проверка - всё одно и тоже.
Если объекты однобитные +1 и -1, тогда N if'ов и N операций (например, суммирования).
IFы нужны, собственно, если они НЕ +1 и -1.
Если битов в объекте K, тогда в К раз больше работы.
Предполагается простейший набор команд процессора.

Date: 2004-07-17 06:07 pm (UTC)
From: [identity profile] kroman139.livejournal.com
Хны, я тоже вначале думал о парах-непарах. Потом перешел к битикам, объединил их в группы и пришел к байтам-двойным байтам.

Пускай мы будем работать с двубайтными значениями (16 бит, 64 К значений). Заводим дополнительный массив размером 256 Кб (64К * 4 байта), сбрасываем все в нолики.

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

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

Если это число меньше или равно половине количества элементов в последовательности, то говорим "решения нет".

В противном случае запоминаем егойный индекс ("subValue", что представляет собой значение младших 16 бит нашего "подозрительного" числа).

Опять обнуляем доп-массив и бежим по нашей последовательности. Но теперь обрабатываем (а) только те элементы, у которых младшие 16 бит равны "subValue" и (б) в качестве "индекса" используем старшие 16 бит.

Снова бежим по доп-массиву и ищем самое большое число.

Если его находим и оно больше половины количества элементов, то получаем решение, в противном случае - "решения нет".

*******
Если кому-то кажется, что 256 Кб на доп-массив - это слишком много, то есть одно объяснение и один обходной маневр.

Объяснение: мне нравится работать или думать об очень больших последовательностях. Которые, например, могут занимать 4-8 Гб (до 2 миллиардов значений). В этом случае наши дополнительные затраты выглядят весьма смешными, зато скорость повышается достаточно сильно (потому что всего два обхода последовательности).

Обходной маневр: будем работать с байтами. Правда, получается до 4х итераций по нашей последовательности, зато затраты на дополнительную память уменьшаются до 1 Кб (не считая нескольких переменных для хранения индекстов, "subValue" и так далее).

*******
Конечно, если вдруг в нашей последовательности будет более 4 миллиардов значений, элементы доп-массива должны иметь разрядность более 32 бит (дабы не произошло перехода через 0). Но и это обходится - будем занимать не 256 Кб, а 512.

Date: 2004-07-18 04:44 pm (UTC)
From: [identity profile] avva.livejournal.com
В общем, выглядит правильно, но вполне можно обходить по битам, а не группам из 16 бит; будет в 16 раз больше обходов, ну и что? время всё равно линейное. В этой форме Ваше решение идентично предложенному [livejournal.com profile] oblomov_jerusal выше.

(no subject)

From: [identity profile] kroman139.livejournal.com - Date: 2004-07-18 09:50 pm (UTC) - Expand

Date: 2004-08-02 04:39 am (UTC)
From: [identity profile] bot-tak.livejournal.com
$sum = 0;
$candidate = 0;
foreach ($numbers as $n)
{
$sum += $n;
if (!isset($min_diff)) $min_diff = $n;
$diff = ($sum / count($sum) - $n);
if ($diff <= $min_diff)
{
$candidate = $n;
$min_diff = $diff;
}
}

echo $candidate;

Набросок идей. Практическую ценность не проверял

December 2025

S M T W T F S
  123 4 56
78 9 10 11 1213
1415 1617181920
21 22 23 24 2526 27
2829 30 31   

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 2nd, 2026 06:55 am
Powered by Dreamwidth Studios