List Haskell(长得可怕)回文检查
我正在努力向臭名昭著的方向发展,我在四处游荡(看看列表是否是回文)。我知道大多数解决方案在合理的短名单上都能很好地发挥作用。现在我如何编写一个函数来测试一个很长的列表是否是回文,例如List Haskell(长得可怕)回文检查,list,haskell,ghc,ghci,palindrome,List,Haskell,Ghc,Ghci,Palindrome,我正在努力向臭名昭著的方向发展,我在四处游荡(看看列表是否是回文)。我知道大多数解决方案在合理的短名单上都能很好地发挥作用。现在我如何编写一个函数来测试一个很长的列表是否是回文,例如 let ll = [1..10000000] ++ [10000000, 10000000-1..1] ++ [7] 我(也许天真地)试图这样测试它: isPalindrome [] = True isPalindrome [_] = True isPalindrome [x,y] = x==y isPalind
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]
的实现,即
贪婪
谢谢。我想这是你怀疑的
最后一个xs
。建议:在执行任何递归之前,在中点*处拆分字符串,并反转后半部分。然后在每次递归时比较两个字符串的第一个字符*如果字符串长度为奇数,则两个字符串都应包含中间字符。我认为这是您怀疑的最后一个xs
。建议:在执行任何递归之前,在中点*处拆分字符串,并反转后半部分。然后在每次递归时比较两个字符串的第一个字符*如果字符串长度为奇数,则两个字符串都应包含中间字符。正如您猜测的那样,最后一个xs
是个问题-它将在列表长度上花费线性时间,并强制立即生成整个列表([a..b]
与Haskell列表一般一样是惰性的)。因此,您的isPalindrome
函数总共将是二次时间
对于一个简单的实现,我将从xs==reverse xs
开始,它具有正确的渐近行为(线性),但具有相对较高的常数因子,并将在reverse
到达列表末尾并开始生成结果时,在内存中有两个完整的列表副本
通过查看长度,然后在中间点拆分列表,或者在一次传球中做一些更聪明的事情,您可能会对该方法有所改进
然而,我认为,为了获得更好的性能,您需要切换数据结构-我会查看类似于或的内容。正如您猜测的那样,最后一个xs
是个问题-它将花费列表长度的线性时间,并强制立即生成整个列表([a..b]
是懒惰的,就像Haskell列表一般一样)。因此,您的isPalindrome
函数总共将是二次时间
对于一个简单的实现,我将从xs==reverse xs
开始,它具有正确的渐近行为(线性),但具有相对较高的常数因子,并将在reverse
到达列表末尾并开始生成结果时,在内存中有两个完整的列表副本
通过查看长度,然后在中间点拆分列表,或者在一次传球中做一些更聪明的事情,您可能会对该方法有所改进
然而,我认为,为了获得更好的性能,您需要切换数据结构-我将查看类似于或的内容。建议在以下位置使用一系列有趣的回文函数:
天真的
无意义
palindrome = liftM2 (==) reverse id
实用的
palindrome = (==) <$> reverse <*> id
以下是一些有趣的回文函数:
天真的
无意义
palindrome = liftM2 (==) reverse id
实用的
palindrome = (==) <$> reverse <*> id
哈,又是你!谢谢你回答我的哈斯克尔问题。事实上,Data.Dequeue
似乎是这个实现的更好的数据结构。哈,你又来了!谢谢你回答我的哈斯克尔问题。实际上,Data.Dequeue
似乎是这种实现的更好的数据结构。