Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет Oleg Izhvanov ([info]izh) в [info]programming
@ 2007-06-24 19:27:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Простая задачка (с красивым решением)
Имеется последовательность из N объектов,
про любые два из которых можно сказать только
равны они или нет. Известно, что некоторого
объекта в последовательности больше половины.
Придумать алгоритм поиска этого объекта,
который бы завершался за один проход по
последовательности и использовал фиксированный
(то есть не зависящий от N) объем памяти.

Комменты скринятся.

Пояснение:

Понятно, что количество бит, при помощи которых
можно закодировать число N зависит от N, но
конкретно этой зависимостью можно пренебречь.
Также понятно, что от размера объекта зависит
объем используемой памяти. Этой зависимостью можно
также пренебречь. Существенно, чтобы количество
используемой памяти не зависело от количества
элементов в последовательности.

Решение (выделить мышкой):

Одно из возможных решений основывается на том
интересном факте, что из последовательности
можно выкинуть 3 произвольных попарно неравных
элемента. При этом количество искомых элементов
по прежнему будет больше половины в уменьшенной
последовательности. Другое решение (более простое),
предложенное Димой Калединым, также использует 
индукцию. Понять, как именно, предоставляется 
читателю в качестве упражнения.

Для простоты в решении рассматривается массив из
целых чисел. Алгоритмы, впрочем, будут работать для
любых объектов.

Мой вариант решения:

int find_most_repeatable(int *arr, size_t size)
{
    unsigned int        i;
    int                 a, b = 0, e, answer_a, answer_b, answer;

    answer_a = arr[0];
    a = 1;
    
    for (i = 1; i < size; i ++)
    {
        e = arr[i];
    
        if (answer_a == e && a > 0)
            a ++;
        else if (answer_b == e && b > 0)
            b ++;
        else
        {
            if (a == 0)
            {
                answer_a = e;
                a = 1;
                continue;
            }
            else if (b == 0)
            {
                answer_b = e;
                b = 1;
                continue;
            }

            a --; b --;
        }
    }

    if (a >= b)
        answer = answer_a;
    else
        answer = answer_b;
    
    return answer;
}

Вариант Димы Каледина (исправленный):

int find_most_repeatable2(int *arr, size_t size)
{
    unsigned int        i;
    int                 answer, e, c;
    
    answer = arr[0];
    c = 0; 
    for (i = 1; i < size; i ++)
    {
        e = arr[i];

        if (answer == e)
        {
            c ++;
            if (c <= 0)
                c ++;
        }
        else if (c >= 0)
            c --;

        if (c < 0)
            answer = e;
    }

    return answer;
}



(Читать комментарии) - (Добавить комментарий)


[info]666
2007-06-25 12:17 (ссылка)
но если к кажому из элементов массива
можно обращаться только 1 раз,
то это противоречит условию:
"про любые два из которых можно сказать только
равны они или нет"

так как сравнивая 1й и 2й элементы,
я уже обращаюсь к каждому из них по 1-му разу,
и таким образом уже не могу сравнить ни один из них с 3-м.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]izh
2007-06-25 12:25 (ссылка)
>но если к кажому из элементов массива
>можно обращаться только 1 раз,
>то это противоречит условию:
>"про любые два из которых можно сказать только
>равны они или нет"

Разумеется нет. Например, Вы можете запомнить
(скопировать) один из элементов и сравнить его
с любым другим. Грубо говоря, Вам дана функция
(предикат), которая на входе имеет два объекта,
а на выходе булево значение "равны/неравны".

>так как сравнивая 1й и 2й элементы,
>я уже обращаюсь к каждому из них по 1-му разу,
>и таким образом уже не могу сравнить ни один
>из них с 3-м.

Кто Вам мешает запомнить эти три элемента?
В условии нет ограничения на запоминание
трех элементов -- там всего лишь есть требование
незавимости используемого объема памяти от
количества элементов в массиве.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]666
2007-06-25 12:32 (ссылка)
понятно, то есть значения элементов доступны

(Ответить) (Уровень выше)


[info]izh
2007-06-25 12:45 (ссылка)
Пардон, не в массиве, а в последовательности.

(Ответить) (Уровень выше)


(Читать комментарии) -