![](/img/trans.png)
[英]Decide(in Haskell) if a number is or not a palindrome without using lists
[英]Haskell (formidably long) palindrome check
我正在努力解决臭名昭著的H-99问题,并且在解决#6问题 (找出列表是否是回文)。 我知道大多数解决方案在合理的简短列表上都能很好地工作。 现在,我将如何编写一个函数来测试很长的列表是否是回文,例如,
let ll = [1..10000000] ++ [10000000, 10000000-1..1] ++ [7]
我(天真的)试图这样测试:
isPalindrome [] = True
isPalindrome [_] = True
isPalindrome [x,y] = x==y
isPalindrome (x:xs) = isPalindrome [x,last xs] && (isPalindrome $ init xs)
我假设如果isPalindrome [x,last xs]
为False
,则&&
的昂贵右侧将不会被评估。
我概述了上面的内容,结果如下:
Mon Jun 30 18:33 2014 Time and Allocation Profiling Report (Final)
h99 +RTS -p -RTS
total time = 1.29 secs (1292 ticks @ 1000 us, 1 processor)
total alloc = 2,720,050,200 bytes (excludes profiling overheads)
COST CENTRE MODULE %time %alloc
main Main 95.6 100.0
isPalindrome Main 4.4 0.0
individual inherited
COST CENTRE MODULE no. entries %time %alloc %time %alloc
MAIN MAIN 43 0 0.0 0.0 100.0 100.0
CAF Main 85 0 0.0 0.0 100.0 100.0
main Main 86 1 95.6 100.0 100.0 100.0
isPalindrome Main 87 2 4.4 0.0 4.4 0.0
CAF GHC.Conc.Signal 84 0 0.0 0.0 0.0 0.0
CAF GHC.IO.Encoding 77 0 0.0 0.0 0.0 0.0
CAF GHC.IO.Encoding.Iconv 75 0 0.0 0.0 0.0 0.0
CAF GHC.IO.Handle.FD 68 0 0.0 0.0 0.0 0.0
CAF GHC.Show 63 0 0.0 0.0 0.0 0.0
从中我推断出问题出在last xs
,这可能需要计算整个xs
。 如果是这样,是否有解决方法? 还是只是[a..b]
实现是贪婪的?
谢谢。
如您所料, last xs
是个问题-它会在列表的长度上花费线性时间,并迫使立即生成整个列表( [a..b]
是惰性的,通常与Haskell列表一样)。 因此,您的isPalindrome
函数总共将是二次时间。
对于简单的实现,我将以xs == reverse xs
,它具有正确的渐近行为(线性),但是常数系数相对较高,最终将在reverse
获取点的内存中拥有列表的两个完整副本。到列表末尾并开始产生结果。
您可以通过查看length
然后在中途分割列表,或者在单遍操作中做一些更巧妙的操作来对这种方法进行某种程度的改进。
但是,我认为为了获得更好的性能,您需要切换数据结构-我将研究诸如Data.Deque
或Data.Sequence
类的东西。
我认为这是last xs
,您怀疑。 建议:在执行任何递归操作之前,请在中点处分割字符串*,然后反转下半部分。 然后,您在每次递归时都比较两个字符串的第一个字符。 *如果字符串长度不固定,则两个字符串都应包含中间字符。
建议在此reddit线程上使用一系列有趣的回文功能:
幼稚
palindrome list = reverse list == list
无点
palindrome = liftM2 (==) reverse id
适用性
palindrome = (==) <$> reverse <*> id
莫纳迪奇
palindrome = reverse >>= (==)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.