我接受了面試,面試官給我一個關於清單的問題。根據具體情況填寫清單
例如,原始列表將如[0,1,0,0,2,0,0,1]
,2
應儘可能地填充列表,除非它遇到1.因此輸出將是[0,1,2,2,2,2,2,1]
。
一個例子:
[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,1,0,0,2,0,0,1]
,2
應儘可能地填充列表,除非它遇到1.因此輸出將是[0,1,2,2,2,2,2,1]
。
一個例子:
[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]
如何解決這個問題?
可以使用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)
如果我們能得到一個功能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
這是比較容易,如果你認爲的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
首先將輸入數據分成「單詞」,然後只需將單詞映射到所有2
s,如果單個單詞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]
它不能處理重複0,但我認爲什麼都不能。 – 2014-11-01 09:33:28
@ØrjanJohansen-是的,這是一個固有的侷限性......即使是手工操作的人也會對是否記下0或2秒,直到看到第一個或第二個記錄這件事感到冷淡。它是那些病理性病例之一在實踐中可能會很明顯(有點像說一個計算器不能給你一個問題的答案,直到整個數字被輸入....並且該數字是9的無限串)。 – jamshidh 2014-11-01 09:42:56
這裏是代碼高爾夫球溶液:
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]
俏皮。但肯定你的意思是「fa = foldr sra 0 0; s 1c l =(++ 1:c 0 0).rl; stcl = c(l + 1).max t; r = replicate'' – 2014-11-02 03:50:41
@ØrjanJohansen非常好,尤其是使用'max'。 – user3237465 2014-11-02 09:32:00
我不認爲這在其他情況下是有用的。考慮'fill2 [0,0,1,0,2,0,1] == [2,2,1,0,2,2,1]',我相信預期的結果是'[0,0,1 ,2,2,2,1]'。 – 2014-11-01 07:38:25
@ØrjanJohansen你能解釋一下你的邏輯嗎?其實,我不確定預期的輸出是什麼。我在描述'2應儘可能地填充列表,除非它遇到1',並且我認爲當'2'遇到'基於'時,「填充」將再次開始。「舉例: [0 ,2,1,0,1,2,0,0] 輸出: [2,2,1,0,1,2,2,2]' – tinlyx 2014-11-01 08:14:44
我的邏輯是,前兩個'0'因爲它們和最近的'2'之間有'1',所以不應該填充,而第三個*應該填充,因爲它與'2'相鄰。這些例子清楚地表明'2'必須填滿左右兩邊。 – 2014-11-01 08:40:56