Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit a0d941e

Browse files
feat: add solutions to lc problem: No.3312 (doocs#3606)
No.3312.Sorted GCD Pair Queries
1 parent 18de759 commit a0d941e

File tree

6 files changed

+340
-10
lines changed

6 files changed

+340
-10
lines changed

‎solution/3300-3399/3312.Sorted GCD Pair Queries/README.md‎

Lines changed: 118 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,32 +84,145 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3312.So
8484

8585
<!-- solution:start -->
8686

87-
### 方法一
87+
### 方法一:预处理 + 前缀和 + 二分查找
88+
89+
我们可以预处理得到数组 $\textit{nums}$ 中的所有数对的最大公约数的出现次数,记录在数组 $\textit{cntG}$ 中。然后,我们计算数组 $\textit{cntG}$ 的前缀和。最后,对于每个查询,我们可以通过二分查找在数组 $\textit{cntG}$ 中找到第一个大于 $\textit{queries}[i]$ 的元素的下标,即为答案。
90+
91+
我们用 $\textit{mx}$ 表示数组 $\textit{nums}$ 中的最大值,用 $\textit{cnt}$ 记录数组 $\textit{nums}$ 中每个数的出现次数。我们用 $\textit{cntG}[i]$ 表示数组 $\textit{nums}$ 中最大公约数等于 $i$ 的数对个数。为了计算 $\textit{cntG}[i],ドル我们可以按照以下步骤进行:
92+
93+
1. 计算数组 $\textit{nums}$ 中 $i$ 的倍数的出现次数 $v,ドル那么从这些元素中任选两个元素组成的数对一定满足最大公约数是 $i$ 的倍数,即 $\textit{cntG}[i]$ 需要增加 $v \times (v - 1) / 2$;
94+
1. 我们需要排除最大公约数是 $i$ 的倍数且大于 $i$ 的数对,因此,对于 $i$ 的倍数 $j,ドル我们需要减去 $\textit{cntG}[j]$。
95+
96+
以上需要我们从大到小遍历 $i,ドル这样才能保证我们在计算 $\textit{cntG}[i]$ 时已经计算了所有的 $\textit{cntG}[j]$。
97+
98+
最后,我们计算数组 $\textit{cntG}$ 的前缀和,然后对于每个查询,我们可以通过二分查找在数组 $\textit{cntG}$ 中找到第一个大于 $\textit{queries}[i]$ 的元素的下标,即为答案。
99+
100+
时间复杂度 $O(n + (M + q) \times \log M),ドル空间复杂度 $O(M)$。其中 $n$ 和 $M$ 分别是数组 $\textit{nums}$ 的长度和最大值,而 $q$ 是查询的数量。
88101

89102
<!-- tabs:start -->
90103

91104
#### Python3
92105

93106
```python
94-
107+
class Solution:
108+
def gcdValues(self, nums: List[int], queries: List[int]) -> List[int]:
109+
mx = max(nums)
110+
cnt = Counter(nums)
111+
cnt_g = [0] * (mx + 1)
112+
for i in range(mx, 0, -1):
113+
v = 0
114+
for j in range(i, mx + 1, i):
115+
v += cnt[j]
116+
cnt_g[i] -= cnt_g[j]
117+
cnt_g[i] += v * (v - 1) // 2
118+
s = list(accumulate(cnt_g))
119+
return [bisect_right(s, q) for q in queries]
95120
```
96121

97122
#### Java
98123

99124
```java
100-
125+
class Solution {
126+
public int[] gcdValues(int[] nums, long[] queries) {
127+
int mx = Arrays.stream(nums).max().getAsInt();
128+
int[] cnt = new int[mx + 1];
129+
long[] cntG = new long[mx + 1];
130+
for (int x : nums) {
131+
++cnt[x];
132+
}
133+
for (int i = mx; i > 0; --i) {
134+
int v = 0;
135+
for (int j = i; j <= mx; j += i) {
136+
v += cnt[j];
137+
cntG[i] -= cntG[j];
138+
}
139+
cntG[i] += 1L * v * (v - 1) / 2;
140+
}
141+
for (int i = 2; i <= mx; ++i) {
142+
cntG[i] += cntG[i - 1];
143+
}
144+
int m = queries.length;
145+
int[] ans = new int[m];
146+
for (int i = 0; i < m; ++i) {
147+
ans[i] = search(cntG, queries[i]);
148+
}
149+
return ans;
150+
}
151+
152+
private int search(long[] nums, long x) {
153+
int n = nums.length;
154+
int l = 0, r = n;
155+
while (l < r) {
156+
int mid = l + r >> 1;
157+
if (nums[mid] > x) {
158+
r = mid;
159+
} else {
160+
l = mid + 1;
161+
}
162+
}
163+
return l;
164+
}
165+
}
101166
```
102167

103168
#### C++
104169

105170
```cpp
106-
171+
class Solution {
172+
public:
173+
vector<int> gcdValues(vector<int>& nums, vector<long long>& queries) {
174+
int mx = ranges::max(nums);
175+
vector<int> cnt(mx + 1);
176+
vector<long long> cntG(mx + 1);
177+
for (int x : nums) {
178+
++cnt[x];
179+
}
180+
for (int i = mx; i; --i) {
181+
long long v = 0;
182+
for (int j = i; j <= mx; j += i) {
183+
v += cnt[j];
184+
cntG[i] -= cntG[j];
185+
}
186+
cntG[i] += 1LL * v * (v - 1) / 2;
187+
}
188+
for (int i = 2; i <= mx; ++i) {
189+
cntG[i] += cntG[i - 1];
190+
}
191+
vector<int> ans;
192+
for (auto&& q : queries) {
193+
ans.push_back(upper_bound(cntG.begin(), cntG.end(), q) - cntG.begin());
194+
}
195+
return ans;
196+
}
197+
};
107198
```
108199
109200
#### Go
110201
111202
```go
112-
203+
func gcdValues(nums []int, queries []int64) (ans []int) {
204+
mx := slices.Max(nums)
205+
cnt := make([]int, mx+1)
206+
cntG := make([]int, mx+1)
207+
for _, x := range nums {
208+
cnt[x]++
209+
}
210+
for i := mx; i > 0; i-- {
211+
var v int
212+
for j := i; j <= mx; j += i {
213+
v += cnt[j]
214+
cntG[i] -= cntG[j]
215+
}
216+
cntG[i] += v * (v - 1) / 2
217+
}
218+
for i := 2; i <= mx; i++ {
219+
cntG[i] += cntG[i-1]
220+
}
221+
for _, q := range queries {
222+
ans = append(ans, sort.SearchInts(cntG, int(q)+1))
223+
}
224+
return
225+
}
113226
```
114227

115228
<!-- tabs:end -->

‎solution/3300-3399/3312.Sorted GCD Pair Queries/README_EN.md‎

Lines changed: 118 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,32 +82,145 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3312.So
8282

8383
<!-- solution:start -->
8484

85-
### Solution 1
85+
### Solution 1: Preprocessing + Prefix Sum + Binary Search
86+
87+
We can preprocess to obtain the occurrence count of the greatest common divisor (GCD) of all pairs in the array $\textit{nums},ドル recorded in the array $\textit{cntG}$. Then, we calculate the prefix sum of the array $\textit{cntG}$. Finally, for each query, we can use binary search to find the index of the first element in the array $\textit{cntG}$ that is greater than $\textit{queries}[i],ドル which is the answer.
88+
89+
Let $\textit{mx}$ denote the maximum value in the array $\textit{nums},ドル and let $\textit{cnt}$ record the occurrence count of each number in the array $\textit{nums}$. Let $\textit{cntG}[i]$ denote the number of pairs in the array $\textit{nums}$ whose GCD is equal to $i$. To calculate $\textit{cntG}[i],ドル we can follow these steps:
90+
91+
1. Calculate the occurrence count $v$ of multiples of $i$ in the array $\textit{nums}$. Then, the number of pairs formed by any two elements from these multiples must have a GCD that is a multiple of $i,ドル i.e., $\textit{cntG}[i]$ needs to be increased by $v \times (v - 1) / 2$;
92+
2. We need to exclude pairs whose GCD is a multiple of $i$ and greater than $i$. Therefore, for multiples $j$ of $i,ドル we need to subtract $\textit{cntG}[j]$.
93+
94+
The above steps require us to traverse $i$ from large to small so that when calculating $\textit{cntG}[i],ドル we have already calculated all $\textit{cntG}[j]$.
95+
96+
Finally, we calculate the prefix sum of the array $\textit{cntG},ドル and for each query, we can use binary search to find the index of the first element in the array $\textit{cntG}$ that is greater than $\textit{queries}[i],ドル which is the answer.
97+
98+
The time complexity is $O(n + (M + q) \times \log M),ドル and the space complexity is $O(M)$. Here, $n$ and $M$ represent the length and the maximum value of the array $\textit{nums},ドル respectively, and $q$ represents the number of queries.
8699

87100
<!-- tabs:start -->
88101

89102
#### Python3
90103

91104
```python
92-
105+
class Solution:
106+
def gcdValues(self, nums: List[int], queries: List[int]) -> List[int]:
107+
mx = max(nums)
108+
cnt = Counter(nums)
109+
cnt_g = [0] * (mx + 1)
110+
for i in range(mx, 0, -1):
111+
v = 0
112+
for j in range(i, mx + 1, i):
113+
v += cnt[j]
114+
cnt_g[i] -= cnt_g[j]
115+
cnt_g[i] += v * (v - 1) // 2
116+
s = list(accumulate(cnt_g))
117+
return [bisect_right(s, q) for q in queries]
93118
```
94119

95120
#### Java
96121

97122
```java
98-
123+
class Solution {
124+
public int[] gcdValues(int[] nums, long[] queries) {
125+
int mx = Arrays.stream(nums).max().getAsInt();
126+
int[] cnt = new int[mx + 1];
127+
long[] cntG = new long[mx + 1];
128+
for (int x : nums) {
129+
++cnt[x];
130+
}
131+
for (int i = mx; i > 0; --i) {
132+
int v = 0;
133+
for (int j = i; j <= mx; j += i) {
134+
v += cnt[j];
135+
cntG[i] -= cntG[j];
136+
}
137+
cntG[i] += 1L * v * (v - 1) / 2;
138+
}
139+
for (int i = 2; i <= mx; ++i) {
140+
cntG[i] += cntG[i - 1];
141+
}
142+
int m = queries.length;
143+
int[] ans = new int[m];
144+
for (int i = 0; i < m; ++i) {
145+
ans[i] = search(cntG, queries[i]);
146+
}
147+
return ans;
148+
}
149+
150+
private int search(long[] nums, long x) {
151+
int n = nums.length;
152+
int l = 0, r = n;
153+
while (l < r) {
154+
int mid = l + r >> 1;
155+
if (nums[mid] > x) {
156+
r = mid;
157+
} else {
158+
l = mid + 1;
159+
}
160+
}
161+
return l;
162+
}
163+
}
99164
```
100165

101166
#### C++
102167

103168
```cpp
104-
169+
class Solution {
170+
public:
171+
vector<int> gcdValues(vector<int>& nums, vector<long long>& queries) {
172+
int mx = ranges::max(nums);
173+
vector<int> cnt(mx + 1);
174+
vector<long long> cntG(mx + 1);
175+
for (int x : nums) {
176+
++cnt[x];
177+
}
178+
for (int i = mx; i; --i) {
179+
long long v = 0;
180+
for (int j = i; j <= mx; j += i) {
181+
v += cnt[j];
182+
cntG[i] -= cntG[j];
183+
}
184+
cntG[i] += 1LL * v * (v - 1) / 2;
185+
}
186+
for (int i = 2; i <= mx; ++i) {
187+
cntG[i] += cntG[i - 1];
188+
}
189+
vector<int> ans;
190+
for (auto&& q : queries) {
191+
ans.push_back(upper_bound(cntG.begin(), cntG.end(), q) - cntG.begin());
192+
}
193+
return ans;
194+
}
195+
};
105196
```
106197
107198
#### Go
108199
109200
```go
110-
201+
func gcdValues(nums []int, queries []int64) (ans []int) {
202+
mx := slices.Max(nums)
203+
cnt := make([]int, mx+1)
204+
cntG := make([]int, mx+1)
205+
for _, x := range nums {
206+
cnt[x]++
207+
}
208+
for i := mx; i > 0; i-- {
209+
var v int
210+
for j := i; j <= mx; j += i {
211+
v += cnt[j]
212+
cntG[i] -= cntG[j]
213+
}
214+
cntG[i] += v * (v - 1) / 2
215+
}
216+
for i := 2; i <= mx; i++ {
217+
cntG[i] += cntG[i-1]
218+
}
219+
for _, q := range queries {
220+
ans = append(ans, sort.SearchInts(cntG, int(q)+1))
221+
}
222+
return
223+
}
111224
```
112225

113226
<!-- tabs:end -->
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class Solution {
2+
public:
3+
vector<int> gcdValues(vector<int>& nums, vector<long long>& queries) {
4+
int mx = ranges::max(nums);
5+
vector<int> cnt(mx + 1);
6+
vector<long long> cntG(mx + 1);
7+
for (int x : nums) {
8+
++cnt[x];
9+
}
10+
for (int i = mx; i; --i) {
11+
long long v = 0;
12+
for (int j = i; j <= mx; j += i) {
13+
v += cnt[j];
14+
cntG[i] -= cntG[j];
15+
}
16+
cntG[i] += 1LL * v * (v - 1) / 2;
17+
}
18+
for (int i = 2; i <= mx; ++i) {
19+
cntG[i] += cntG[i - 1];
20+
}
21+
vector<int> ans;
22+
for (auto&& q : queries) {
23+
ans.push_back(upper_bound(cntG.begin(), cntG.end(), q) - cntG.begin());
24+
}
25+
return ans;
26+
}
27+
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
func gcdValues(nums []int, queries []int64) (ans []int) {
2+
mx := slices.Max(nums)
3+
cnt := make([]int, mx+1)
4+
cntG := make([]int, mx+1)
5+
for _, x := range nums {
6+
cnt[x]++
7+
}
8+
for i := mx; i > 0; i-- {
9+
var v int
10+
for j := i; j <= mx; j += i {
11+
v += cnt[j]
12+
cntG[i] -= cntG[j]
13+
}
14+
cntG[i] += v * (v - 1) / 2
15+
}
16+
for i := 2; i <= mx; i++ {
17+
cntG[i] += cntG[i-1]
18+
}
19+
for _, q := range queries {
20+
ans = append(ans, sort.SearchInts(cntG, int(q)+1))
21+
}
22+
return
23+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
class Solution {
2+
public int[] gcdValues(int[] nums, long[] queries) {
3+
int mx = Arrays.stream(nums).max().getAsInt();
4+
int[] cnt = new int[mx + 1];
5+
long[] cntG = new long[mx + 1];
6+
for (int x : nums) {
7+
++cnt[x];
8+
}
9+
for (int i = mx; i > 0; --i) {
10+
int v = 0;
11+
for (int j = i; j <= mx; j += i) {
12+
v += cnt[j];
13+
cntG[i] -= cntG[j];
14+
}
15+
cntG[i] += 1L * v * (v - 1) / 2;
16+
}
17+
for (int i = 2; i <= mx; ++i) {
18+
cntG[i] += cntG[i - 1];
19+
}
20+
int m = queries.length;
21+
int[] ans = new int[m];
22+
for (int i = 0; i < m; ++i) {
23+
ans[i] = search(cntG, queries[i]);
24+
}
25+
return ans;
26+
}
27+
28+
private int search(long[] nums, long x) {
29+
int n = nums.length;
30+
int l = 0, r = n;
31+
while (l < r) {
32+
int mid = l + r >> 1;
33+
if (nums[mid] > x) {
34+
r = mid;
35+
} else {
36+
l = mid + 1;
37+
}
38+
}
39+
return l;
40+
}
41+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /