Skip to content

Commit c52646e

Browse files
committed
LeetCode 347: Top K Frequent Elements
1 parent c15f43b commit c52646e

7 files changed

Lines changed: 368 additions & 0 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.gd.leetcode.p0215;
2+
3+
import org.gd.leetcode.common.LeetCode;
4+
5+
/**
6+
* https://leetcode.com/problems/kth-largest-element-in-an-array/
7+
*
8+
* @author Horkhover Dmytro
9+
* @see org.gd.leetcode.p0347.Solution
10+
* @see org.gd.leetcode.p0692.Solution
11+
* @see org.gd.leetcode.p0973.Solution
12+
* @since 2020-08-10
13+
*/
14+
@SuppressWarnings("JavadocReference")
15+
@LeetCode(
16+
name = "Kth Largest Element in an Array",
17+
difficulty = LeetCode.Level.MEDIUM,
18+
state = LeetCode.State.TODO,
19+
tags = {
20+
LeetCode.Tags.DIVIDE_AND_CONQUER,
21+
LeetCode.Tags.HEAP
22+
}
23+
)
24+
class Solution {
25+
26+
public int findKthLargest(int[] nums, int k) {
27+
throw new UnsupportedOperationException(new String(new char[]{175, 92, 95, 40, 12_484, 41, 95, 47, 175}));
28+
}
29+
}
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
package org.gd.leetcode.p0347;
2+
3+
import java.util.*;
4+
5+
/**
6+
* @author Horkhover Dmytro
7+
* @see SortSolution
8+
* @since 2020-08-10
9+
*/
10+
class LinkedListSolution implements Solution {
11+
12+
private CountNode head, tail;
13+
14+
public int[] topKFrequent(final int[] nums, final int k) {
15+
16+
if (nums == null || nums.length == 0)
17+
return nums;
18+
19+
head = tail = new CountNode(-1);
20+
CountNode.connect(head, tail);
21+
head.insertRight(new CountNode(0));
22+
23+
Map<Integer, Node> nodeMap = new HashMap<>(nums.length);
24+
25+
for (int num : nums) {
26+
27+
Node node = nodeMap.get(num);
28+
if (node == null) {
29+
30+
node = new Node(num);
31+
head.next(0).add(node);
32+
nodeMap.putIfAbsent(num, node);
33+
34+
} else {
35+
36+
CountNode parent = node.parent;
37+
node.unlink();
38+
parent.next().add(node);
39+
if (parent.isEmpty())
40+
parent.unlink();
41+
}
42+
}
43+
44+
int i = 0;
45+
int[] result = new int[Math.min(k, nodeMap.size())];
46+
Iterator<Node> iterator = new DownIterator(tail);
47+
while (iterator.hasNext() && i < result.length)
48+
result[i++] = iterator.next().value;
49+
50+
return result;
51+
}
52+
53+
@Override
54+
public String toString() {
55+
StringJoiner sj = new StringJoiner(", ", "[", "]");
56+
CountNode next = head.next;
57+
while (next != tail) {
58+
sj.add(next.toString());
59+
next = next.next;
60+
}
61+
return sj.toString();
62+
}
63+
64+
static class CountNode {
65+
final int count;
66+
CountNode prev, next;
67+
Node head, tail;
68+
69+
CountNode(int count) {
70+
this.count = count;
71+
head = tail = new Node(-1, this);
72+
Node.connect(head, tail);
73+
}
74+
75+
static void connect(CountNode prev, CountNode next) {
76+
if (prev != null)
77+
prev.next = next;
78+
if (next != null)
79+
next.prev = prev;
80+
}
81+
82+
boolean isEmpty() {
83+
return head.next == tail;
84+
}
85+
86+
CountNode next() {
87+
return next(count + 1);
88+
}
89+
90+
CountNode next(int count) {
91+
if (next.count == count)
92+
return next;
93+
94+
CountNode next = new CountNode(count);
95+
insertRight(next);
96+
return next;
97+
}
98+
99+
void insertRight(CountNode node) {
100+
connect(node, next);
101+
connect(this, node);
102+
}
103+
104+
void add(Node node) {
105+
node.parent = this;
106+
head.insertRight(node);
107+
}
108+
109+
void unlink() {
110+
connect(prev, next);
111+
prev = null;
112+
next = null;
113+
}
114+
115+
@Override
116+
public String toString() {
117+
StringJoiner sj = new StringJoiner(", ", count + " -> [", "]");
118+
Node next = head.next;
119+
while (next != tail) {
120+
sj.add("" + next.value);
121+
next = next.next;
122+
}
123+
return sj.toString();
124+
}
125+
}
126+
127+
static class Node {
128+
129+
final int value;
130+
CountNode parent;
131+
Node prev, next;
132+
133+
Node(int value) {
134+
this.value = value;
135+
}
136+
137+
Node(int value, CountNode parent) {
138+
this.value = value;
139+
this.parent = parent;
140+
}
141+
142+
static void connect(Node prev, Node next) {
143+
if (prev != null)
144+
prev.next = next;
145+
if (next != null)
146+
next.prev = prev;
147+
}
148+
149+
void insertRight(Node node) {
150+
node.parent = parent;
151+
Node next = this.next;
152+
connect(this, node);
153+
connect(node, next);
154+
}
155+
156+
void unlink() {
157+
connect(prev, next);
158+
prev = null;
159+
next = null;
160+
parent = null;
161+
}
162+
}
163+
164+
static class DownIterator implements Iterator<Node> {
165+
166+
CountNode countNode;
167+
Node node = null;
168+
169+
DownIterator(CountNode countNode) {
170+
this.countNode = countNode;
171+
}
172+
173+
@Override
174+
public boolean hasNext() {
175+
if (countNode == null)
176+
return false;
177+
178+
if (node == null)
179+
node = countNode.tail.prev;
180+
181+
if (node != countNode.head)
182+
return true;
183+
184+
node = null;
185+
countNode = countNode.prev;
186+
return hasNext();
187+
}
188+
189+
@Override
190+
public Node next() {
191+
if (!hasNext())
192+
throw new NoSuchElementException();
193+
194+
Node value = this.node;
195+
this.node = this.node.prev;
196+
return value;
197+
}
198+
}
199+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.gd.leetcode.p0347;
2+
3+
import org.gd.leetcode.common.LeetCode;
4+
5+
/**
6+
* @author Horkhover Dmytro
7+
* @see org.gd.leetcode.p0215.Solution
8+
* @see org.gd.leetcode.p0692.Solution
9+
* @see org.gd.leetcode.p0973.Solution
10+
* @since 2020-08-10
11+
*/
12+
@SuppressWarnings("JavadocReference")
13+
@LeetCode(
14+
name = "Top K Frequent Elements",
15+
difficulty = LeetCode.Level.MEDIUM,
16+
state = LeetCode.State.DONE,
17+
tags = {
18+
LeetCode.Tags.HASH_TABLE,
19+
LeetCode.Tags.HEAP
20+
}
21+
)
22+
interface Solution {
23+
24+
int[] topKFrequent(int[] nums, int k);
25+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.gd.leetcode.p0347;
2+
3+
import java.util.Arrays;
4+
import java.util.HashMap;
5+
import java.util.Map;
6+
7+
/**
8+
* @author Horkhover Dmytro
9+
* @see LinkedListSolution
10+
* @since 2020-08-10
11+
*/
12+
class SortSolution implements Solution {
13+
14+
public int[] topKFrequent(int[] nums, int k) {
15+
16+
Integer[] arr = new Integer[nums.length];
17+
Map<Integer, Integer> counts = new HashMap<>();
18+
int length = 0;
19+
20+
for (int num : nums)
21+
if (counts.compute(num, (ignored, c) -> 1 + (c == null ? 0 : c)) == 1)
22+
arr[length++] = num;
23+
24+
Arrays.sort(arr, 0, length, (o1, o2) -> Integer.compare(counts.get(o2), counts.get(o1)));
25+
26+
int[] result = new int[Math.min(length, k)];
27+
for (int i = 0; i < result.length; i++)
28+
result[i] = arr[i];
29+
30+
return result;
31+
}
32+
}

src/main/java/org/gd/leetcode/p0692/Solution.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
* https://leetcode.com/problems/top-k-frequent-words/
99
*
1010
* @author Horkhover Dmytro
11+
* @see org.gd.leetcode.p0347.Solution
12+
* @see org.gd.leetcode.p0973.Solution
1113
* @since 2020-08-09
1214
*/
15+
@SuppressWarnings("JavadocReference")
1316
@LeetCode(
1417
name = "Top K Frequent Words",
1518
difficulty = LeetCode.Level.MEDIUM,
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.gd.leetcode.p0973;
2+
3+
import org.gd.leetcode.common.LeetCode;
4+
5+
/**
6+
* https://leetcode.com/problems/k-closest-points-to-origin/
7+
*
8+
* @author Horkhover Dmytro
9+
* @see org.gd.leetcode.p0347.Solution
10+
* @see org.gd.leetcode.p0692.Solution
11+
* @since 2020-08-10
12+
*/
13+
@SuppressWarnings("JavadocReference")
14+
@LeetCode(
15+
name = "K Closest Points to Origin",
16+
difficulty = LeetCode.Level.MEDIUM,
17+
state = LeetCode.State.TODO,
18+
tags = {
19+
LeetCode.Tags.HEAP,
20+
LeetCode.Tags.SORT,
21+
LeetCode.Tags.DIVIDE_AND_CONQUER
22+
}
23+
)
24+
class Solution {
25+
26+
public int[][] kClosest(int[][] points, int K) {
27+
throw new UnsupportedOperationException(new String(new char[]{175, 92, 95, 40, 12_484, 41, 95, 47, 175}));
28+
}
29+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package org.gd.leetcode.p0347;
2+
3+
import org.gd.common.CollectionUtils;
4+
import org.junit.jupiter.api.*;
5+
import org.junit.jupiter.params.ParameterizedTest;
6+
import org.junit.jupiter.params.provider.Arguments;
7+
import org.junit.jupiter.params.provider.MethodSource;
8+
9+
import java.util.Arrays;
10+
import java.util.List;
11+
import java.util.concurrent.TimeUnit;
12+
import java.util.stream.Stream;
13+
14+
import static org.junit.jupiter.api.Assertions.*;
15+
16+
/**
17+
* Test for {@link Solution}
18+
*
19+
* @author Horkhover Dmytro
20+
* @since 2020-08-10
21+
*/
22+
@DisplayName("LeetCode #347: Top K Frequent Elements")
23+
@Timeout(value = 100, unit = TimeUnit.MILLISECONDS)
24+
class SolutionTest {
25+
26+
private static Stream<Arguments> args() {
27+
return Stream.of(
28+
Arguments.of(new int[]{1, 1, 2, 2, 3}, 2, new int[]{1, 2}),
29+
Arguments.of(new int[]{1, 1, 1, 2, 2, 3}, 2, new int[]{1, 2})
30+
);
31+
}
32+
33+
private static List<Integer> listOf(int[] arr) {
34+
Arrays.sort(arr);
35+
return CollectionUtils.listOf(arr);
36+
}
37+
38+
@ParameterizedTest
39+
@MethodSource("args")
40+
@DisplayName("O( N )")
41+
void test_LinkedListSolution(int[] nums, int k, int[] expected) {
42+
assertEquals(listOf(expected), listOf(new LinkedListSolution().topKFrequent(nums, k)));
43+
}
44+
45+
@ParameterizedTest
46+
@MethodSource("args")
47+
@DisplayName("O( N * Log(N) )")
48+
void test_SortSolution(int[] nums, int k, int[] expected) {
49+
assertEquals(listOf(expected), listOf(new SortSolution().topKFrequent(nums, k)));
50+
}
51+
}

0 commit comments

Comments
 (0)