Не хочется изобретать велосипед
Jun. 28th, 2016 07:15 pmЕсть программистская задачка, на которую я не знаю правильного ответа.
Дан массив чисел. Нужно наиболее эффективным образом найти в нем такой непрерывный подмассив, чтобы среднее значение элементов этого подмассива и среднее значение остальных элементов максимально различались.
Например, пусть дан массив [99, 99, 99, 0, 0, 0, 100, 0, 0, 0].
Если мы возьмем подмассив, состоящий только из элемента 100, то среднее остальных элементов будет 3*99/9 = 33, а разность средних - 100-33 = 67.
Если брать в качестве подмассива группу из трех нулей, то среднее остальных равно (3*99+100)/7 = 56.714..., что хуже.
Если мы возьмем подмассив, состоящий из трех элементов, равных 99, то его среднее будет 99, среднее остальных элементов - 100/7 = 14.285..., а разность - 99-14.285... = 84.714... (максимум).
Но при увеличении количества нулей результат меняется. Пусть массив таков:
[99, 99, 99, (триста нулей), 100, (триста нулей)].
Тогда если взять подмассив [99, 99, 99], получим разность средних 99-100/601 = 98.8..., а если взять подмассив [100], получим 100-3*99/603=99.5..., и в этом случае подмассив [100] оптимален.
Дан массив чисел. Нужно наиболее эффективным образом найти в нем такой непрерывный подмассив, чтобы среднее значение элементов этого подмассива и среднее значение остальных элементов максимально различались.
Например, пусть дан массив [99, 99, 99, 0, 0, 0, 100, 0, 0, 0].
Если мы возьмем подмассив, состоящий только из элемента 100, то среднее остальных элементов будет 3*99/9 = 33, а разность средних - 100-33 = 67.
Если брать в качестве подмассива группу из трех нулей, то среднее остальных равно (3*99+100)/7 = 56.714..., что хуже.
Если мы возьмем подмассив, состоящий из трех элементов, равных 99, то его среднее будет 99, среднее остальных элементов - 100/7 = 14.285..., а разность - 99-14.285... = 84.714... (максимум).
Но при увеличении количества нулей результат меняется. Пусть массив таков:
[99, 99, 99, (триста нулей), 100, (триста нулей)].
Тогда если взять подмассив [99, 99, 99], получим разность средних 99-100/601 = 98.8..., а если взять подмассив [100], получим 100-3*99/603=99.5..., и в этом случае подмассив [100] оптимален.
no subject
Date: 2016-06-29 02:22 am (UTC)no subject
Date: 2016-06-29 02:27 am (UTC)no subject
Date: 2016-06-29 02:38 am (UTC)99, 99, 99, 0, 0, 0, 100, 0, 0, 0
100-3*99/9 = 67
99-100/7 = 84
no subject
Date: 2016-06-29 02:39 am (UTC)no subject
Date: 2016-06-29 02:50 am (UTC)no subject
Date: 2016-06-29 05:19 am (UTC)no subject
Date: 2016-06-29 05:26 am (UTC)Но вот даже вышеупомянутую maximum subarray problem сформулировали в 1977 году, а линейное решение придумали далеко не мгновенно, так что я не оставляю надежды.
no subject
Date: 2016-06-29 11:55 am (UTC)no subject
Date: 2016-06-29 03:08 pm (UTC)no subject
Date: 2016-06-29 05:07 pm (UTC)Потому что иначе ответ прост:
За один проход находим среднее массива, а так же самое большое и самое маленькое число в нем (и их позиции). Смотрим, что дальше от среднего в массиве - самое большое или самое маленькое число, и соответственно выбираем его как подмассив из 1 элемента.
Чуть более интеллектуальная разновидность: запоминаем не просто самое большое и самое маленькое число, а последовательности из них, и предпочитаем самую длинную последовательность. Вуаля, линейное решение.
Вот если размер подмассива фиксирован - то сложнее.
no subject
Date: 2016-06-29 05:34 pm (UTC)no subject
Date: 2016-06-30 12:44 am (UTC)Тогда, подозреваю, более адекватная постановка была бы с поиском не максимальной разницы средних, а минимальной суммы квадратов отличий чисел от соотв. средних.
no subject
Date: 2016-06-30 01:16 am (UTC)no subject
Date: 2016-06-30 03:09 am (UTC)no subject
Date: 2016-06-30 03:36 am (UTC)no subject
Date: 2016-06-30 03:38 am (UTC)no subject
Date: 2016-06-30 03:40 am (UTC)Должно хорошо работать в тех случаях, когда картинка не слишком зашумлена и типичные "береговые линии" (если всё, что ниже порога, -- море, а выше -- суша) достаточно гладкие, без островков и луж.
no subject
Date: 2016-06-30 06:03 am (UTC)no subject
Date: 2016-06-30 06:30 am (UTC)1. Максимум и минимум в окрестности.
2. Среднее среди элементов, больших среднего по окрестности, и среднее среди меньших.
3. Граница выбирается по максимуму разницы между соседними упорядоченными элементами (если таких несколько, делается взвешенное усреднение), и вычисляются средние по двум подмножествам, которые и становятся "новым белым" и "новым черным".
Алгоритм "если центральный пиксель светлее среднего, сделать его новым белым, а если темнее - новым черным" (максимизация контраста) у меня тоже есть. Он применяется в предобработке перед усреднением. Но хотелось бы уметь в постобработке отъедать жирные черные наплывы, как, например, в верхней части букв (особенно I) тут
не сильно трогая остальное. Сейчас я использую эрозию (сделать пиксель новым белым).
Также я экспериментировал с методом new = max(old, max + min - old), т.е. чем темнее был, тем светлее станет, но не темнее прежнего. Итеративно это красиво, но пользы мало.
Еще я с сегодняшнего дня умею делать в точности круговые окрестности (а не просто множество пикселей, попадающих центрами в круг) и вычислять взвешенные минимум и максимум (тут уж не локально, а пользуясь известными границами области значений). Если радиус не больше sqrt(2.25), т.е. если пиксель с весом 100% всего один - центральный, то эрозия получается плавная, чем я сейчас и пытаюсь пользоваться. Но будь у меня возможность делать направленную эрозию, я бы, возможно, мог достичь более красивого результата.
no subject
Date: 2016-06-30 05:39 pm (UTC)На первом проходе определяем среднее массива.
На втором проходе ищем подмассивы и запоминаем лучший найденный. Начинаем с первого числа и смотрим, больше оно или меньше среднего. Продолжаем добавлять к подмассиву средние числа, пока они находятся с той же стороны от среднего (при переносе каждого числа в подмассив, соответственно корректируем среднее оставшихся в массиве чисел). Если находится число с другой стороны от среднего, то запоминаем эту позицию (в каждый момент может быть запомнено не более одной позиции) и продолжаем пытаться добавить еще чисел, пока не случится одно из (а) среднее подмассива сравнится со средним остального массива или (б) найдется некоторое фиксированное количество X чисел подряд, которые попадают на другую сторону. Если одно их этих условий случается, плюем и отскакиваем на запомненную позицию, где опять начинаем с одного числа в подмассиве.
Введение ограничения числа X ограничивает оптимальность, но и ограничивает время выполнения O(X*N), то есть при малом X выходит O(N).
no subject
Date: 2016-06-30 05:47 pm (UTC)Линейная эвристика, которую я придумал, пользуется алгоритмом поиска максимального и минимального подмассива, и потом пытается их улучшить путем растяжения или сжатия. Но и в этом случае оптимальность не гарантируется, поскольку и мой, и твой алгоритм будут работать на тестовом примере одинаковым образом независимо от количества нулей.
no subject
Date: 2016-06-30 05:48 pm (UTC)На первом проходе определяем среднее массива.
На втором проходе ищем подмассивы и запоминаем лучший найденный. Начинаем с переноса в подмассив первого числа и смотрим, больше оно или меньше среднего. Продолжаем добавлять к подмассиву следующие числа, пока они находятся с той же стороны от
среднего в массивесредневзвешенной точки между средним в массиве и средним в подмассиве, вес согласно числе чисел в массиве и подмассиве (при переносе каждого числа в подмассив, соответственно корректируем среднее оставшихся в массиве чисел). Это учловие гарантирует, что при переносе этого числа в подмассив, средние массива и подмассива разойдутся дальше. Если находится число с другой стороны от этой точки, то запоминаем эту позицию (в каждый момент может быть запомнено не более одной позиции) и продолжаем пытаться добавить еще чисел, пока не случится одно из (а) среднее подмассива сравнится со средним остального массива или (б) найдется некоторое фиксированное количество X чисел подряд, которые попадают на другую сторону. Если одно их этих условий случается, плюем и отскакиваем на запомненную позицию, где опять начинаем с одного числа в подмассиве.Введение ограничения числа X ограничивает оптимальность, но и ограничивает время выполнения O(X*N), то есть при малом X выходит O(N).
Если X=N, то получается в худшем случае квадратичный алгоритм, который находит оптимальную точку.
no subject
Date: 2016-06-30 06:06 pm (UTC)И средневзвешенная точка оказывается фиксированной, это среднее изначального полного массива.
no subject
Date: 2016-06-30 06:27 pm (UTC)Например, допустим массив из 10 чисел уже нормализован:
[1, 7, -1, -1, ...]
Берем 1 - разница средних 10/9. Добавляем 7, разница средних 5, отлично. Дальше хуже. Твой алгоритм вернет [1, 7], что неверно, потому что оптимально [7], разница средних 70/9.
no subject
Date: 2016-06-30 06:37 pm (UTC)no subject
Date: 2016-06-30 07:51 pm (UTC)no subject
Date: 2016-06-30 08:12 pm (UTC)no subject
Date: 2016-06-30 08:20 pm (UTC)Ну будет у нас,
и дальше?
no subject
Date: 2016-06-30 10:29 pm (UTC)no subject
Date: 2016-06-30 11:14 pm (UTC)no subject
Date: 2016-07-02 01:43 am (UTC)no subject
Date: 2016-07-03 12:48 pm (UTC)Но [99, 99, 15, 99, 99, 0, 0, 0, 100, 0, 0, 0] уже непройдёт...
no subject
Date: 2016-07-04 09:19 pm (UTC)