Условие оригинальной задачи можно прочитать здесь.
Я решил немного усложнить задание и сделать алгоритм для работы на произвольном n
, где n
- количество цифр во множителях.
С наскоку получается алгоритм вроде этого:
- Взять множество Int от 10 ^ n - 1 до 0, упорядоченое от большего до меньшего
- Найти Декартово произведение этого множества самого на себя
[(x, y)| x <- xs, y <- xs]
- Найти пару с найбольшим числом, которое является палиндромом и получено из умножения первого на второй элеметов пары.
Если до 2 пункта включительно все было понятно то на 3-м явно проблемы.
- Полный перебор всех пар, фильтрование по критерию "палиндромности" и нахождение большего - наиболее точный но слишком затратный способ;
- Упрощение до первой пары с наибольшим первым числом - потеря правильного результата
Допустим n
= 3 и пары у нас следующие
[(999, 999), (999, 998), (999, 997), .. (998, 999), (998, 998), .. (100, 100)]
Во-первых сразуможно отрезать половину пар ибо (999, 998)
== (998, 999)
и т.д. Во-вторых первый найденый палиндром в этом
множистве будет 580085, который является произведением 995 * 583, но он не самый большой.
Во-первых, ограничимся в паре (x, y) x >= y. Во-вторых надо просматривать результаты после нахождения первого палиндрома. Можно проверять множество просто со следующей пары но эффективней будет сразуперейти на следующее число по первому элементу пары.
- Мы нашли первый палиндром 580085 для пары (995, 583)
- Уменьшили пару до (994, 994) и продолжили поиск (* помним, часть пар мы уже отсекли)
Логика размышлений такая, если мы и найдем палиндром больше, первое число будет не 995 (считаем, что для [996 .. 999] мы ничего не нашли),
а какое-то другое и можно смело отнимать 1. Если быть доконца честным искомый палиндром может быть только в пределах 995 <= x,y <= 584
,
т.к. для данного y
пару с максимальным результатом мы тоже нашли.
Я довольно плохо знаю C и это решение - первое, что пришло в голову, после перерыва почти в 5 лет, за которые я не трогал этот язык. С Haskell только знакомлюсь и тоже не знаю всех возможностей оптимизации, даже C знаю лучше. Python (3.6.0) - первая пришедшая в голову реализация, на данный момент мой рабочий язык.
- Haskell 87.36s
- C 19.13s
- Python 94.48s
Заменив проверку со строки на числодробилку в Haskell получаем более чем двукратное повышение производительности
- Haskell 41.45s