字符串连接查询

时间:2016-07-21 16:30:22

标签: string algorithm

我有一个字符列表,比如x,用b[1], b[2], b[3] ... b[x]表示。在x之后,

  • b[x+1]是此订单中b[1],b[2].... b[x]的串联。同样,

  • b[x+2]b[2],b[3]....b[x],b[x+1]的串联。

  • 所以,基本上,b[n]将是x的{​​{1}}个术语的连接,从右边开始。

  • 将参数b[i]p作为查询,如何找出qb[1], b[2], b[3]..... b[x] th q的字符对应于?

注意: b[p]x已针对所有查询修复。

我尝试过强制但是字符串长度对于大x来说呈指数级增长。(x <= 100)。

示例:

  • b[1], b[2], b[3]..... b[x]

    x=3
  • 因此,对于b[] = a, b, c, a b c, b c abc, c abc bcabc, abc bcabc cabcbcabc, //.... //Spaces for clarity, only commas separate array elements p=7的查询,返回的答案为q=5(对应于字符3)。

我很难搞清楚它背后的数学。语言没有问题

1 个答案:

答案 0 :(得分:1)

当我弄清楚时,我写了这个答案,所以请耐心等待。

正如您所提到的,更容易找出b[p][q]中的字符来自原始x字符的位置,而不是为大b[p]生成p。为此,我们将使用循环查找当前b[p][q]的来源,从而减少p,直到介于1x之间,q直到它是1

让我们看一下x=3的示例,看看我们是否可以得到一个公式:

p  N(p)  b[p]
-  ----  ----
1  1     a
2  1     b
3  1     c
4  3     a b c
5  5     b c abc
6  9     c abc bcabc
7  17    abc bcabc cabcbcabc
8  31    bcabc cabcbcabc abcbcabccabcbcabc
9  57    cabcbcabc abcbcabccabcbcabc bcabccabcbcabcabcbcabccabcbcabc

序列清晰:N(p) = N(p-1) + N(p-2) + N(p-3),其中N(p)b的第p个元素中的字符数。给定px,您可以强制计算范围N的所有[1, p]。这样您就可以确定b b[p][q]的先前元素来自哪个。

为了说明,请说x=3p=9q=45

  1. 上图提供了N(6)=9N(7)=17N(8)=31。自45>9+17起,您知道b[9][45]来自b[8][45-(9+17)] = b[8][19]
  2. 迭代/递归地继续19>9+5b[8][19] = b[7][19-(9+5)] = b[7][5]
  3. 现在5>N(4)5<N(4)+N(5)b[7][5] = b[5][5-3] = b[5][2]
  4. b[5][2] = b[3][2-1] = b[3][1]
  5. 3 <= x起,我们有终止条件,b[9][45] c来自b[3]
  6. pqxbx开始,可以非常容易地递归计算或迭代计算这样的事情。我的方法需要p个数组元素来计算整个序列的N(p)。如果以递归方式工作,可以在数组或堆栈中分配。

    这是vanilla Python中的参考实现(没有外部导入,虽然numpy可能有助于简化这一点):

    def so38509640(b, p, q):
        """
        p, q are integers. b is a char sequence of length x.
        list, string, or tuple are all valid choices for b.
        """
        x = len(b)
    
        # Trivial case
        if p <= x:
            if q != 1:
                raise ValueError('q={} out of bounds for p={}'.format(q, p))
            return p, b[p - 1]
    
        # Construct list of counts
        N = [1] * p
        for i in range(x, p):
            N[i] = sum(N[i - x:i])
        print('N =', N)
    
        # Error check
        if q > N[-1]:
            raise ValueError('q={} out of bounds for p={}'.format(q, p))
    
        print('b[{}][{}]'.format(p, q), end='')
    
        # Reduce p, q until it is p < x
        while p > x:
            # Find which previous element character q comes from
            offset = 0
            for i in range(p - x - 1, p):
                if i == p - 1:
                    raise ValueError('q={} out of bounds for p={}'.format(q, p))
                if offset + N[i] >= q:
                    q -= offset
                    p = i + 1
                    print(' = b[{}][{}]'.format(p, q), end='')
                    break
                offset += N[i]
        print()
        return p, b[p - 1]
    

    调用so38509640('abc', 9, 45)生成

    N = [1, 1, 1, 3, 5, 9, 17, 31, 57]
    b[9][45] = b[8][19] = b[7][5] = b[5][2] = b[3][1]
    (3, 'c') # <-- Final answer
    

    同样,对于问题中的示例,so38509640('abc', 7, 5)会产生预期结果:

    N = [1, 1, 1, 3, 5, 9, 17]
    b[7][5] = b[5][2] = b[3][1]
    (3, 'c') # <-- Final answer
    

    抱歉,我无法想出一个更好的函数名称:)这是一个非常简单的代码,它应该在Py2和3中同样有效,尽管range函数/类有差异。

    我很想知道是否存在针对此问题的非迭代解决方案。也许有一种方法可以使用模运算或其他方式......