交错字符串算法

时间:2016-03-12 22:54:50

标签: algorithm dynamic-programming

我正试图轻微扭曲地解决经典的交错问题。扭曲是第三个字符串可以是前两个字符串循环的交错。例如:假设str1 =“ABC”,Str2 =“ADC”。然后第三个字符串可以是“ABC”和“ADC”循环的交错。循环可以是(string)^ k的任何前缀,其中k是一些正int。所以A的循环将是ABCABCA,因为它是str1 ^ 2的前缀。

一个澄清的例子如下:
str1等于“ABC”
str2 =“ADC”
Str3 =“ABCADCABADCCA” - 查找str3是否是str1和str2的循环的交错。

“答案:是的,因为str3是循环的交错:ABCABCA是str1 ^ 3的前缀,循环ADCADC是str2的前缀。”

1 个答案:

答案 0 :(得分:0)

作为一个起点,我建议以下算法是正确的,没有评论其运行时的最佳性:

  1. 构建一个DFA(让我们称之为L代表"左和#34;)接受第一个字符串的循环,例如: (ABC)*(e|A|AB)其中e是接受空字符串的正则表达式。
  2. 同样构建一个DFA(将其称为R为"右"),它接受第二个字符串的循环。
  3. 我们现在为您的交错语言构建一个NFA(称为N,用于"非确定性"),如下所示:

    • 状态N是状态对(l,r),其中l是L的状态,r是R的状态。
    • 如果以下两个条件之一成立,则在(1,r)到(l',r')的边缘标记为C,如果有以下两个条件之一:
      • 从l到l' L中标记为c,r = r',OR
      • 从r到r' R中标记为c,l = 1'
    • (l,r)在N中是最终的,如果L在L中是最终的,r在R中是最终的。
    • N的起始状态是(l,r),其中l是L的起始状态,r是R的起始状态。
  4. 然后我认为N接受你的交错语言:接受通过这个NFA的路径对应于选择" L"或" R"对于每个角色以及通过L的接受路径,标记为" L"以及通过R接受标记为" R"。

    的字符的路径

    为了好玩,我在Haskell中组合了一个非常小的实现这个想法,而没有花费大量时间进行优化或类似的事情。 (所以没有最小化DFA,或试图记住状态转换,或类似的东西。)它对你的例子是可行的,至少:

    import Data.List
    
    type Position a = ([a], [a])
    type DFAState a = (Position a, Position a)
    type NFAState a = [DFAState a]
    
    initialize :: [a] -> [a] -> NFAState a
    initialize xs ys = [(([], xs), ([], ys))]
    
    stepPosition :: Eq a => a -> Position a -> [Position a]
    stepPosition x ([], []  ) = []
    stepPosition x (bs, []  ) = stepPosition x ([], reverse bs)
    stepPosition x (bs, e:es) = [(e:bs, es) | e == x]
    
    ordNub :: Ord a => [a] -> [a]
    ordNub = concatMap (take 1) . group . sort
    
    stepDFA :: Ord a => a -> DFAState a -> [DFAState a]
    stepDFA x (l, r) = ordNub
                     $ [(l', r) | l' <- stepPosition x l]
                    ++ [(l, r') | r' <- stepPosition x r]
    
    stepNFA :: Ord a => a -> NFAState a -> NFAState a
    stepNFA x ss = concatMap (stepDFA x) ss
    
    evalNFA :: Ord a => [a] -> NFAState a -> Bool
    evalNFA _      [] = False
    evalNFA []     ss = True
    evalNFA (c:cs) ss = evalNFA cs (stepNFA c ss)
    
    top :: Ord a => [a] -> [a] -> [a] -> Bool
    top ls rs cs = evalNFA cs (initialize ls rs)
    

    以下是ghci中的一些示例运行:

    *Main> :set +s
    *Main> top "ABC" "ADC" "ABCADCABADCCA"
    True
    (0.00 secs, 0 bytes)
    *Main> top "ABC" "ADC" "ABCADCABADCCADABCC"
    True
    (0.01 secs, 0 bytes)
    *Main> top "ABC" "ADC" "ABCADCABADCCADADCC"
    False
    (0.00 secs, 0 bytes)