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

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

使用BIT的最长递增子序列

BIT,也称树状数组,是一种经典的数据结构,用于快速计算序列的前缀和。在许多算法问题中,BIT都有着重要的应用,其中包括计算最长递增子序列(LIS)长度。

什么是最长递增子序列?

给定一个长度为n的序列a,最长递增子序列就是指一个严格递增的子序列,其长度最大。例如,对于序列a=[3,1,4,1,5,9,2,6,5],其最长递增子序列为[1,4,5,6],长度为4。

传统方法

传统的动态规划方法使用O(n^2)的时间复杂度计算最长递增子序列,其核心思想是对于每一个元素,计算其之前所有比其小的元素所形成的最长递增子序列长度,然后加上1就得到以这个元素为结尾所能够形成的最长递增子序列长度。最终的结果就是所有以每个元素为结尾的最长递增子序列长度中的最大值。

使用BIT的方法

BIT可以在O(nlogn)的时间复杂度内计算最长递增子序列。其思路是对原始序列进行离散化,然后从左到右扫描序列,用BIT来维护已扫描过的元素所形成的最长严格递增子序列长度(LIS)。对于每个元素,将其值作为索引,在BIT中查询该索引之前的所有元素中LIS的最大值,然后再将自身的LIS长度加1并更新BIT中对应的值。最终BIT中的最大值就是最长递增子序列的长度。

下面是使用Python实现的代码示例:

def get_lis_length(a: list) -> int:
    # 离散化
    sorted_a = sorted(list(set(a)))
    a_dict = {v: i for i, v in enumerate(sorted_a)}

    bit = [0] * (len(a_dict) + 1)

    # 扫描序列并更新BIT
    for v in a:
        idx = a_dict[v] + 1
        lis_len = query(bit, idx - 1)
        update(bit, idx, lis_len + 1)
    
    # 查询BIT中的最大值
    return query(bit, len(bit) - 1)

def query(bit: list, idx: int) -> int:
    res = 0
    while idx > 0:
        res = max(res, bit[idx])
        idx -= (idx & -idx)
    return res

def update(bit: list, idx: int, val: int):
    while idx < len(bit):
        bit[idx] = max(bit[idx], val)
        idx += (idx & -idx)

其中,query函数用于查询BIT中索引为[1,idx]的元素中的最大值,update函数用于将索引为idx的元素更新为val值。

总结

使用BIT计算最长递增子序列是一种非常高效的算法,其时间复杂度为O(nlogn),相较于传统的动态规划算法能够带来明显的效率提升。在实际应用中,BIT也具有广泛的应用,例如计算序列的前缀和、求逆序对等等。因此,程序员需要熟练掌握BIT的使用,以便在解决复杂问题的过程中获得更高的效率。