我试图检查给定列表是否是另一个列表的子序列:
这里列出了真实的列表示例:
subseq "" "w"
subseq "w" "w"
subseq "ab" "cab"
subseq "cb" "cab"
subseq "aa" "xaxa"
not (subseq "aa" "xax")
not (subseq "ab" "ba")
我刚刚谈到这个但在某些情况下它会给出错误的结果
subseq :: Eq a => [a] -> [a] -> Bool
subseq [] [] = True
subseq [] ys = True
subseq xs [] = False
subseq (x:xs) (y:ys) = x == y || subseq xs ( 1 `drop` ys )
答案 0 :(得分:7)
两件事,一件是高级,一件是低级。高级别优先:
您的递归案例不正确。在英语中,你写过非空列表是另一个非空列表的子序列,如果它们的第一个字符匹配,或者除了列表1中的第一个字符之外的每个字符都是每个字符的子序列而第二个列表中的前两个字符。这显然是不正确的,因为例如“aaa”不是“abc”的子序列,即使它们的第一个字符匹配,并且“db”不是“cab”的子序列,即使“b”是“b”的子序列
对最终案例的一个更好的方法是用英语表达:“非空列表是另一个非空列表的子序列,如果:1。它们的第一个字符匹配,列表1的其余字符是子序列列表2的剩余字符,或2.它们的第一个字符不匹配,列出一个是列表2中除第一个字符以外的所有字符的子序列。“
因为这看起来像是家庭作业,所以我会留给你把它翻译成Haskell代码。
低级别:代码片段
subseq (x:xs) (y:ys) = x == y || subseq xs ( 1 `drop` ys )
不符合您的想法。 ys
已经是第二个列表中除第一个之外的所有元素;你不需要从中删除任何更多的元素。此外,第一种情况(subseq [] [] = True
)是不必要的,因为它会被第二种情况捕获,但这不是什么大问题。
答案 1 :(得分:2)
对于只想寻找简单线性时间实现的人来说,这就是一个。
subseq :: Eq a => [a] -> [a] -> Bool
[] `subseq` _ = True
(_:_ ) `subseq` [] = False
(a:as) `subseq` (b:bs) = (if a == b then as else a:as) `subseq` bs
答案 2 :(得分:1)
这样做:
import Control.Monad
subseq a b = elem a . filterM (\x-> [True,False]) $ b
(thank you SO / sacundim为此!)。
从jacobm的answer获取建议,你得到了
subseq [] ys = True
subseq xs [] = False
subseq (x:xs) (y:ys) = x == y && (....)
|| x /= y && subseq (....) (....)
最好用守卫写的,
subseq (x:xs) (y:ys)
| x == y = (....)
| otherwise = subseq (....) (....)
第一个代码更好地被视为规范,而不是代码,效率非常低。为了改进它,我们可以尝试融合 elem
和filterM
- 这可能已经实现为
filterM p xs = liftM concat $ sequence [ do {t<-p x; return [x|t]} | x<-xs]
这样
elem xs $ filterM (\x-> [True,False]) ys ==
elem xs $ map concat $ sequence [ [[y|t] | t<-[True,False]] | y<-ys] ==
elem xs $ map concat $ sequence [ [[y],[]] | y<-ys] ==
not.null $ filter (match [[x]|x<-xs]) $ sequence [ [[y],[]] | y<-ys]
where
match [] _ = True
match _ [] = False
match ([x]:t) ([y]:s) | x==y = match t s
match q (_:s) = match q s ==
not.null $ [()|r<-sequence [ [[y],[]] | y<-ys], match [[x]|x<-xs] r] ==
match2 xs ys
where
match2 [] _ = True
match2 _ [] = False
match2 (x:t) (y:s) | x==y = match2 t s
match2 q (_:s) = match2 q s