我想要擅长功能编程,所以我为自己设定了一些任务。
我想确定整数列表中最长子序列的长度,其中下一个元素 增加1 。< / p>
所以结果应该是
incsubseq [] ~?= 0,
incsubseq [5] ~?= 1,
incsubseq [1,2,3,5,6] ~?= 3,
incsubseq [5,6,1,2,3] ~?= 3,
incsubseq [5,6,1,4,3] ~?= 2,
incsubseq [6,5,4,3,2,1] ~?= 1]
我的尝试是这样的:
incsubseq :: [Int] -> Int
incsubseq [] = 0
incsubseq [_] = 1
incsubseq (a:b)
| a == ((head b)-1) = 1 + (incsubseq b)
| a /= ((head b)-1) = (incsubseq b)
但当然这仅适用于没有较长子序列的列表,例如[ 1,2,3 ,42] = 3 ,但不适用于[1,2, 100,101,102 ]这样的列表,应该是3但是是不(它是2)!
我真的非常感谢你的帮助,因为这个问题让我疯狂,来自OO-编程。
答案 0 :(得分:4)
你在同一时间解决了太多问题 - 我会尝试以更易懂的步骤解决问题
length
map
的新列表
maximum
长度如果您的序列是&#34;所有相同的事情&#34;现在第一部分会很容易。那么来自group
的{{1}}就足够了,但在这里情况并非如此,不幸的是Data.List
这正是你所寻找的 - 不起作用(由于技术原因我做的不想扩大。)
首先,您需要实现自己的groupBy (\x y -> x + 1 == y)
功能或&#34;作弊&#34;并查看here我得到的地方
groupBy'
然后你可以简单地
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy rel [] = []
groupBy rel (x:xs) = (x:ys) : groupBy rel zs
where (ys,zs) = groupByAux x xs
groupByAux x0 (x:xs) | rel x0 x = (x:ys, zs)
where (ys,zs) = groupByAux x xs
groupByAux y xs = ([], xs)
接下来的步骤应该是可以管理的。
注意:如果您想要最长的序列,可以创建一个快捷方式并使用groupBy (\x y -> x + 1 == y) [1,2,100,101,102]
。
完整解决方案:
maximumBy (compare `on` length)
答案 1 :(得分:3)
您可以使用名为 accumulators 的技术解决此问题:您可以将某个函数与沿运行时修改的某些值一起调用。然后,基本情况返回使用这些 accumulators 计算的函数的结果。
对于这个特定问题,我们引入了两个累加器:curi
和maxi
。 curi
存储当前序列的长度,maxi
包含迄今为止看到的最大递增序列。
基本情况是当我们到达列表的末尾时,我们返回maxi
:
maxincsub [] curi maxi = maxi
另一个基本情况是我们遇到最后一个元素。在这种情况下,我们会返回maxi
和curi
的最大值:
maxincsub [_] curi maxi = max curi maxi
归纳案例是当我们在列表中看到两个元素时:我们确定a1
是否为a2
的增量。如果是,我们递增curi
。如果没有,我们会将curi
设置回1
,但首先将maxi
设置为此maxi
的最大值curi
:
maxincsub (a0:a1:as) curi maxi | a0+1 == a1 = maxincsub (a1:as) (curi+1) maxi
| otherwise = maxincsub (a1:as) 1 (max curi maxi)
或将它们放在一起:
maxincsub [] curi maxi = maxi
maxincsub [_] curi maxi = max curi maxi
maxincsub (a0:a1:as) curi maxi | a0+1 == a1 = maxincsub (a1:as) (curi+1) maxi
| otherwise = maxincsub (a1:as) 1 (max curi maxi)
最后,我们需要通过设置incsubseq
和maxincsub
的初始值来将您的函数curi
与我们的maxi
绑定:
incsubseq :: [Int] -> Int
incsubseq xs = maxincsub xs 1 0
用你给定的输入来判断:
*Main> incsubseq []
0
*Main> incsubseq [5]
1
*Main> incsubseq [1,2,3,4,5,6]
6
*Main> incsubseq [1,2,3,5,6]
3
*Main> incsubseq [5,6,1,2,3]
3
*Main> incsubseq [5,6,1,4,3]
2
*Main> incsubseq [6,5,4,3,2,1]
1
答案 2 :(得分:0)
您可以将折叠函数用于此类递归函数。
这可能不是惯用的,但这是我使用foldl的版本。
incsubseq [] = 0
incsubseq (x:xs) = (\(a,_,_)->a) $ foldl update (1,1,x) xs
where
update (maxn,n,h) x
| h+1 /= x = (maxn, 1, x)
| n+1 > maxn = (n+1, n+1, x)
| otherwise = (maxn, n+1, x)