我接受了采访,面试官给了我关于名单的问题。
例如,原始列表就像[0,1,0,0,2,0,0,1]
,2
应该尽可能填充列表,除非它遇到1.因此输出将是[0,1,2,2,2,2,2,1]
。< / p>
一个例子:
[0,2,1,0,1,2,0,0]
输出:
[2,2,1,0,1,2,2,2]
另一个例子:
[2,0,0,0,1,1,0,1]
输出:
[2,2,2,2,1,1,0,1]
如何解决这个问题?
答案 0 :(得分:4)
您可以使用Deterministic Finite Automaton两种状态s_fill
和s_keep
,如下所示:
fill2 :: [Int] -> [Int]
fill2 xs = s_keep xs []
where s_keep [] w = reverse w
s_keep (c:cs) w = if c == 2 then s_fill cs (c:w) else s_keep cs (c:w)
s_fill [] w = reverse w
s_fill (c:cs) w = if c == 1 then s_keep cs (c:w)
else s_fill cs (2:w)
在状态s_fill
中,函数fill2
将2
填充到累加器的头部,直到满足1
,在这种情况下,DFA跳转到状态s_keep
。
在s_keep
中,fill2
会将每个元素本身推回到累加器w
,直到遇到2
,在这种情况下,DFA会跳转到s_fill
。
当余数列表(s_ {keep,fill}的第一个参数)为空时,递归终止。在这种情况下,函数返回累加器的反向,因为靠近磁头的元素被推到累加器尾部附近更深。
到目前为止,函数fill2
从左到右填充2。剩下的工作是在(fill2 xs)
的结果上从右到左填写,这可以在(fill2 xs)
的反面轻松获得,如下所示:
fill2' xs = reverse $ fill2 $reverse $fill2 xs
输出:
*Main> fill2' [0,1,0,0,2,0,0,1]
[0,1,2,2,2,2,2,1]
*Main> fill2' [0,2,1,0,1,2,0,0]
[2,2,1,0,1,2,2,2]
*Main> fill2' [2,0,0,0,1,1,0,1]
[2,2,2,2,1,1,0,1]
和
*Main> fill2' [0,0,1,0,2,0,1]
[0,0,1,2,2,2,1]
---代码的原始版本---
(感谢@ØrjanJohansen指出下面代码的原始版本问题以及初始状态和填充方向)。
fill2 :: [Int] -> [Int]
fill2 str = s_fill str []
where s_keep [] w = reverse w
s_keep (c:cs) w = if c == 2 then s_fill cs (c:w) else s_keep cs (c:w)
s_fill [] w = reverse w
s_fill (c:cs) w = if c == 1 then s_keep cs (c:w)
else s_fill cs (2:w)
答案 1 :(得分:3)
如果我们能得到一个向右填充的函数fillRight
,即
fillRight [0,2,1,0,1,2,0,0] = [0,2,1,0,1,2,2,2]
然后我们可以轻松实现完整的解决方案:
fillLeft = reverse . fillRight . reverse
fill = fillLeft . fillRight
所以我们可以将精力用在fillRight
上。正如其他人所指出的那样,这是一个简单的状态机,我将用以下方式编写,阐明状态转换(注意我是如何添加一个参数来跟踪状态的):
fillRight' :: Bool -> [Int] -> [Int]
fillRight' _ [] = []
fillRight' True (0:xs) = 2 : fillRight' True xs
fillRight' False (0:xs) = 0 : fillRight' False xs
fillRight' _ (1:xs) = 1 : fillRight' False xs
fillRight' _ (2:xs) = 2 : fillRight' True xs
然后通过设置初始状态
关闭它fillRight = fillRight' False
答案 2 :(得分:3)
如果您将1
视为空格,并将0
和2
视为字母中的字母,则可以更轻松地解决此问题
import Data.List
words'::[Int]->[[Int]]
words' [] = [[]]
words' x =
case rest of
(1:after) -> first:words' after
_ -> [first]
where (first, rest) = break (== 1) x
fill::[Int]->[Int]
fill x = intercalate [1] $
map (\x -> replicate (length x) (if 2 `elem` x then 2 else 0)) $
words' x
首先将传入的数据拆分为&#34;单词&#34;,如果单个2位于单词内,则只需将单词映射到所有2
。
这将在输入大小中起作用O(n),甚至可以处理无限输入流。
实施例
main = do
print $ fill [1,0,0,0]
print $ fill [1,0,0]
print $ fill [0,0,1,0,2,0,1]
print $ fill [0,1,0,0,2,0,0,1,0,1,2,0,1]
print $ fill [0,1,0,0,2,0,0,1,0,0,1,2,0,1]
print $ fill [0,2,1,0,1,2,0,0]
print $ fill [2,0,0,0,1,1,0,1]
print $ fill [0,1,0,0,0,0,0,1]
输出
[1,0,0,0]
[1,0,0]
[0,0,1,2,2,2,1]
[0,1,2,2,2,2,2,1,0,1,2,2,1]
[0,1,2,2,2,2,2,1,0,0,1,2,2,1]
[2,2,1,0,1,2,2,2]
[2,2,2,2,1,1,0,1]
[0,1,0,0,0,0,0,1]
答案 3 :(得分:1)
这是代码高尔夫解决方案:
fill xs = foldr step replicate xs 0 0 where
step 0 r l m = r (l + 1) m
step 1 r l m = replicate l m ++ 1 : r 0 0
step 2 r l m = r (l + 1) 2
main = do
print $ fill [1,0,0,0]
print $ fill [1,0,0]
print $ fill [0,0,1,0,2,0,1]
print $ fill [0,1,0,0,2,0,0,1,0,1,2,0,1]
print $ fill [0,1,0,0,2,0,0,1,0,0,1,2,0,1]
print $ fill [0,2,1,0,1,2,0,0]
print $ fill [2,0,0,0,1,1,0,1]
print $ fill [0,1,0,0,0,0,0,1]
结果
[1,0,0,0]
[1,0,0]
[0,0,1,2,2,2,1]
[0,1,2,2,2,2,2,1,0,1,2,2,1]
[0,1,2,2,2,2,2,1,0,0,1,2,2,1]
[2,2,1,0,1,2,2,2]
[2,2,2,2,1,1,0,1]
[0,1,0,0,0,0,0,1]