leetcode
leetcode 1901 ~ 1950
统计数组中好三元组数目

统计数组中好三元组数目

难度:

标签:

题目描述

代码结果

运行时间: 448 ms, 内存: 32.6 MB


// Java Stream solution for counting good triplets
// Problem: Given two arrays nums1 and nums2, find the number of good triplets (x, y, z)
// where the order of elements in both arrays is the same.

// Approach:
// 1. Use a stream to map the elements of nums1 and nums2 to their indices.
// 2. Filter the triplets in nums1 and check if the indices in nums2 follow the same order.
// 3. Count such triplets.

import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;

public class GoodTripletsStream {
    public long countGoodTriplets(int[] nums1, int[] nums2) {
        int n = nums1.length;
        Map<Integer, Integer> posInNums1 = new HashMap<>();
        Map<Integer, Integer> posInNums2 = new HashMap<>();

        // Store the positions of elements in nums1 and nums2
        IntStream.range(0, n).forEach(i -> {
            posInNums1.put(nums1[i], i);
            posInNums2.put(nums2[i], i);
        });

        // Count good triplets
        return IntStream.range(0, n)
                .boxed()
                .flatMap(i -> IntStream.range(i + 1, n)
                        .boxed()
                        .flatMap(j -> IntStream.range(j + 1, n)
                                .mapToObj(k -> new int[]{i, j, k})))
                .filter(triplet -> {
                    int pos1 = posInNums2.get(nums1[triplet[0]]);
                    int pos2 = posInNums2.get(nums1[triplet[1]]);
                    int pos3 = posInNums2.get(nums1[triplet[2]]);
                    return pos1 < pos2 && pos2 < pos3;
                })
                .count();
    }
}

解释

方法:

这个题解采用了一个有序集合来优化查找和插入操作。首先,使用一个数组 p 存储 nums1 中每个值的索引,使得 p[nums2[i]] 可以快速获得 nums2 中元素在 nums1 中的位置。接着,通过遍历 nums2 来构建好的三元组。对于 nums2 中的每一个元素 nums2[i](作为三元组中的 y),使用一个有序集合 s 来维护已经遍历过的 nums2 元素在 nums1 中的位置。对于每个元素 y,通过二分查找其在 s 中的位置,可以得到小于 y 的元素数量(即作为 x 的候选数量)。同时,计算出大于 y 的元素数量(即作为 z 的候选数量),这样就可以确定以 y 为中心的好三元组数量。每次循环结束时,将当前 y 加入集合 s 中,以便后续查找和统计。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
在算法中,有序集合s是如何确保元素顺序的,它是基于什么数据结构实现的?
在算法中,有序集合s通过使用平衡二叉搜索树(如红黑树)或者排序数组来确保元素的顺序。在Python的`sortedcontainers`模块中,`SortedList`通常是基于排序数组实现的,它保持元素在内部数组中排序,从而能够快速进行二分查找和有序插入操作。
🦆
为什么选用SortedList而不是其他类型的数据结构,如普通列表或哈希表?
选择`SortedList`而不是普通列表或哈希表是因为`SortedList`可以更高效地支持插入和二分查找操作。普通列表虽然可以通过`bisect`模块支持二分查找,但插入操作(尤其是中间插入)的效率较低,因为它需要移动后续的所有元素。哈希表虽然插入和查找操作的平均时间复杂度为O(1),但它不保持元素的顺序,因此无法直接用来获取小于给定值的元素个数。
🦆
代码中的`less = s.bisect_left(y)`步骤是如何工作的,它返回的是什么?
`less = s.bisect_left(y)`步骤通过二分查找算法在有序集合s中查找元素y应插入的位置,以保持集合的有序性。该方法返回的是y在s中的索引位置,如果s中存在y,这个位置指向第一个y;如果s中不存在y,这个位置是y应当被插入的位置。这个索引同时也表示了s中小于y的元素的数量。
🦆
在计算好三元组数量时,公式`ans += less * (n - 1 - y - (i - less))`是如何推导出来的?
该公式用于计算以元素y为中心的好三元组的数量。这里的`less`是y左侧(小于y的元素)的数量。`n-1-y`是在nums1中y右侧的元素数量。由于我们已经遍历了i个元素,我们需要从这个右侧元素总数中减去已经包括在遍历中的元素数量`i-less`(即y右侧但在遍历中的元素数量),从而得到`n-1-y-(i-less)`。这表示对于每一个小于y的元素(共less个),有`n-1-y-(i-less)`种选择作为z。因此,各个y可以形成的好三元组数量就是`less`乘以这个值。

相关问题