在 Haskell 中生成下一个字典字符串
Posted
技术标签:
【中文标题】在 Haskell 中生成下一个字典字符串【英文标题】:Generate next lexicographical string in Haskell 【发布时间】:2016-03-17 14:14:01 【问题描述】:如果给我一个像skhfbvqa
这样的字符串,我将如何生成 next 字符串?对于这个例子,它是skhfbvqb
,下一个字符串是skhfbvqc
,以此类推。给定的字符串(和答案)总是 N 个字符长(在这种情况下,N=8)。
我尝试了什么:
我试图生成可能组合的整个(无限)列表,并获取给定字符串的所需(下一个)字符串,但不出所料,它太慢了,我什至没有得到 的答案N=6.
我使用了列表理解:
allStrings = [ c : s | s <- "" : allStrings, c <- ['a'..'z'] ]
main = do
input <- readFile "k.in"
putStrLn . head . tail . dropWhile (not . (==) input) . map reverse $ allStrings
(请原谅我非常糟糕的 Haskell-ing :) 仍然是菜鸟)
所以我的问题是,我该怎么做?如果有多种方法,非常感谢它们之间的比较。谢谢!
【问题讨论】:
扫描allStrings
看起来非常低效——它类似于通过\x -> head . tail $ dropWhile (/= x) [0..]
计算后继。它有效,但需要指数时间/空间。相反,我会将字符串表示为向后列表,并对每个字符/数字执行标准的“带进位加法”。正如预期的那样,这将具有线性的最坏情况复杂性。 (此外,它也是摊销常数时间,因为几何和收敛,因此是最优的)
@chi 是的,allStrings
效率极低。这只是我想到的第一件事。你的建议听起来很有趣。您能否提供一个答案,但提供更多指示/步骤?
【参考方案1】:
这是一个带有基本转换的版本(这样你可以随意加减):
encode x base = encode' x [] where
encode' x' z | x' == 0 = z
| otherwise = encode' (div x' base) ((mod x' base):z)
decode num base =
fst $ foldr (\a (b,i) -> (b + a * base^i,i + 1)) (0,0) num
输出:
*Main> map (\x -> toEnum (x + 97)::Char)
$ encode (decode (map (\x -> fromEnum x - 97) "skhfbvqa") 26 + 1) 26
"skhfbvqb"
【讨论】:
感谢您的回答!所以这就像将字符串视为以 26 为基数的数字,对吧?使用字符[a-z]
而不是数字。
@Roshnal 是的,完全正确 - 就像将字符串视为 base-26 数字,使用字符 [a-z]
而不是数字。
@Roshnal 它可能需要对具有 a
s(视为零)作为前缀的字符串进行一些填充
啊,是的,没错。有趣的方法,也会尝试一下:)【参考方案2】:
我会去创建一个辅助函数f :: Integer -> String
和一个g :: String -> Integer
,其中f 1 = "a"
,...f 27 = "aa"
,f 28 = "ab"
等等,反之则为g
。
然后incrementString = f . succ . g
注意:为了学习,我省略了f
的实现
更新
对于不同的方法,您可以使用进位函数 inc' :: Char -> (Char, Bool)
定义增量,然后
incString :: String -> String
incString = reverse . incString'
where incString' [] = []
incString' (x:xs) = case inc' x of (x',True) -> x': incString' xs
(x',False) -> x':xs
注意:这个函数不是尾递归的!
【讨论】:
感谢您的回复。没想到是这样的;会试试的!但是我想知道这是否可以以更“Haskell-y”的方式完成(例如使用内置函数、monad 等)【参考方案3】:我发现这行得通。它只是使用模式匹配来查看字符串是否以 z 开头并相应地添加额外的 a。
incrementString' :: String -> String
incrementString' [] = ['a']
incrementString' ('z':xs) = 'a' : incrementString' xs
incrementString' (x:xs) = succ x : xs
incrementString :: String -> String
incrementString = reverse . incrementString' . reverse
【讨论】:
这对我来说非常好。检查incrementString "zzzzzzzz"
是否是您真正想要的——我提到这一点是因为您写道答案的长度必须为 8。
@chi 你说得对,那里有问题。它给出了 9 a's 的输出......但我的意思是问题提供者(这是一个更大的练习问题的一部分)提到答案将是 N 位数。再次阅读我的问题,看来我可能有点不清楚。对不起:/以上是关于在 Haskell 中生成下一个字典字符串的主要内容,如果未能解决你的问题,请参考以下文章