📜  使用BIT的最长递增子序列(1)

📅  最后修改于: 2023-12-03 15:22:18.137000             🧑  作者: Mango

使用BIT的最长递增子序列

最长递增子序列(Longest Increasing Subsequence,简称LIS)是指在一个无序的数列中,找到一个尽可能长的子序列使得这个子序列中的所有元素都按照升序排序。BIT,即树状数组,可以用来实现最长递增子序列的求解。

BIT简介

BIT(Binary Indexed Tree),也叫树状数组,是一种查询、修改复杂度均为$O(logn)$的数据结构。BIT在对区间和、区间最大/最小值等数据进行查询和修改时,具有很大的优越性,尤其适合在动态不断变化的序列中维护前缀信息。

BIT实现最长递增子序列
思路

假设原数列为$a_1,a_2,...,a_n$,用BIT维护长度为$i$的递增子序列的结尾元素最小值为$dp_i$。初始状态,$dp_i$均为无穷大,因为此时长度为$i$的递增子序列不存在。

从原序列中依次取出元素$cur$,利用BIT查询$cur$之前的所有$dp_i$中小于$cur$的最大值$pre$,并将$dp_{j+1}$(其中$j$为$pre$对应的下标)更新为$cur$。更新完后,$cur$的位置对应的$dp$值为更新后的$dp$值,即$dp_{j+1}$,因为长度为$j+1$的递增子序列的结尾就是$cur$。

最后,$dp$数组中最后一个不为无穷大的值的下标就是最长递增子序列的长度。

代码
def LIS(a):
    n = len(a)
    dp = [float('inf')] * (n + 1)
    dp[0] = float('-inf')

    def lowbit(x):
        return x & -x

    def update(bit, x, val):
        while x <= n:
            bit[x] = min(bit[x], val)
            x += lowbit(x)

    def query(bit, x):
        res = float('inf')
        while x:
            res = min(res, bit[x])
            x -= lowbit(x)
        return res

    bit = [float('inf')] * (n + 1)
    for i in range(n):
        cur = a[i]
        pre = bisect_right(bit, cur) - 1
        dp[pre + 1] = cur
        update(bit, pre + 1, cur)
    return dp.index(float('inf')) - 1
复杂度分析

BIT实现最长递增子序列的时间复杂度为$O(nlogn)$,其中$n$为序列长度。分析如下:

BIT的查询和更新操作都是$O(logn)$的,所以一次更新操作的复杂度为$O(logn)$。在实现最长递增子序列时,需要遍历其中每个元素,因此总时间复杂度为$O(nlogn)$。