Skip to content

Commit ead61d9

Browse files
authored
Merge branch 'DaleStudy:main' into main
2 parents facd449 + 004452c commit ead61d9

File tree

13 files changed

+549
-0
lines changed

13 files changed

+549
-0
lines changed

3sum/TonyKim9401.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// TC: O(n^2)
2+
// SC: O(n)
3+
public class Solution {
4+
public List<List<Integer>> threeSum(int[] nums) {
5+
6+
Arrays.sort(nums);
7+
8+
List<List<Integer>> output = new ArrayList<>();
9+
Map<Integer, Integer> map = new HashMap<>();
10+
11+
for (int i = 0; i < nums.length; ++i) map.put(nums[i], i);
12+
13+
for (int i = 0; i < nums.length - 2; ++i) {
14+
if (nums[i] > 0) break;
15+
16+
for (int j = i + 1; j < nums.length - 1; ++j) {
17+
int cValue = -1 * (nums[i] + nums[j]);
18+
19+
if (map.containsKey(cValue) && map.get(cValue) > j) {
20+
output.add(List.of(nums[i], nums[j], cValue));
21+
}
22+
j = map.get(nums[j]);
23+
}
24+
25+
i = map.get(nums[i]);
26+
}
27+
28+
return output;
29+
}
30+
}

