Skip to content

Commit 7a2c597

Browse files
committed
feat: add solution 1998. GCD Sort of an Array
1 parent 4b1e2a2 commit 7a2c597

File tree

2 files changed

+221
-0
lines changed

2 files changed

+221
-0
lines changed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# [1998. GCD Sort of an Array](https://leetcode.com/problems/gcd-sort-of-an-array)
2+
3+
## Description
4+
5+
<div class="elfjS" data-track-load="description_content"><p>You are given an integer array <code>nums</code>, and you can perform the following operation <strong>any</strong> number of times on <code>nums</code>:</p>
6+
7+
<ul>
8+
<li>Swap the positions of two elements <code>nums[i]</code> and <code>nums[j]</code> if <code>gcd(nums[i], nums[j]) &gt; 1</code> where <code>gcd(nums[i], nums[j])</code> is the <strong>greatest common divisor</strong> of <code>nums[i]</code> and <code>nums[j]</code>.</li>
9+
</ul>
10+
11+
<p>Return <code>true</code> <em>if it is possible to sort </em><code>nums</code><em> in <strong>non-decreasing</strong> order using the above swap method, or </em><code>false</code><em> otherwise.</em></p>
12+
13+
<p>&nbsp;</p>
14+
<p><strong class="example">Example 1:</strong></p>
15+
16+
<pre><strong>Input:</strong> nums = [7,21,3]
17+
<strong>Output:</strong> true
18+
<strong>Explanation:</strong> We can sort [7,21,3] by performing the following operations:
19+
- Swap 7 and 21 because gcd(7,21) = 7. nums = [<u><strong>21</strong></u>,<u><strong>7</strong></u>,3]
20+
- Swap 21 and 3 because gcd(21,3) = 3. nums = [<u><strong>3</strong></u>,7,<u><strong>21</strong></u>]
21+
</pre>
22+
23+
<p><strong class="example">Example 2:</strong></p>
24+
25+
<pre><strong>Input:</strong> nums = [5,2,6,2]
26+
<strong>Output:</strong> false
27+
<strong>Explanation:</strong> It is impossible to sort the array because 5 cannot be swapped with any other element.
28+
</pre>
29+
30+
<p><strong class="example">Example 3:</strong></p>
31+
32+
<pre><strong>Input:</strong> nums = [10,5,9,3,15]
33+
<strong>Output:</strong> true
34+
We can sort [10,5,9,3,15] by performing the following operations:
35+
- Swap 10 and 15 because gcd(10,15) = 5. nums = [<u><strong>15</strong></u>,5,9,3,<u><strong>10</strong></u>]
36+
- Swap 15 and 3 because gcd(15,3) = 3. nums = [<u><strong>3</strong></u>,5,9,<u><strong>15</strong></u>,10]
37+
- Swap 10 and 15 because gcd(10,15) = 5. nums = [3,5,9,<u><strong>10</strong></u>,<u><strong>15</strong></u>]
38+
</pre>
39+
40+
<p>&nbsp;</p>
41+
<p><strong>Constraints:</strong></p>
42+
43+
<ul>
44+
<li><code>1 &lt;= nums.length &lt;= 3 * 10<sup>4</sup></code></li>
45+
<li><code>2 &lt;= nums[i] &lt;= 10<sup>5</sup></code></li>
46+
</ul>
47+
</div>
48+
49+
<p>&nbsp;</p>
50+
51+
## Solutions
52+
53+
**Solution: `Union Find + Sieve of Eratosthenes`**
54+
55+
- Time complexity: <em>O(nlogn+nlogMax(nums)+Max(nums)log(logMax(nums)))</em>
56+
- Space complexity: <em>O(n+Max(nums))</em>
57+
58+
<p>&nbsp;</p>
59+
60+
### **JavaScript**
61+
62+
```js
63+
/**
64+
* @param {number[]} nums
65+
* @return {boolean}
66+
*/
67+
const gcdSort = function (nums) {
68+
const maxNum = Math.max(...nums);
69+
const sortedNums = [...nums].sort((a, b) => a - b);
70+
const uf = new UnionFind(maxNum + 1);
71+
const minPrimeSieve = Array.from({ length: maxNum + 1 }, (_, index) => index);
72+
73+
minPrimeSieve[0] = 0;
74+
minPrimeSieve[1] = 0;
75+
76+
const getPrimeFactors = num => {
77+
const result = [];
78+
79+
while (num > 1) {
80+
const prime = minPrimeSieve[num];
81+
82+
result.push(prime);
83+
84+
while (num % prime === 0) {
85+
num /= prime;
86+
}
87+
}
88+
89+
return result;
90+
};
91+
92+
for (let num = 2; num * num <= maxNum; num++) {
93+
if (minPrimeSieve[num] !== num) continue;
94+
95+
for (let factor = num * num; factor <= maxNum; factor += num) {
96+
minPrimeSieve[factor] = num;
97+
}
98+
}
99+
100+
for (const num of nums) {
101+
const primeFactors = getPrimeFactors(num);
102+
103+
for (const factor of primeFactors) {
104+
uf.union(num, factor);
105+
}
106+
}
107+
108+
return nums.every((num, index) => uf.find(num) === uf.find(sortedNums[index]));
109+
};
110+
111+
class UnionFind {
112+
constructor(n) {
113+
this.groups = Array.from({ length: n }, (_, index) => index);
114+
this.ranks = Array.from({ length: n }, () => 0);
115+
}
116+
117+
find(node) {
118+
if (this.groups[node] === node) return node;
119+
const group = this.find(this.groups[node]);
120+
121+
this.groups[node] = group;
122+
return group;
123+
}
124+
125+
union(a, b) {
126+
const groupA = this.find(a);
127+
const groupB = this.find(b);
128+
129+
if (groupA === groupB) return false;
130+
if (this.ranks[groupA] > this.ranks[groupB]) {
131+
this.groups[groupB] = groupA;
132+
} else if (this.ranks[groupA] < this.ranks[groupB]) {
133+
this.groups[groupA] = groupB;
134+
} else {
135+
this.groups[groupB] = groupA;
136+
this.ranks[groupA] += 1;
137+
}
138+
139+
return true;
140+
}
141+
}
142+
```
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* @param {number[]} nums
3+
* @return {boolean}
4+
*/
5+
const gcdSort = function (nums) {
6+
const maxNum = Math.max(...nums);
7+
const sortedNums = [...nums].sort((a, b) => a - b);
8+
const uf = new UnionFind(maxNum + 1);
9+
const minPrimeSieve = Array.from({ length: maxNum + 1 }, (_, index) => index);
10+
11+
minPrimeSieve[0] = 0;
12+
minPrimeSieve[1] = 0;
13+
14+
const getPrimeFactors = num => {
15+
const result = [];
16+
17+
while (num > 1) {
18+
const prime = minPrimeSieve[num];
19+
20+
result.push(prime);
21+
22+
while (num % prime === 0) {
23+
num /= prime;
24+
}
25+
}
26+
27+
return result;
28+
};
29+
30+
for (let num = 2; num * num <= maxNum; num++) {
31+
if (minPrimeSieve[num] !== num) continue;
32+
33+
for (let factor = num * num; factor <= maxNum; factor += num) {
34+
minPrimeSieve[factor] = num;
35+
}
36+
}
37+
38+
for (const num of nums) {
39+
const primeFactors = getPrimeFactors(num);
40+
41+
for (const factor of primeFactors) {
42+
uf.union(num, factor);
43+
}
44+
}
45+
46+
return nums.every((num, index) => uf.find(num) === uf.find(sortedNums[index]));
47+
};
48+
49+
class UnionFind {
50+
constructor(n) {
51+
this.groups = Array.from({ length: n }, (_, index) => index);
52+
this.ranks = Array.from({ length: n }, () => 0);
53+
}
54+
55+
find(node) {
56+
if (this.groups[node] === node) return node;
57+
const group = this.find(this.groups[node]);
58+
59+
this.groups[node] = group;
60+
return group;
61+
}
62+
63+
union(a, b) {
64+
const groupA = this.find(a);
65+
const groupB = this.find(b);
66+
67+
if (groupA === groupB) return false;
68+
if (this.ranks[groupA] > this.ranks[groupB]) {
69+
this.groups[groupB] = groupA;
70+
} else if (this.ranks[groupA] < this.ranks[groupB]) {
71+
this.groups[groupA] = groupB;
72+
} else {
73+
this.groups[groupB] = groupA;
74+
this.ranks[groupA] += 1;
75+
}
76+
77+
return true;
78+
}
79+
}

0 commit comments

Comments
 (0)