Re[5]: Решение за O(N) и доп. память O(N)
От: dilmah США  
Дата: 04.04.10 09:06
Оценка:
A>Резюме: использование хешированного списка (например, Dictionary в C#) является решением задачи за время O(N) и доп. память O(N).

не понимаю. Если сделать хэш размером N, то коллизии хэшей убьют O(1) доступ, и реально будет тот же логарифм.
Чтобы сохранить O(1) (в среднем) доступ нужен хэш размером N*lgN, опять таки вылазит логарифм.
Re[6]: Поиск повторяющегося числа в массиве
От: batu Украина  
Дата: 04.04.10 14:00
Оценка:
Здравствуйте, Xobotik, Вы писали:


X>Да все я понял, под сравнениями я имел ввиду >, <, <=, >=. Я просто решил задачу в пятницу, захожу сюда, чтобы отписаться вчера, а тут вы решение уже сказали, обидно блин. Такое ощущение, что не сам догадался.

Та ладно.. Фигня все это. Развлекаемся.
Re[6]: Поиск повторяющегося числа в массиве
От: batu Украина  
Дата: 04.04.10 14:12
Оценка:
Здравствуйте, dilmah, Вы писали:

D>тебе нужно проинициализировать нулями массив размером M. Формально это O(M), если забыть о трюках с paged memory management

Формально да. Есть языки, которые не требуют инициализации.. А так ты прав
Re: Поиск повторяющегося числа в массиве
От: frogkiller Россия  
Дата: 04.04.10 14:19
Оценка: +1
Здравствуйте, Xobotik, Вы писали:

X>Условие задачи:

X>Дан массив размера N из целых чисел, принимающих значения от 1 до M, при этом одно
X>число в этом массиве повторяется два раза. Найти это число за время O(N).

Странно, что никто не предложил такой вариант: lexical sort (=O(N*log(M))) + ещё один проход для сравнения соседних элементов (=O(N)).
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re[2]: Поиск повторяющегося числа в массиве
От: samius Япония http://sams-tricks.blogspot.com
Дата: 04.04.10 14:31
Оценка:
Здравствуйте, frogkiller, Вы писали:

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


F>Странно, что никто не предложил такой вариант: lexical sort (=O(N*log(M))) + ещё один проход для сравнения соседних элементов (=O(N)).


Что-то я не понял откуда в lexical sort оценка O(N*log(M))

radix sort для Int32 займет O(4*N). Т.е. формально за O(N) с дополнительной памятью O(C).
Re[3]: Поиск повторяющегося числа в массиве
От: dilmah США  
Дата: 04.04.10 16:13
Оценка: 1 (1)
S>Что-то я не понял откуда в lexical sort оценка O(N*log(M))

S>radix sort для Int32 займет O(4*N). Т.е. формально за O(N) с дополнительной памятью O(C).


ну вот эта четверка это и есть log(M) -- другими словами -- количество бит в сортируемых числах
Re[5]: Решение за O(N) и доп. память O(N)
От: Xobotik Россия  
Дата: 04.04.10 20:17
Оценка: 3 (1)
Здравствуйте, andy1618, Вы писали:

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


A>>В C# это называется Dictionary<T>. Если правильно указать ёмкость словарика при инициализации (M), то алгоритм будет работать за время O(N). Но есть один нюанс — отожрётся памяти O(M), что в подобных задачах обычно считается неприемлемым (ибо тогда это эквивалентно заведению простого вспомогательного массива из M элементов, после чего задача становится тривиальной).


A>Упс, ошибся! Ведь M может быть очень велико и существенно превышать N (например, M=2^64, N=1000), а для шустрой работы хешированного словарика вполне достаточно памяти порядка O(N).

A>Резюме: использование хешированного списка (например, Dictionary в C#) является решением задачи за время O(N) и доп. память O(N).

Да вы правы Словари решают задачу за O(N)

            public int GetDuplicateNumber(int[] array)
            {
                Dictionary<int, int> dictionary = new Dictionary<int, int>(array.Length);
                foreach (int i in array) // O(N)
                {
                    if (dictionary.ContainsKey(i)) // Этот метод является операцией порядка сложности O(1)
                    {
                        return i;
                    }
                    else
                    {
                        dictionary.Add(i, 0); // O(1) размер словаря, равен размеру массива, размер не увеличивается
                    }
                }
                return 0;
                // результат: O(N*1*1) = O(N) 
            }
С уважением!
Re[6]: Решение за O(N) и доп. память O(N)
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 04.04.10 20:28
Оценка: 3 (1)
Здравствуйте, dilmah, Вы писали:

D>не понимаю. Если сделать хэш размером N, то коллизии хэшей убьют O(1) доступ, и реально будет тот же логарифм.


Не будет, посчитай. К тому же, хэш можно сделать размером kN для любого положительного k.
Ce n'est que pour vous dire ce que je vous dis.
Re[6]: Решение за O(N) и доп. память O(N)
От: Xobotik Россия  
Дата: 04.04.10 20:34
Оценка:
Здравствуйте, dilmah, Вы писали:

A>>Резюме: использование хешированного списка (например, Dictionary в C#) является решением задачи за время O(N) и доп. память O(N).


D>не понимаю. Если сделать хэш размером N, то коллизии хэшей убьют O(1) доступ, и реально будет тот же логарифм.

D>Чтобы сохранить O(1) (в среднем) доступ нужен хэш размером N*lgN, опять таки вылазит логарифм.

Я так долго копил баллы, за что -1 то? Я метод делал строго по документации MSDN.

О методе ContainsKey:
здесь]

В заметках написано: Этот метод является операцией порядка сложности O(1).

О вставки в словарь:
здесь

В заметках написано о сложности вставки.
С уважением!
Re[7]: Решение за O(N) и доп. память O(N)
От: dilmah США  
Дата: 04.04.10 21:01
Оценка: +2
D>>не понимаю. Если сделать хэш размером N, то коллизии хэшей убьют O(1) доступ, и реально будет тот же логарифм.

DR>Не будет, посчитай. К тому же, хэш можно сделать размером kN для любого положительного k.


ок, согласен, посчитал количество коллизий стремится к распределению пуассона, так что в среднем константный оверхед.
Но все равно, зависимость от M спрятана неявно -- в вычислении хэша.
Re[6]: Решение за O(N) и доп. память O(N)
От: Xobotik Россия  
Дата: 04.04.10 22:36
Оценка:
Здравствуйте, Xobotik, Вы писали:

Только не так:
X>
X>            public int GetDuplicateNumber(int[] array)
X>            {
X>                Dictionary<int, int> dictionary = new Dictionary<int, int>(array.Length);
X>                foreach (int i in array) // O(N)
X>                {
X>                    if (dictionary.ContainsKey(i)) // Этот метод является операцией порядка сложности O(1)
X>                    {
X>                        return i;
X>                    }
X>                    else
X>                    {
X>                        dictionary.Add(i, 0); // O(1) размер словаря, равен размеру массива, размер не увеличивается
X>                    }
X>                }
X>                return 0;
X>                // результат: O(N*1*1) = O(N) 
X>            }
X>


а вот так:
        public int GetDuplicateNumber(int[] array)
        {
            Dictionary<int, int> dictionary = new Dictionary<int, int>(array.Length);
            for (int i = 0; i < array.Length; i++)
            {
                if (dictionary.ContainsKey(array[i]))
                {
                    return array[i];
                }
                else
                {
                    dictionary.Add(array[i], i); // ключи словаря - это значения массива, а значения словаря - это шаг цикла for
                }
            }
            return 0;
        }
С уважением!
Re[8]: Решение за O(N) и доп. память O(N)
От: samius Япония http://sams-tricks.blogspot.com
Дата: 05.04.10 03:15
Оценка:
Здравствуйте, dilmah, Вы писали:

D>Но все равно, зависимость от M спрятана неявно -- в вычислении хэша.


Можно развернуть мысль?
Re[9]: Решение за O(N) и доп. память O(N)
От: dilmah США  
Дата: 05.04.10 07:14
Оценка: 1 (1) +2
D>>Но все равно, зависимость от M спрятана неявно -- в вычислении хэша.

S>Можно развернуть мысль?


ну в исходной задаче было озвучено 2 параметра: N и M.
Решение с хэшом имеет сложность O(N) только в предположении, что M не превышает некого фиксированного числа, скажем UINT64_MAX
Но так как M тоже является параметром, то формально сложность равна O(N*log(M)), потому что чем больше M, тем больше бит в числах.
Re[7]: Решение за O(N) и доп. память O(N)
От: Буравчик Россия  
Дата: 05.04.10 08:57
Оценка:
Здравствуйте, Xobotik, Вы писали:

X>
X>        public int GetDuplicateNumber(int[] array)
X>        {       ...
X>                    dictionary.Add(array[i], i); // ключи словаря - это значения массива, а значения словаря - это 
X>                ...
X>        }
X>


Раз уж начали использовать готовые контейнеры, осталось понять, зачем запоминать в словарь помимо ключа еще и значение (в данном случае i), которое в дальнейшем не используется.

Ведь это:
1. Запутывает код.
2. Увеличивает требования к памяти.
Best regards, Буравчик
Re[8]: Решение за O(N) и доп. память O(N)
От: andy1618 Россия  
Дата: 06.04.10 00:41
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Раз уж начали использовать готовые контейнеры, осталось понять, зачем запоминать в словарь помимо ключа еще и значение (в данном случае i), которое в дальнейшем не используется.


Это да. Вообще говоря, решение через стандартные хеш-словари не очень интересное, любопытно было бы найти какой-то изящный алгоритм. Например, если бы задача звучала "Все числа повторяются по 2 раза, кроме искомого", то обычный побитовый XOR решал бы задачу за O(N) вообще без дополнительной памяти.
Re[8]: Решение за O(N) и доп. память O(N)
От: Xobotik Россия  
Дата: 06.04.10 09:59
Оценка: -1
Здравствуйте, Буравчик, Вы писали:

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


X>>
X>>        public int GetDuplicateNumber(int[] array)
X>>        {       ...
X>>                    dictionary.Add(array[i], i); // ключи словаря - это значения массива, а значения словаря - это 
X>>                ...
X>>        }
X>>


Б>Раз уж начали использовать готовые контейнеры, осталось понять, зачем запоминать в словарь помимо ключа еще и значение (в данном случае i), которое в дальнейшем не используется.


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

Б>Ведь это:

Б>1. Запутывает код.

Отнюдь.

Б>2. Увеличивает требования к памяти.


Увеличивает на парочку бит
С уважением!
Re[9]: Решение за O(N) и доп. память O(N)
От: Xobotik Россия  
Дата: 06.04.10 10:02
Оценка:
Здравствуйте, andy1618, Вы писали:

A>Здравствуйте, Буравчик, Вы писали:


Б>>Раз уж начали использовать готовые контейнеры, осталось понять, зачем запоминать в словарь помимо ключа еще и значение (в данном случае i), которое в дальнейшем не используется.


A>Это да. Вообще говоря, решение через стандартные хеш-словари не очень интересное, любопытно было бы найти какой-то изящный алгоритм. Например, если бы задача звучала "Все числа повторяются по 2 раза, кроме искомого", то обычный побитовый XOR решал бы задачу за O(N) вообще без дополнительной памяти.


Да задачу (стартовую) решили уже без применения каких-то сложных структур:

здесь
Автор: Xobotik
Дата: 03.04.10

private static int foo(int[] a)
        {
            int buf = 0;
            int[] b = new int[a.Length];
            for (int i = 0; i < a.Length; i++)
            {
                if (b[a[i]] == 0)
                {
                    b[a[i]] = a[i];
                }
                else
                {
                    buf = a[i];
                    return buf;
                }
            }
            return buf;
        }


Теперь просто пытаемся найти еще другие методы решения задачи.
С уважением!
Re: Поиск повторяющегося числа в массиве
От: _FRED_ Черногория
Дата: 06.04.10 10:16
Оценка:
Здравствуйте, Xobotik, Вы писали:

X>Условие задачи:

X>Дан массив размера N из целых чисел, принимающих значения от 1 до M, при этом одно
X>число в этом массиве повторяется два раза. Найти это число за время O(N).

Весь топик не читал, боясь встретить подсказки, а связи нейронные наростить надо бы, ибо вчера была кушал водку

Правиьно ли я понимаю, что только указанного условия достаточно для решения? То есть
?
Help will always be given at Hogwarts to those who ask for it.
Re[9]: Решение за O(N) и доп. память O(N)
От: Xobotik Россия  
Дата: 06.04.10 10:16
Оценка:
Здравствуйте, andy1618, Вы писали:

A>Здравствуйте, Буравчик, Вы писали:


Б>>Раз уж начали использовать готовые контейнеры, осталось понять, зачем запоминать в словарь помимо ключа еще и значение (в данном случае i), которое в дальнейшем не используется.


A>Это да. Вообще говоря, решение через стандартные хеш-словари не очень интересное, любопытно было бы найти какой-то изящный алгоритм. Например, если бы задача звучала "Все числа повторяются по 2 раза, кроме искомого", то обычный побитовый XOR решал бы задачу за O(N) вообще без дополнительной памяти.


Да задачу (стартовую) решили уже без применения каких-то сложных структур:

здесь
Автор: Xobotik
Дата: 03.04.10


        private static int foo(int[] a)
        {
            int[] b = new int[a.Length];
            for (int i = 0; i < a.Length; i++)
            {
                if (b[a[i]] == 0)
                {
                    b[a[i]] = a[i];
                }
                else
                {
                    return a[i];
                }
            }
            return 0;
        }


Теперь просто пытаемся найти еще другие методы решения задачи.
С уважением!
Re[2]: Поиск повторяющегося числа в массиве
От: Xobotik Россия  
Дата: 06.04.10 10:19
Оценка:
Здравствуйте, _FRED_, Вы писали:

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


X>>Условие задачи:

X>>Дан массив размера N из целых чисел, принимающих значения от 1 до M, при этом одно
X>>число в этом массиве повторяется два раза. Найти это число за время O(N).

_FR>Весь топик не читал, боясь встретить подсказки, а связи нейронные наростить надо бы, ибо вчера была кушал водку


_FR>Правиьно ли я понимаю, что только указанного условия достаточно для решения? То есть

_FR> _FR>?

Да.
С уважением!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.