Skip to content

Commit 8d2d3f3

Browse files
committed
feat: add solutions to lc problem: No.2179
No.2179.Count Good Triplets in an Array
1 parent e072993 commit 8d2d3f3

File tree

2 files changed

+473
-11
lines changed

2 files changed

+473
-11
lines changed

solution/2100-2199/2179.Count Good Triplets in an Array/README.md

+241-10
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,6 @@
4545

4646
<!-- 这里可写通用的实现逻辑 -->
4747

48-
本题可以用树状数组解决。
49-
50-
树状数组,也称作“二叉索引树”(Binary Indexed Tree)或 Fenwick 树。 它可以高效地实现如下两个操作:
51-
52-
1. **单点更新** `update(x, delta)`: 把序列 x 位置的数加上一个值 delta;
53-
1. **前缀和查询** `query(x)`:查询序列 `[1,...x]` 区间的区间和,即位置 x 的前缀和。
54-
55-
这两个操作的时间复杂度均为 `O(log n)`
56-
5748
对于本题,我们先用 pos 记录每个数在 nums2 中的位置,然后依次对 nums1 中的每个元素进行处理。
5849

5950
考虑**以当前数字作为三元组中间数字**的好三元组的数目。第一个数字需要是之前已经遍历过的,并且在 nums2 中的位置比当前数字更靠前的;第三个数字需要是当前还没有遍历过的,并且在 nums2 中的位置比当前数字更靠后的。
@@ -66,14 +57,25 @@
6657
1. ...
6758
1. 最后是 2,此时 nums2 中出现情况为 `[4,1,0,2,3]`,2 之前有值的个数是 4,2 之后没有值的个数是 0。因此以 2 为中间数字能形成 0 个好三元组。
6859

69-
我们可以用树状数组来更新 nums2 中各个位置数字的出现情况,快速算出每个数字左侧 1 的个数,以及右侧 0 的个数。
60+
我们可以用**树状数组****线段树**来更新 nums2 中各个位置数字的出现情况,快速算出每个数字左侧 1 的个数,以及右侧 0 的个数。
61+
62+
树状数组,也称作“二叉索引树”(Binary Indexed Tree)或 Fenwick 树。 它可以高效地实现如下两个操作:
63+
64+
1. **单点更新** `update(x, delta)`: 把序列 x 位置的数加上一个值 delta;
65+
1. **前缀和查询** `query(x)`:查询序列 `[1,...x]` 区间的区间和,即位置 x 的前缀和。
66+
67+
这两个操作的时间复杂度均为 `O(log n)`
68+
69+
> 本题 Python3 线段树代码 TLE。
7070
7171
<!-- tabs:start -->
7272

7373
### **Python3**
7474

7575
<!-- 这里可写当前语言的特殊实现逻辑 -->
7676

77+
树状数组:
78+
7779
```python
7880
class BinaryIndexedTree:
7981
def __init__(self, n):
@@ -112,10 +114,75 @@ class Solution:
112114
return ans
113115
```
114116

117+
线段树:
118+
119+
```python
120+
class Node:
121+
def __init__(self):
122+
self.l = 0
123+
self.r = 0
124+
self.v = 0
125+
126+
class SegmentTree:
127+
def __init__(self, n):
128+
self.tr = [Node() for _ in range(4 * n)]
129+
self.build(1, 1, n)
130+
131+
def build(self, u, l, r):
132+
self.tr[u].l = l
133+
self.tr[u].r = r
134+
if l == r:
135+
return
136+
mid = (l + r) >> 1
137+
self.build(u << 1, l, mid)
138+
self.build(u << 1 | 1, mid + 1, r)
139+
140+
def modify(self, u, x, v):
141+
if self.tr[u].l == x and self.tr[u].r == x:
142+
self.tr[u].v += v
143+
return
144+
mid = (self.tr[u].l + self.tr[u].r) >> 1
145+
if x <= mid:
146+
self.modify(u << 1, x, v)
147+
else:
148+
self.modify(u << 1 | 1, x, v)
149+
self.pushup(u)
150+
151+
def pushup(self, u):
152+
self.tr[u].v = self.tr[u << 1].v + self.tr[u << 1 | 1].v
153+
154+
def query(self, u, l, r):
155+
if self.tr[u].l >= l and self.tr[u].r <= r:
156+
return self.tr[u].v
157+
mid = (self.tr[u].l + self.tr[u].r) >> 1
158+
v = 0
159+
if l <= mid:
160+
v += self.query(u << 1, l, r)
161+
if r > mid:
162+
v += self.query(u << 1 | 1, l, r)
163+
return v
164+
165+
class Solution:
166+
def goodTriplets(self, nums1: List[int], nums2: List[int]) -> int:
167+
pos = {v: i for i, v in enumerate(nums2, 1)}
168+
ans = 0
169+
n = len(nums1)
170+
tree = SegmentTree(n)
171+
for num in nums1:
172+
p = pos[num]
173+
left = tree.query(1, 1, p)
174+
right = n - p - (tree.query(1, 1, n) - tree.query(1, 1, p))
175+
ans += left * right
176+
tree.modify(1, p, 1)
177+
return ans
178+
```
179+
115180
### **Java**
116181

117182
<!-- 这里可写当前语言的特殊实现逻辑 -->
118183

184+
树状数组:
185+
119186
```java
120187
class Solution {
121188
public long goodTriplets(int[] nums1, int[] nums2) {
@@ -168,8 +235,96 @@ class BinaryIndexedTree {
168235
}
169236
```
170237

