📌  相关文章
📜  使用二元索引树计算右侧的较小元素和左侧的较大元素(1)

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

使用二元索引树计算右侧的较小元素和左侧的较大元素

二元索引树(Binary Indexed Tree,也叫树状数组)是一种用于维护序列前缀和、区间和等问题的数据结构,其时间复杂度为O(logN),优于暴力算法O(N),适用于数据范围较大的问题。在本篇文章中,我们将介绍如何使用二元索引树计算序列中每个元素的左侧较大值和右侧较小值。

左侧较大值

左侧较大值问题可以描述为:给定一个长度为N的序列a,对于每个1<=i<=N,求a[1:i-1]中最大的数。使用二元索引树可以很方便地解决该问题。我们可以在树的每个节点中维护一个最大值,当访问到位置i时,从右向左依次查询0:i-1范围内的最大值即可得到左侧较大值。

以下是使用Python实现的计算左侧较大值的代码:

def construct_bit(nums):
    bit = [0] * (len(nums) + 1)

    def update(i):
        while i > 0:
            bit[i] = max(nums[i - 1], bit[i])
            i -= i & -i

    for i in range(len(nums)):
        update(i + 1)

    return bit


def query(bit, i):
    res = 0
    while i < len(bit):
        res = max(res, bit[i])
        i += i & -i
    return res

nums = [1, 3, 4, 2, 4, 7, 6]
bit = construct_bit(nums)
ans = []
for i in range(len(nums)):
    ans.append(query(bit, i))
print(ans) # [0, 1, 3, 4, 4, 4, 7]

其中,construct_bit函数用于构建二元索引树,update函数用于更新树中的每个节点,query函数用于查询从根节点到节点i的路径上的最大值,ans为计算得到序列中每个元素的左侧较大值。

右侧较小值

右侧较小值问题可以描述为:给定一个长度为N的序列a,对于每个1<=i<=N,求a[i+1:N]中最小的数。使用二元索引树也可以很方便地解决该问题。我们可以在树的每个节点中维护一个最小值,当访问到位置i时,从左向右依次查询i+1:N范围内的最小值即可得到右侧较小值。

以下是使用Python实现的计算右侧较小值的代码:

def construct_bit(nums):
    bit = [float('inf')] * (len(nums) + 1)

    def update(i):
        while i < len(bit):
            bit[i] = min(nums[i - 1], bit[i])
            i += i & -i

    for i in range(len(nums), 0, -1):
        update(i)

    return bit


def query(bit, i):
    res = float('inf')
    while i > 0:
        res = min(res, bit[i])
        i -= i & -i
    return res

nums = [1, 3, 4, 2, 4, 7, 6]
bit = construct_bit(nums)
ans = []
for i in range(len(nums)):
    ans.append(query(bit, i + 1))
print(ans) # [2, 2, 2, 4, 6, 6, inf]

其中,与计算左侧较大值的代码类似,construct_bit函数用于构建二元索引树,update函数用于更新树中的每个节点,query函数用于查询从节点i到根节点的路径上的最小值,ans为计算得到序列中每个元素的右侧较小值。

使用二元索引树可以很方便地解决左侧较大值和右侧较小值问题,而且时间复杂度为O(NlogN),非常适用于数据范围较大的问题。