3sum/jdalma.kt

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder
4+
import org.junit.jupiter.api.Test
5+
6+
class `3sum` {
7+
8+
fun threeSum(nums: IntArray): List<List<Int>> {
9+
return usingTwoPointer(nums)
10+
}
11+
12+
/**
13+
* 1. 정수 배열을 순회하며 모두 확인한다. (시간초과)
14+
* TC: O(n^3), SC: O(n)
15+
*/
16+
private fun usingIterative(nums: IntArray): List<List<Int>> {
17+
val result = mutableSetOf<List<Int>>()
18+
for (first in nums.indices) {
19+
for (second in first + 1 until nums.size) {
20+
for (third in second + 1 until nums.size) {
21+
if (nums[first] + nums[second] + nums[third] == 0) {
22+
result.add(listOf(nums[first], nums[second], nums[third]).sorted())
23+
}
24+
}
25+
}
26+
}
27+
return result.toList()
28+
}
29+
30+
/**
31+
* 2. 입력받은 정수 배열을 정렬하여 순회하면서 원소를 합산하여 0과 비교한 결과를 기준으로 투 포인터의 값을 조작한다.
32+
* TC: O(n^2), SC: O(n)
33+
*/
34+
private fun usingTwoPointer(nums: IntArray): List<List<Int>> {
35+
val sortedNumbers = nums.sorted()
36+
val result = mutableSetOf<List<Int>>()
37+
for (index in nums.indices) {
38+
var left = index + 1
39+
var right = nums.size - 1
40+
while (left < right) {
41+
val sum = sortedNumbers[index] + sortedNumbers[left] + sortedNumbers[right]
42+
if (sum == 0) {
43+
result.add(listOf(sortedNumbers[index], sortedNumbers[left], sortedNumbers[right]))
44+
left++
45+
right--
46+
} else if (sum < 0) {
47+
left++
48+
} else {
49+
right--
50+
}
51+
}
52+
}
53+
return result.toList()
54+
}
55+
56+
@Test
57+
fun `입력받은 정수 배열의 세 개의 원소의 합이 0이 되는 리스트를 반환한다`() {
58+
threeSum(intArrayOf(-1,0,1,2,-1,-4)) shouldContainExactlyInAnyOrder listOf(
59+
listOf(-1,-1,2),
60+
listOf(-1,0,1)
61+
)
62+
threeSum(intArrayOf(0,0,0)) shouldContainExactlyInAnyOrder listOf(
63+
listOf(0,0,0)
64+
)
65+
}
66+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// TC: O(n)
2+
// SC: O(1)
3+
class Solution {
4+
public int maxProfit(int[] prices) {
5+
int bestProfit = 0;
6+
int buyPrice = prices[0];
7+
for (int i = 1; i < prices.length; i++) {
8+
if (buyPrice > prices[i]) {
9+
buyPrice = prices[i];
10+
continue;
11+
}
12+
bestProfit = Math.max(bestProfit, prices[i] - buyPrice);
13+
}
14+
return bestProfit;
15+
}
16+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
import kotlin.math.max
6+
7+
class `best-time-to-buy-and-sell-stock` {
8+
9+
fun maxProfit(prices: IntArray): Int {
10+
if (prices.size == 1) return 0
11+
return usingKadaneAlgorithm(prices)
12+
}
13+
14+
/**
15+
* 1. 방향이 존재하기 때문에 투 포인터를 활용하여 주식을 팔 수 있는 경우라면 최대 값을 계산하고 만약 산 가격보다 싼 가격을 만나면 다시 산다
16+
* TC: O(n), SC: O(1)
17+
*/
18+
private fun usingTwoPointer(prices: IntArray): Int {
19+
var (left, right) = 0 to 1
20+
var maxProfit = 0
21+
22+
while (right < prices.size) {
23+
if (prices[left] < prices[right]) {
24+
maxProfit = max(prices[right] - prices[left], maxProfit)
25+
right++
26+
} else if (prices[left] >= prices[right]) {
27+
left = right
28+
right++
29+
}
30+
}
31+
32+
return maxProfit
33+
}
34+
35+
/**
36+
* 2. 카데인 알고리즘의 변형된 버전으로 가장 싼 경우를 buy에 저장하고 현재 최대 수익을 초과하면 업데이트한다
37+
* TC: O(n), SC: O(1)
38+
*/
39+
private fun usingKadaneAlgorithm(prices: IntArray): Int {
40+
var buy = prices[0]
41+
var maxProfit = 0
42+
43+
for (index in 1 until prices.size) {
44+
if (prices[index] < buy) {
45+
buy = prices[index]
46+
} else if (prices[index] - buy > maxProfit) {
47+
maxProfit = prices[index] - buy
48+
}
49+
}
50+
return maxProfit
51+
}
52+
53+
@Test
54+
fun `주어진 가격 배열을 통해 최대의 수익을 반환한다`() {
55+
maxProfit(intArrayOf(3,3)) shouldBe 0
56+
maxProfit(intArrayOf(7,6,5,4,3,2,1,0)) shouldBe 0
57+
maxProfit(intArrayOf(7,1,5,3,6,4)) shouldBe 5
58+
maxProfit(intArrayOf(1,2,4,2,5,7,2,4,9,0,9)) shouldBe 9
59+
}
60+
}

group-anagrams/TonyKim9401.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// TC: O(n * m log m)
2+
// SC: O(n * m)
3+
class Solution {
4+
public List<List<String>> groupAnagrams(String[] strs) {
5+
List<List<String>> output = new ArrayList<>();
6+
Map<String, List<String>> map = new HashMap<>();
7+
8+
for (int i = 0; i < strs.length; i++) {
9+
char[] charArray = strs[i].toCharArray();
10+
Arrays.sort(charArray);
11+
String target = new String(charArray);
12+
13+
if (map.containsKey(target)) {
14+
map.get(target).add(strs[i]);
15+
} else {
16+
List<String> inside = new ArrayList<>();
17+
inside.add(strs[i]);
18+
map.put(target, inside);
19+
}
20+
}
21+
22+
for (String key : map.keySet()) output.add(map.get(key));
23+
return output;
24+
}
25+
}

group-anagrams/jdalma.kt

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder
4+
import org.junit.jupiter.api.Test
5+
6+
class `group-anagrams` {
7+
8+
fun groupAnagrams(strs: Array<String>): List<List<String>> {
9+
return usingArray(strs)
10+
}
11+
12+
/**
13+
* 1. 입력받은 문자열들을 문자 배열로 변환하여 정렬된 결과를 map 의 키로 정하여 키 기준으로 문자열들을 그룹화한다.
14+
* TC: O(n * k log(k)), SC: O(n)
15+
*/
16+
private fun usingSort(strs: Array<String>): List<List<String>> {
17+
val map = strs.groupBy { it.toCharArray().sorted() }
18+
return map.values.toList()
19+
}
20+
21+
/**
22+
* 2. 입력받은 문자열들을 순회하며 문자열의 문자 갯수를 카운트하여 애너그램인지 구별한다.
23+
* TC: O(n), SC: O(n)
24+
*/
25+
private fun usingArray(strs: Array<String>): List<List<String>> {
26+
val map = strs.groupBy { it ->
27+
val counter = IntArray(26)
28+
for (ch in it) {
29+
counter[ch - 'a']++
30+
}
31+
counter.joinToString(",") // 구분자를 넣지 않으면 arrayOf("bdddddddddd","bbbbbbbbbbc") 테케를 실패함
32+
}
33+
34+
return map.values.toList()
35+
}
36+
37+
@Test
38+
fun `입력받은 문자열들을 애너그램 기준 그룹별로 반환한다`() {
39+
groupAnagrams(arrayOf("eat","tea","tan","ate","nat","bat")) shouldContainExactlyInAnyOrder listOf(
40+
listOf("tan","nat"),
41+
listOf("bat"),
42+
listOf("eat","tea","ate"),
43+
)
44+
groupAnagrams(arrayOf("cab","tin","pew","duh","may","ill","buy","bar","max","doc")) shouldContainExactlyInAnyOrder listOf(
45+
listOf("max"),listOf("buy"),listOf("doc"),listOf("may"),listOf("ill"),
46+
listOf("duh"),listOf("tin"),listOf("bar"),listOf("pew"),listOf("cab")
47+
)
48+
groupAnagrams(arrayOf("bdddddddddd","bbbbbbbbbbc")) shouldContainExactlyInAnyOrder listOf(
49+
listOf("bbbbbbbbbbc"),
50+
listOf("bdddddddddd")
51+
)
52+
}
53+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
class TrieNode {
2+
TrieNode[] children;
3+
boolean isEndOfWord;
4+
5+
public TrieNode() {
6+
children = new TrieNode[26];
7+
isEndOfWord = false;
8+
}
9+
}
10+
11+
class Trie {
12+
13+
private TrieNode root;
14+
15+
public Trie() {
16+
root = new TrieNode();
17+
}
18+
19+
// TC: O(n)
20+
// SC: O(n * m)
21+
// -> word length * new TrieNode spaces
22+
public void insert(String word) {
23+
TrieNode node = root;
24+
for (char c : word.toCharArray()) {
25+
int idx = c - 'a';
26+
if (node.children[idx] == null) {
27+
node.children[idx] = new TrieNode();
28+
}
29+
node = node.children[idx];
30+
}
31+
node.isEndOfWord = true;
32+
}
33+
34+
// TC: O(n)
35+
// SC: O(1)
36+
public boolean search(String word) {
37+
TrieNode node = searchPrefix(word);
38+
return node != null && node.isEndOfWord;
39+
}
40+
41+
// TC: O(n)
42+
// SC: O(1)
43+
private TrieNode searchPrefix(String word) {
44+
TrieNode node = root;
45+
for (char c : word.toCharArray()) {
46+
int idx = c - 'a';
47+
if (node.children[idx] == null) return null;
48+
node = node.children[idx];
49+
}
50+
return node;
51+
}
52+
53+
public boolean startsWith(String prefix) {
54+
return searchPrefix(prefix) != null;
55+
}
56+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
6+
class `implement-trie-prefix-tree` {
7+
8+
/**
9+
* 영어 소문자만 입력된다.
10+
*/
11+
class Trie {
12+
13+
private val node = Node()
14+
15+
/**
16+
* TC: O(n), SC: O(n)
17+
*/
18+
fun insert(word: String) {
19+
var now = node
20+
21+
for (char in word) {
22+
val index = char - 'a'
23+
if (now.next[index] == null) {
24+
now.next[index] = Node()
25+
}
26+
now.next[index]?.apply { now = this }
27+
}
28+
now.isEnd = true
29+
}
30+
31+
/**
32+
* TC: O(n), SC: O(1)
33+
*/
34+
fun search(word: String): Boolean {
35+
var now = node
36+
37+
for (char in word) {
38+
val index = char - 'a'
39+
if (now.next[index] == null) {
40+
return false
41+
}
42+
now.next[index]?.apply { now = this }
43+
}
44+
45+
return now.isEnd
46+
}
47+
48+
/**
49+
* TC: O(n), SC: O(1)
50+
*/
51+
fun startsWith(prefix: String): Boolean {
52+
var now = node
53+
54+
for (char in prefix) {
55+
val index = char - 'a'
56+
if (now.next[index] == null) {
57+
return false
58+
}
59+
now.next[index]?.apply { now = this }
60+
}
61+
62+
return true
63+
}
64+
65+
}
66+
67+
@Test
68+
fun `접두사 트리를 구현하라`() {
69+
val trie = Trie()
70+
trie.insert("apple")
71+
trie.search("apple") shouldBe true
72+
trie.search("app") shouldBe false
73+
trie.startsWith("app") shouldBe true
74+
trie.insert("app")
75+
trie.search("app") shouldBe true
76+
}
77+
}
78+
79+
private class Node {
80+
val next = Array<Node?>(26) { null }
81+
var isEnd = false
82+
}

0 commit comments

Comments
 (0)