字符串连接查询

我有一个字符列表,比如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]将是b [i]的最后x项的连接,从右边开始.
>给出p和q作为查询的参数,如何找出b [1],b [2],b [3]中的哪个字符….. b [x]确定b [p]的第q个字符对应?

注意:对于所有查询,x和b [1],b [2],b [3] ….. b [x]是固定的.

我尝试了强制执行,但是对于大的x,字符串长度呈指数增长.(x <= 100). 例:
>当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(对应于字符’c’).

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

最佳答案 当我想出来的时候,我写下了这个答案,所以请耐心等待.

正如你所提到的,更容易找出b [p] [q]中的字符来自原始x字符而不是为大p生成b [p].为此,我们将使用循环来查找当前b [p] [q]的来源,从而将p减小到1和x之间,并且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个元素中的字符数.给定p和x,你可以蛮力计算范围[1,p]的所有N.这将允许您找出b b [p] [q]的哪个先前元素来自.

为了说明,例如x = 3,p = 9且q = 45.

>上图给出N(6)= 9,N(7)= 17和N(8)= 31.由于45> 9 17,你知道b [9] [45]来自b [8] [45-(9 17)] = b [8] [19].
>迭代地/递归地继续,19> 9 5,因此b [8] [19] = b [7] [19-(9 5)] = b [7] [5].
>现在5> N(4)但是5 > b [5] [2] = b [3] [2-1] = b [3] [1]
>由于3 <= x,我们有终止条件,而b [9] [45]是来自b [3]的c.
在开始p,q,x和b到x之后,可以非常容易地递归地或迭代地计算这样的东西.我的方法需要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中同样有效,尽管范围函数/类有差异.

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

点赞