我需要检查Haskell,如果四位数是一个回文,问题是我不能使用列表,尽管有一个固定的数字,我应该使用递归。我一直在思考这个问题,但是我无法使用递归来获得解决方案。我能得到的最接近的是:
pldrm :: Integer -> Bool
pldrm x
|x > 9999 = False
|x > 999 = (div x 1000 == mod x 10) && (mod (div x 100) 10) == div (mod x 100) 10
|otherwise = False
你知道吗?感谢
答案 0 :(得分:12)
如何检查数字是否等于其反转?
palindrome :: Integer -> Bool
palindrome x = reversal x == x
reversal :: Integral a => a -> a
reversal = go 0
where go a 0 = a
go a b = let (q,r) = b `quotRem` 10 in go (a*10 + r) q
这样可以让-121
这样的负数成为回文,如果你不想这样做,很容易检查。
nonNegativePalindrome x = x >= 0 && palindrome x
reversal
给出一个整数,其数字与输入的顺序相反(忽略12 == ...000012
中隐含的无限前导零)。
reversal
通过剥离底部的数字(使用quotRem
,which is a lot like divMod
)并以相反的顺序(通过多重复制和添加)将它们组合在一起。
reversal 12345
= go 0 12345
= go 5 1234
= go 54 123
= go 543 12
= go 5432 1
= go 54321 0
= 54321
值得注意的是n == reversal $ reversal n
仅当n
为零或具有非零的1位数时。 (reversal (reversal 1200) == 12
),但reversal
范围内的整数都是可逆的:reversal x == reversal (reversal (reversal x))
forall x
。
有关如何获得此解决方案的更详尽说明in this blog post。
答案 1 :(得分:7)
好吧,这确实比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
会查找位数:
边缘情况如下:
| x < 0 = False
| x == 0 = True
| x < 10 = digits == 1
inner
这样的1011
是一位数的nubmer 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来测试它(应该是一个很好的例子: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.
答案 2 :(得分:6)
如果仅考虑四位数,您可以递归减去1001以检查第一个和最后一个数字是否相等,然后减去0110以检查中间数字是否相等。
pldrm :: Int -> Bool
pldrm x
| x > 1000 = pldrm (x - 1001)
| x > 100 = pldrm (x - 110)
| otherwise = x == 0
请注意,此功能会为[1000,9999]范围以外的数字提供不正确的结果。
答案 3 :(得分:3)
很遗憾你不能使用清单。这是基于算术运算的繁琐解决方案(仅适用于四位数字):
pldrm :: Int -> Bool -- no need for Integer if you work only with four
-- digit numbers
pldrm x = (div x 1000 == mod x 10) && (div y 10 == mod y 10)
where y = rem x 1000 `quot` 10 -- extracts two inner digits
> pldrm 3113
True
> pldrm 3111
False
答案 4 :(得分:0)
isPolindrom :: Integer -> Bool
isPolindrom n = if let i = read (reverse (show n)) :: Integer in i==n then True else False