Хорошо, это действительно немного сложно и больше математики, чем Haskell, поэтому давайте посмотрим на возможное решение (предполагая десятичную систему).
Идея состоит в том, чтобы использовать div
и mod
для получения старшей и младшей цифры числа. Помните, что вы можете написать
(q,r) = n `divMod` m
получить числа q
и r
так, чтобы q * m + r = n
с 0 <= r < q
. Для m = 10
это будет удобно (для положительного n
):
- в
q
все, кроме последних цифр
- в
r
последняя цифра
примечание: какое-то время я ошибался в этом - надеюсь, теперь это правильно - пограничные случаи действительно сложны.
palindrome :: Integer -> Bool
palindrome n = palin n (digits n)
where
palin x dgts
| x < 0 = False
| x == 0 = True
| x < 10 = dgts == 1
| otherwise = q == x `mod` 10 && palin inner (dgts-2)
where
inner = r `div` 10
(q,r) = x `divMod` size
size = 10^(dgts-1)
digits :: Integer -> Integer
digits x
| x < 10 = 1
| otherwise = 1 + digits (x `div` 10)
Очевидно, я не знал размера вашей проблемы, поэтому digits
будет искать количество цифр:
- цифры 5445 = 4
- цифры 123 = 3
- ...
Пограничные случаи таковы:
| x < 0 = False
| x == 0 = True
| x < 10 = digits == 1
- Очевидные отрицательные числа не должны быть палиндромами
- если все цифры 0 то это палиндром
- однозначные числа являются палиндромами, если мы действительно смотрим только на длину 1 (это меня расстроило, так как
inner
таких вещей, как 1011
, является однозначным числом 1
)
Остальное основано на этих наблюдениях:
x div 10^(digits-1)
= старшая цифра (5445 div 1000 = 5
)
x mod 10^(digits-1)
= все, кроме старшей цифры (5445 mod 1000 = 445
)
x mod 10
= самая младшая цифра (5445 mod 10 = 5
)
number div 10
= удалить младшую цифру (5445 div 10 = 544
)
просто на всякий случай давайте проверим это с помощью Quickcheck:
Давайте используем Quickcheck, чтобы проверить это (должен быть хороший пример: D)
module Palindrome where
import Test.QuickCheck
main :: IO ()
main = do
checkIt palindrome
palindrome :: Integer -> Bool
palindrome n = palin n (digits n)
where
palin x dgts
| x < 0 = False
| x == 0 = True
| x < 10 = dgts == 1
| otherwise = q == x `mod` 10 && palin inner (dgts-2)
where
inner = r `div` 10
(q,r) = x `divMod` size
size = 10^(dgts-1)
digits :: Integer -> Integer
digits x
| x < 10 = 1
| otherwise = 1 + digits (x `div` 10)
checkIt :: (Integer -> Bool) -> IO ()
checkIt p =
quickCheckWith more (\n -> n < 0 || p n == (reverse (show n) == show n))
where more = stdArgs { maxSuccess = 10000, maxSize = 999999 }
вроде нормально:
runghc Palindrom.hs
+++ OK, passed 10000 tests.
person
Random Dev
schedule
11.10.2014
Traversable
экземпляр числа. Затем просто сравните пройденный в обратном направлении номер с обычным пройденным номером. - person Vektorweg   schedule 11.10.2014mono-traversable
. - person rampion   schedule 13.10.2014