给你两个下标从 0 开始且长度为 n 的整数数组 nums1 和 nums2 ,两者都是 [0, 1, …, n - 1] 的 排列 。
好三元组 指的是 3 个 互不相同 的值,且它们在数组 nums1 和 nums2 中出现顺序保持一致。换句话说,如果我们将 pos1v 记为值 v 在 nums1 中出现的位置,pos2v 为值 v 在 nums2 中的位置,那么一个好三元组定义为 0 <= x, y, z <= n - 1 ,且 pos1x < pos1y < pos1z
和 pos2x < pos2y < pos2z
都成立的 (x, y, z) 。
请你返回好三元组的 总数目 。3 <= n <= 100000
示例 1:
输入:nums1 = [2,0,1,3], nums2 = [0,1,2,3]
输出:1
解释:
总共有 4 个三元组 (x,y,z) 满足 pos1x < pos1y < pos1z ,
分别是 (2,0,1) ,(2,0,3) ,(2,1,3) 和 (0,1,3) 。
这些三元组中,只有 (0,1,3) 满足 pos2x < pos2y < pos2z 。
所以只有 1 个好三元组。
示例 2:
输入:nums1 = [4,0,1,3,2], nums2 = [4,1,0,2,3]
输出:4
解释:总共有 4 个好三元组 (4,0,3) ,(4,0,2) ,(4,1,3) 和 (4,1,2) 。
思路:
nums1:[4,0,1,3,2] -> [0,1,2,3,4] 记录nums1中数字的位置(或者说映射关系)
nums2:[4,1,0,2,3] -> [0,2,1,4,3] 让nums2按照这个顺序排列
nums2左边小于当前数,有几对[0,1,1,3,3]
nums2右边大于当前数,有几对[4,2,2,0,0]
ans = sum(left[i] * right[i]);
注意:树状数组的下标是 1 … n,而给定的数组下标是 0 … n-1
class Solution {
public long goodTriplets(int[] nums1, int[] nums2) {
int n=nums1.length;
long res=0;
Map<Integer, Integer> hash = new HashMap<>();
for (int i = 0; i < n; i++) hash.put(nums1[i], i);
for (int i = 0; i < n; i++) nums2[i] = hash.get(nums2[i]);
BIT bit=new BIT(100005);
for(int i=0;i<n;i++){
int l = bit.query(nums2[i]+1); // 左边小于nums2[i]的数
int t = i - l; // 左边大于nums2[i]的数
int r = (n - nums2[i] - 1) - t; // 右边大于nums2[i]的数
bit.update(nums2[i]+1);
res += 1L * l * r;
}
return res;
}
}
class BIT {
private int[] tree;
private int n;
public BIT(int n) {
this.n = n;
this.tree = new int[n + 1];
}
public static int lowbit(int x) {
return x & (-x);
}
public int query(int x) {
int ret = 0;
while (x != 0) {
ret += tree[x];
x -= lowbit(x);
}
return ret;
}
public void update(int x) {
while (x <= n) {
++tree[x];
x += lowbit(x);
}
}
}