238+
线段树:
239+
240+
```java
241+
class Solution {
242+
public long goodTriplets(int[] nums1, int[] nums2) {
243+
int n = nums1.length;
244+
int[] pos = new int[n];
245+
SegmentTree tree = new SegmentTree(n);
246+
for (int i = 0; i < n; ++i) {
247+
pos[nums2[i]] = i + 1;
248+
}
249+
long ans = 0;
250+
for (int num : nums1) {
251+
int p = pos[num];
252+
long left = tree.query(1, 1, p);
253+
long right = n - p - (tree.query(1, 1, n) - tree.query(1, 1, p));
254+
ans += left * right;
255+
tree.modify(1, p, 1);
256+
}
257+
return ans;
258+
}
259+
}
260+
261+
class Node {
262+
int l;
263+
int r;
264+
int v;
265+
}
266+
267+
class SegmentTree {
268+
private Node[] tr;
269+
270+
public SegmentTree(int n) {
271+
tr = new Node[4 * n];
272+
for (int i = 0; i < tr.length; ++i) {
273+
tr[i] = new Node();
274+
}
275+
build(1, 1, n);
276+
}
277+
278+
public void build(int u, int l, int r) {
279+
tr[u].l = l;
280+
tr[u].r = r;
281+
if (l == r) {
282+
return;
283+
}
284+
int mid = (l + r) >> 1;
285+
build(u << 1, l, mid);
286+
build(u << 1 | 1, mid + 1, r);
287+
}
288+
289+
public void modify(int u, int x, int v) {
290+
if (tr[u].l == x && tr[u].r == x) {
291+
tr[u].v += v;
292+
return;
293+
}
294+
int mid = (tr[u].l + tr[u].r) >> 1;
295+
if (x <= mid) {
296+
modify(u << 1, x, v);
297+
} else {
298+
modify(u << 1 | 1, x, v);
299+
}
300+
pushup(u);
301+
}
302+
303+
public void pushup(int u) {
304+
tr[u].v = tr[u << 1].v + tr[u << 1 | 1].v;
305+
}
306+
307+
public int query(int u, int l, int r) {
308+
if (tr[u].l >= l && tr[u].r <= r) {
309+
return tr[u].v;
310+
}
311+
int mid = (tr[u].l + tr[u].r) >> 1;
312+
int v = 0;
313+
if (l <= mid) {
314+
v += query(u << 1, l, r);
315+
}
316+
if (r > mid) {
317+
v += query(u << 1 | 1, l, r);
318+
}
319+
return v;
320+
}
321+
}
322+
```
323+
171324
### **C++**
172325

326+
树状数组:
327+
173328
```cpp
174329
class BinaryIndexedTree {
175330
public:
@@ -222,6 +377,82 @@ public:
222377
};
223378
```
224379
380+
线段树:
381+
382+
```cpp
383+
class Node {
384+
public:
385+
int l;
386+
int r;
387+
int v;
388+
};
389+
390+
class SegmentTree {
391+
public:
392+
vector<Node*> tr;
393+
394+
SegmentTree(int n) {
395+
tr.resize(4 * n);
396+
for (int i = 0; i < tr.size(); ++i) tr[i] = new Node();
397+
build(1, 1, n);
398+
}
399+
400+
void build(int u, int l, int r) {
401+
tr[u]->l = l;
402+
tr[u]->r = r;
403+
if (l == r) return;
404+
int mid = (l + r) >> 1;
405+
build(u << 1, l, mid);
406+
build(u << 1 | 1, mid + 1, r);
407+
}
408+
409+
void modify(int u, int x, int v) {
410+
if (tr[u]->l == x && tr[u]->r == x)
411+
{
412+
tr[u]->v += v;
413+
return;
414+
}
415+
int mid = (tr[u]->l + tr[u]->r) >> 1;
416+
if (x <= mid) modify(u << 1, x, v);
417+
else modify(u << 1 | 1, x, v);
418+
pushup(u);
419+
}
420+
421+
void pushup(int u) {
422+
tr[u]->v = tr[u << 1]->v + tr[u << 1 | 1]->v;
423+
}
424+
425+
int query(int u, int l, int r) {
426+
if (tr[u]->l >= l && tr[u]->r <= r) return tr[u]->v;
427+
int mid = (tr[u]->l + tr[u]->r) >> 1;
428+
int v = 0;
429+
if (l <= mid) v += query(u << 1, l, r);
430+
if (r > mid) v += query(u << 1 | 1, l, r);
431+
return v;
432+
}
433+
};
434+
435+
class Solution {
436+
public:
437+
long long goodTriplets(vector<int>& nums1, vector<int>& nums2) {
438+
int n = nums1.size();
439+
vector<int> pos(n);
440+
for (int i = 0; i < n; ++i) pos[nums2[i]] = i + 1;
441+
SegmentTree* tree = new SegmentTree(n);
442+
long long ans = 0;
443+
for (int& num : nums1)
444+
{
445+
int p = pos[num];
446+
int left = tree->query(1, 1, p);
447+
int right = n - p - (tree->query(1, 1, n) - tree->query(1, 1, p));
448+
ans += 1ll * left * right;
449+
tree->modify(1, p, 1);
450+
}
451+
return ans;
452+
}
453+
};
454+
```
455+
225456
### **Go**
226457

227458
```go

0 commit comments

Comments
 (0)