Performance 为什么头尾模式匹配比索引快得多?
我今天正在处理一个HackerRank问题,最初是用索引编写的,对于大多数测试用例来说,速度都非常慢,因为它们非常庞大。然后我决定切换到Performance 为什么头尾模式匹配比索引快得多?,performance,haskell,pattern-matching,Performance,Haskell,Pattern Matching,我今天正在处理一个HackerRank问题,最初是用索引编写的,对于大多数测试用例来说,速度都非常慢,因为它们非常庞大。然后我决定切换到head:tail模式匹配,它只是放大了。差别是日夜分明的,但我不明白为什么效率会有如此大的变化。如果有用的话,下面是代码供参考 最有效的索引尝试 count :: Eq a => Integral b => a -> [a] -> b count e [] = 0 count e (a:xs) = (count e xs +) $ if
head:tail
模式匹配,它只是放大了。差别是日夜分明的,但我不明白为什么效率会有如此大的变化。如果有用的话,下面是代码供参考
最有效的索引尝试
count :: Eq a => Integral b => a -> [a] -> b
count e [] = 0
count e (a:xs) = (count e xs +) $ if a == e then 1 else 0
fullCheck :: String -> Bool
fullCheck a = prefixCheck 0 (0,0,0,0) a (length a) && (count 'R' a == count 'G' a) && (count 'Y' a == count 'B' a)
prefixCheck :: Int -> (Int, Int, Int, Int) -> String -> Int -> Bool
prefixCheck n (r',g',y',b') s l
| n == l = True
| otherwise =
((<= 1) $ abs $ r - g) && ((<= 1) $ abs $ y - b)
&& prefixCheck (n+1) (r,g,y,b) s l
where c = s !! n
r = if c == 'R' then r' + 1 else r'
g = if c == 'G' then g' + 1 else g'
y = if c == 'Y' then y' + 1 else y'
b = if c == 'B' then b' + 1 else b'
run :: Int -> IO ()
run 0 = putStr ""
run n = do
a <- getLine
print $ fullCheck a
run $ n - 1
main :: IO ()
main = do
b <- getLine
run $ read b
作为参考,问题是
您将获得一系列的N
球,有4种颜色:红色、绿色、黄色和蓝色。当且仅当以下所有条件均为真时,序列才会充满颜色:
- 红球和绿球一样多
- 黄色的球和蓝色的球一样多
- 序列的每个前缀中红色球和绿色球的数量之差最多为1
- 序列每个前缀中黄色球和蓝色球的数量之差最多为1
m
的任何子字符串,其中m
小于字符串的大小
您已经在注释中找到了列表索引为何线性执行的答案。但是,如果您对一个更具Haskell风格的解决方案感兴趣,那么即使是头尾模式匹配也是不必要的。使用正确的折叠可以实现更高性能的解决方案:
import Control.Applicative ((<$>))
import Control.Monad (replicateM_)
solve :: String -> Bool
solve s = foldr go (\r g y b -> r == g && y == b) s 0 0 0 0
where
go x run r g y b
| 1 < abs (r - g) || 1 < abs (y - b) = False
| x == 'R' = run (r + 1) g y b
| x == 'G' = run r (g + 1) y b
| x == 'Y' = run r g (y + 1) b
| x == 'B' = run r g y (b + 1)
main :: IO ()
main = do
n <- read <$> getLine
replicateM_ n $ getLine >>= print . solve
import-Control.Applicative(())
导入控制.Monad(复制项)
求解::字符串->布尔
求解s=foldr go(\r g y b->r==g&&y==b)s0
哪里
去x跑r g y b
|1=打印。解决
Haskell列表是,因此获取列表的第一个元素是一个常量时间操作,xs!!n
在列表长度上是线性的。@AlexisKing噢,所以hd:tl
是O(1)和xs!!n
O(n)在Haskell中吗?@EliSadoffCorrect@EliSadoff对如果你想要一个随机访问的数据结构,在不同的库中有不同的数组数据类型,但是内置的列表只是一个标准的单链接列表。请查看这个和其他FAQWow,这绝对漂亮。
import Control.Applicative ((<$>))
import Control.Monad (replicateM_)
solve :: String -> Bool
solve s = foldr go (\r g y b -> r == g && y == b) s 0 0 0 0
where
go x run r g y b
| 1 < abs (r - g) || 1 < abs (y - b) = False
| x == 'R' = run (r + 1) g y b
| x == 'G' = run r (g + 1) y b
| x == 'Y' = run r g (y + 1) b
| x == 'B' = run r g y (b + 1)
main :: IO ()
main = do
n <- read <$> getLine
replicateM_ n $ getLine >>= print . solve