繁体   English   中英

Haskell(相当长)回文检查

[英]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.DequeData.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM