📌  相关文章
📜  使得i <j <k且a [k] <a [i] <a [j]的数组(i,j,k)中的三元组的计数(1)

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

计算使得i < j < k且a[k] < a[i] < a[j]的三元组的数量

给定一个数组a,计算符合上述条件(i,j,k)的三元组的数量。

思路

首先考虑i和j的位置,遍历所有可能的i和j,然后再确定k的位置。对于每个(i,j)组合,我们需要找到符合要求的k的位置,即a[k]<a[i]且a[k]<a[j]。在这里,可以使用前缀最小值和后缀最大值这两个预处理技巧,将时间复杂度优化到O(n)。

具体实现步骤:

  1. 从左到右扫描数组a,维护一个前缀最小值的数组minArr。对于每个位置i,minArr[i]记录a[0]~a[i]的最小值。
  2. 从右到左扫描数组a,维护一个后缀最大值的数组maxArr。对于每个位置i,maxArr[i]记录a[i]~a[n-1]的最大值。
  3. 遍历所有符合要求的(i,j)组合,计算k的数量。对于每个(i,j)组合,k的数量就是符合条件的a[k]在a[i]和a[j]之间的数量。可以通过二分查找或者线性扫描的方式计算出来。
代码
def count_triplets(a):
    n = len(a)
    minArr = [a[0]] * n
    maxArr = [a[n - 1]] * n

    for i in range(1, n):
        minArr[i] = min(minArr[i - 1], a[i])
    
    for i in range(n - 2, -1, -1):
        maxArr[i] = max(maxArr[i + 1], a[i])
    
    res = 0
    for i in range(n):
        for j in range(i + 1, n):
            if (minArr[i] < a[j] < maxArr[j]):
                k = bisect_left(a, minArr[i], j + 1, n)
                res += j - k
    
    return res

其中,bisect_left(a, x, lo, hi)是一个标准库函数,用于在有序数组a[lo:hi]中查找第一个大于等于x的元素的位置。如果没有找到,返回hi。

时间复杂度

预处理minArr和maxArr的时间复杂度均为O(n),对于每个(i,j)组合,计算k的数量的时间复杂度为O(log n)或O(n),故总的时间复杂度为O(n^2 log n)或O(n^3)。