【问题标题】:Find all alternate concatenations of 2 strings查找 2 个字符串的所有替代串联
【发布时间】:2014-01-05 03:21:38
【问题描述】:

所以我正在尝试编写一个函数来查找 2 个字符串的所有替代连接。说x = '12'y = 'ab',那么预期结果是['ab12', 'a1b2', 'a12b', '1ab2', '1a2b', '12ab']。我编写了以下程序:

# [ list of sequences where each seq is a concat of s and t ] 
def g( s, t ) :
    #
    if ( s == "" ) :
        return [ t ]
    elif ( t == "" ) :
        return [ s ]
    else :
        res = []
        for i in xrange( len(s) ) :
            for j in xrange( 1, len(t) + 1 ) :
                res.extend( [ s[:i] + t[:j] + x for x in g( s[i:], t[j:] ) ] )
                #
        res.append( s + t )
        return res

它输出正确的结果,但有些序列有重复:

In [22]: r = g( "12", "ab" )
         [ (x, r.count(x)) for x in set( r ) ]
Out[22]: [('ab12', 2), ('12ab', 1), ('1ab2', 2), ('a12b', 1), ('1a2b', 1), ('a1b2', 1)]

如何避免重复? (我不想检查是否已经添加了元素;我对生成唯一序列的“真正”方式感兴趣)

【问题讨论】:

    标签: algorithm concatenation dynamic-programming combinatorics


    【解决方案1】:

    最好使用递归方法。去掉 s 的第一个字符,找出剩余字符串的所有组合,对 t 做同样的事情:

    def g1( s, t ):
            return [s[0]+x for x in g( s[1:], t )]
    
    def g(s,t):
            if( s=="" ):
                    return [t]
            elif t=="":
                    return [s]
            else:
                    return g1( s, t ) + g1( t, s )
    

    【讨论】:

      【解决方案2】:

      重复来自哪里?

      代码两次构建t 的子字符串:循环遍历j 的值并在每次递归时始终选择s 的空前缀。

      对于j 的每次迭代,您将附加t[:j],然后附加一个以i = 0 开头的递归调用,从而附加更多t 字符。因此t 中的相同字符子串将由j 循环和递归创建。例如,“12ab”可以在第一层递归中以“1”开头,也可以在第一层递归中以“12”开头。

      (重复的模式对于较长的字符串更为明显,例如“abc”和“123”。)

      修复原来的解决方案

      让我们修复原来的解决方案。我们希望通过j 循环或递归来构建t 的每个附加子字符串。为了好玩,我会为每个人展示一个解决方案。

      首先,让我们保留j 循环。这意味着我们需要强制对g 的每个递归调用不以t 字符开头。但是我们还需要先调用g 来生成以t 字符开头的字符串。这是一种半hacky的方法:

      def g( s, t, z=0 ) :
          if ( s == "" ) :
              return [ t ]
          elif ( t == "" ) :
              return [ s ]
          else :
              res = []
              for i in xrange( z, len(s) ) :
                  for j in xrange( 1, len(t) + 1 ) :
                      res.extend( [ s[:i] + t[:j] + x for x in g( s[i:], t[j:], 1) ])
              res.append( s + t )
              return res
      

      g 的每次调用都将遍历所有前缀为s 的所有字符串,后跟所有t 的前缀,然后是递归(必须以s 开头)。第一次调用g 是一种特殊情况,因此我们明确允许第一次调用允许t 作为第一个前缀。

      或者我们可以让递归构建t的子字符串。

      def g( s, t, ) :
          if ( s == "" ) :
              return [ t ]
          elif ( t == "" ) :
              return [ s ]
          else :
              res = []
              for i in xrange( len(s) ) :
                  res.extend( [ s[:i] + t[:1] + x for x in g( s[i:], t[1:] ) ] )
              res.append( s + t )
              return res
      

      在这个版本中,我们选择s的所有前缀,从t中添加一个字符,然后递归。由于我们将"" 算作s 的前缀,因此将构建大于1 的t 的子字符串。

      顺便说一句,当递归起作用时,您可以使用

      for i in xrange( len(s) + 1) :
      

      消除线

      res.append( s + t )
      

      【讨论】:

        【解决方案3】:

        您正在从 0...len(a)+len(b)-1 中选择 len(b) 索引,以便 b 的字符出现在其中(其他索引从 a 中获取字符)。这建议使用itertools.combinations,它提供了这样的解决方案:

        import itertools
        
        def concats(a, b):
            for i in map(set, itertools.combinations(xrange(len(a) + len(b)), len(b))):
                its = iter(a), iter(b)
                yield ''.join(next(its[x in i]) for x in xrange(len(a) + len(b)))
        
        print list(concats('abc', '12'))
        

        【讨论】:

        • 谢谢,yield 一行让我很开心。您真的不需要与set() 进行映射,对吗?
        • 在功能上 set() 是多余的,但它通过近似线性因子减少运行时间,因为它使 x in i O(1) 而不是 O(len(b)),并且它被称为 @987654327 @次。
        【解决方案4】:

        顺便说一句,我在 Mathematica.SE 上 recently answered 也有同样的问题(尽管不是针对字符串)。
        我的解决方案使用了 pentadecagon 描述的算法:

        f[u : {a_, x___}, v : {b_, y___}, c___] := f[{x}, v, c, a] ~Join~ f[u, {y}, c, b]
        
        f[{x___}, {y___}, c___] := {{c, x, y}}
        

        用途:

        f[{1, 2}, {a, b}]
        
        {{1, 2, a, b}, {1, a, 2, b}, {1, a, b, 2},
         {a, 1, 2, b}, {a, 1, b, 2}, {a, b, 1, 2}}
        

        这段代码几乎只使用了Mathematicapattern matching syntax,唯一的例外是Join

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-07-13
          • 2021-07-13
          • 2013-07-01
          • 2013-12-22
          • 1970-01-01
          • 1970-01-01
          • 2012-10-24
          相关资源
          最近更新 更多