|
| 1 | +# [2179. Count Good Triplets in an Array (Hard)](https://leetcode.com/problems/count-good-triplets-in-an-array/) |
| 2 | + |
| 3 | +<p>You are given two <strong>0-indexed</strong> arrays <code>nums1</code> and <code>nums2</code> of length <code>n</code>, both of which are <strong>permutations</strong> of <code>[0, 1, ..., n - 1]</code>.</p> |
| 4 | + |
| 5 | +<p>A <strong>good triplet</strong> is a set of <code>3</code> <strong>distinct</strong> values which are present in <strong>increasing order</strong> by position both in <code>nums1</code> and <code>nums2</code>. In other words, if we consider <code>pos1<sub>v</sub></code> as the index of the value <code>v</code> in <code>nums1</code> and <code>pos2<sub>v</sub></code> as the index of the value <code>v</code> in <code>nums2</code>, then a good triplet will be a set <code>(x, y, z)</code> where <code>0 <= x, y, z <= n - 1</code>, such that <code>pos1<sub>x</sub> < pos1<sub>y</sub> < pos1<sub>z</sub></code> and <code>pos2<sub>x</sub> < pos2<sub>y</sub> < pos2<sub>z</sub></code>.</p> |
| 6 | + |
| 7 | +<p>Return <em>the <strong>total number</strong> of good triplets</em>.</p> |
| 8 | + |
| 9 | +<p> </p> |
| 10 | +<p><strong>Example 1:</strong></p> |
| 11 | + |
| 12 | +<pre><strong>Input:</strong> nums1 = [2,0,1,3], nums2 = [0,1,2,3] |
| 13 | +<strong>Output:</strong> 1 |
| 14 | +<strong>Explanation:</strong> |
| 15 | +There are 4 triplets (x,y,z) such that pos1<sub>x</sub> < pos1<sub>y</sub> < pos1<sub>z</sub>. They are (2,0,1), (2,0,3), (2,1,3), and (0,1,3). |
| 16 | +Out of those triplets, only the triplet (0,1,3) satisfies pos2<sub>x</sub> < pos2<sub>y</sub> < pos2<sub>z</sub>. Hence, there is only 1 good triplet. |
| 17 | +</pre> |
| 18 | + |
| 19 | +<p><strong>Example 2:</strong></p> |
| 20 | + |
| 21 | +<pre><strong>Input:</strong> nums1 = [4,0,1,3,2], nums2 = [4,1,0,2,3] |
| 22 | +<strong>Output:</strong> 4 |
| 23 | +<strong>Explanation:</strong> The 4 good triplets are (4,0,3), (4,0,2), (4,1,3), and (4,1,2). |
| 24 | +</pre> |
| 25 | + |
| 26 | +<p> </p> |
| 27 | +<p><strong>Constraints:</strong></p> |
| 28 | + |
| 29 | +<ul> |
| 30 | + <li><code>n == nums1.length == nums2.length</code></li> |
| 31 | + <li><code>3 <= n <= 10<sup>5</sup></code></li> |
| 32 | + <li><code>0 <= nums1[i], nums2[i] <= n - 1</code></li> |
| 33 | + <li><code>nums1</code> and <code>nums2</code> are permutations of <code>[0, 1, ..., n - 1]</code>.</li> |
| 34 | +</ul> |
| 35 | + |
| 36 | + |
| 37 | +**Similar Questions**: |
| 38 | +* [Count of Smaller Numbers After Self (Hard)](https://leetcode.com/problems/count-of-smaller-numbers-after-self/) |
| 39 | +* [Increasing Triplet Subsequence (Medium)](https://leetcode.com/problems/increasing-triplet-subsequence/) |
| 40 | +* [Create Sorted Array through Instructions (Hard)](https://leetcode.com/problems/create-sorted-array-through-instructions/) |
| 41 | + |
| 42 | +## Solution 1. Divide and Conquer (Merge Sort) |
| 43 | + |
| 44 | + |
| 45 | +The first idea is that we pick a number as the middle number in the triplet, and count the common numbers in front of this number and after this number. |
| 46 | + |
| 47 | +For example, |
| 48 | + |
| 49 | +``` |
| 50 | +A = [4,0,1,3,2] |
| 51 | +B = [4,1,0,2,3] |
| 52 | +``` |
| 53 | + |
| 54 | +For number `1`, there is a single common number (`4`) in front of `1` and two common numbers (`3,4`) after `1`, so the count of triplets with `1` in the middle is `1 * 2 = 2`. |
| 55 | + |
| 56 | +But counting the common numbers is not easy. **Since the numbers are permutations of `[0, N-1]`, we can simplify the problem by mapping on of the array to `[0, N-1]`.** |
| 57 | + |
| 58 | +For example, if we map `A` to `[0, N-1]`. |
| 59 | + |
| 60 | +``` |
| 61 | +A = [4,0,1,3,2] |
| 62 | +A'= [0,1,2,3,4] |
| 63 | +mapping = 4->0, 0->1, 1->2, 3->3, 2->4 |
| 64 | +``` |
| 65 | + |
| 66 | +We apply the same mapping to `B` |
| 67 | + |
| 68 | +``` |
| 69 | +B = [4,1,0,2,3] |
| 70 | +B'= [0,2,1,4,3] |
| 71 | +``` |
| 72 | + |
| 73 | +Now look at the new arrays |
| 74 | + |
| 75 | +``` |
| 76 | +A = [0,1,2,3,4] |
| 77 | +B = [0,2,1,4,3] |
| 78 | +``` |
| 79 | + |
| 80 | +For the number `1`, we trivially know that in `A`, there is one number `0` before it and 3 numbers `2,3,4` after it. So, we just need to look at `B`. The problem now becomes counting the numbers smaller than `1` before `1` and numbers greater than `1` after `1`. |
| 81 | + |
| 82 | +Let `lt[i]` be the count of numbers smaller than `B[i]`. The count of common numbers before `B[i]` is `min(B[i], lt[i])`. The count of common numbers after `B[i]` in `A` is `N - B[i] - 1`. The count of common numbers after `B[i]` in `B` is `N - i - 1 - (B[i] - lt[i]) = N - B[i] - 1 - i + lt[i]`. Since `i >= lt[i]`, `-i + lt[i] <= 0`, the count of common numbers after `B[i]` in both arrays is `N - B[i] - 1 - i + lt[i]`. |
| 83 | + |
| 84 | +So, the count of triplets with `B[i]` as the middle number is `min(B[i], lt[i]) * (N - B[i] - 1 - i + lt[i])` |
| 85 | + |
| 86 | +```cpp |
| 87 | +// OJ: https://leetcode.com/problems/count-good-triplets-in-an-array/ |
| 88 | +// Author: github.com/lzl124631x |
| 89 | +// Time: O(NlogN) |
| 90 | +// Space: O(N) |
| 91 | +class Solution { |
| 92 | +public: |
| 93 | + long long goodTriplets(vector<int>& A, vector<int>& B) { |
| 94 | + long N = A.size(), ans = 0; |
| 95 | + vector<int> m(N), lt(N), tmp(N), tmpLt(N), index(N); |
| 96 | + for (int i = 0; i < N; ++i) m[A[i]] = i; |
| 97 | + for (int i = 0; i < N; ++i) { |
| 98 | + B[i] = m[B[i]]; |
| 99 | + index[B[i]] = i; |
| 100 | + } |
| 101 | + function<void(int, int)> merge = [&](int begin, int end) { |
| 102 | + if (begin + 1 >= end) return; |
| 103 | + int mid = (begin + end) / 2; |
| 104 | + merge(begin, mid); |
| 105 | + merge(mid, end); |
| 106 | + int i = begin, j = mid, k = begin; |
| 107 | + for (; k < end; ++k) { |
| 108 | + if (j >= end || (i < mid && B[i] < B[j])) { |
| 109 | + tmp[k] = B[i]; |
| 110 | + tmpLt[k] = lt[i]; |
| 111 | + ++i; |
| 112 | + } else { |
| 113 | + tmp[k] = B[j]; |
| 114 | + tmpLt[k] = lt[j] + i - begin; |
| 115 | + ++j; |
| 116 | + } |
| 117 | + } |
| 118 | + for (int i = begin; i < end; ++i) { |
| 119 | + B[i] = tmp[i]; |
| 120 | + lt[i] = tmpLt[i]; |
| 121 | + } |
| 122 | + }; |
| 123 | + merge(0, N); |
| 124 | + for (int i = 0; i < N; ++i) { |
| 125 | + ans += (long)min(B[i], lt[i]) * (N - B[i] - 1 - index[B[i]] + lt[i]); |
| 126 | + } |
| 127 | + return ans; |
| 128 | + } |
| 129 | +}; |
| 130 | +``` |
0 commit comments