根据具体情况填写清单

时间:2014-11-01 04:02:19

标签: haskell

我接受了采访,面试官给了我关于名单的问题。

例如,原始列表就像[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]

如何解决这个问题?

4 个答案:

答案 0 :(得分:4)

您可以使用Deterministic Finite Automaton两种状态s_fills_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中,函数fill22填充到累加器的头部,直到满足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视为空格,并将02视为字母中的字母,则可以更轻松地解决此问题

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]
相关问题