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

📅  最后修改于: 2023-12-03 14:54:58.216000             🧑  作者: Mango

数组中三元组的计数

在一个数字数组中,找出所有符合条件的三元组的个数,条件为:i < j < k 且 a[k] < a[i] < a[j]。

思路

寻找符合条件的三元组,我们需要找到一个数对 $(i, j)$,其中 $i < j$,然后分别扫描左边和右边的元素,计算符合条件的三元组个数。

我们可以使用两个数组 $left$ 和 $right$ 来记录当前位置左右两侧的元素中,符合条件的最小、最大值。其中 $left_i$ 记录 $i$ 左侧的最小元素,即:

$$ left_i=\min_{j<i}a_j $$

同理,$right_i$ 记录 $i$ 右侧的最大元素,即:

$$ right_i=\max_{j>i}a_j $$

然后我们将数组 $a$ 从左到右扫描一遍,同时计算符合条件的三元组总数 $ans$,具体方法如下:

  • 对于每个位置 $j$,计算左右两侧的最小、最大值 $left_j, right_j$。
  • 如果满足条件 $a[i] < a[j] < a[k]$,则找到了一个符合条件的三元组,我们需要计算由 $i, j, k$ 组成的三元组数量。由于只需要计数,因此我们可以使用 left 和 right 数组来计算,计算方法如下:

$$ ans+=\sum_{i=0}^{j-1}[a_i< a[j]\cdot min_i< a[j]\cdot max_i<a[j]] $$

上述公式中,$min_i$ 和 $max_i$ 分别是元素 $a_0\sim a_{j-1}$ 中,最小和最大的元素值,符合条件的 $i$ 的数量即为计算结果。

代码实现
def count_triplets(arr: list) -> int:
    n = len(arr)
    left, right = [0] * n, [0] * n
    left[0] = float('inf')
    right[n-1] = float('-inf')
    ans = 0

    # 预处理 left 数组,记录从左边开始,每个位置的最小元素
    for i in range(1, n):
        left[i] = min(left[i-1], arr[i-1])

    # 预处理 right 数组,记录从右边开始,每个位置的最大元素
    for i in range(n-2, -1, -1):
        right[i] = max(right[i+1], arr[i+1])

    # 计算符合条件的三元组数量
    for i in range(1, n-1):
        if left[i] < arr[i] < right[i]:
            cnt = sum([1 for j in range(i) if arr[j] < arr[i] < right[j]])
            ans += cnt

    return ans
复杂度分析

预处理 left 和 right 数组的时间复杂度均为 $O(n)$,算法的总时间复杂度为 $O(n^2)$。