Skip to content

Commit 50ede68

Browse files
authored
Merge branch 'DaleStudy:main' into main
2 parents 6e15e64 + 6dd8755 commit 50ede68

File tree

18 files changed

+793
-0
lines changed

18 files changed

+793
-0
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// 시간복잡도: O(n)
2+
// 공간복잡도: O(1)
3+
4+
/**
5+
* @param {number[]} height
6+
* @return {number}
7+
*/
8+
var maxArea = function(height) {
9+
let maxArea = 0;
10+
11+
let leftIdx = 0;
12+
let rightIdx = height.length - 1;
13+
14+
while (leftIdx <= rightIdx) {
15+
const minHeight = Math.min(height[leftIdx], height[rightIdx]);
16+
const distance = rightIdx - leftIdx
17+
18+
maxArea = Math.max(maxArea, distance * minHeight);
19+
20+
if (height[leftIdx] < height[rightIdx]) leftIdx++
21+
else rightIdx--
22+
}
23+
24+
return maxArea
25+
};
26+
27+
console.log(maxArea([1,8,6,2,5,4,8,3,7])) //49
28+
console.log(maxArea([1,1])) //1
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
import kotlin.math.abs
6+
import kotlin.math.max
7+
import kotlin.math.min
8+
9+
typealias Element = Pair<Int,Int>
10+
11+
class `container-with-most-wate` {
12+
13+
/**
14+
* 투 포인터를 활용하여 높이가 낮은 인덱스의 값을 한 칸씩 이동하며 최대 높이를 반환한다.
15+
* TC: O(n), SC: O(1)
16+
*/
17+
fun maxArea(height: IntArray): Int {
18+
var (left, right) = 0 to height.size - 1
19+
var result = 0
20+
21+
while (left < right) {
22+
result = max(result, extent(Element(height[left], left), Element(height[right], right)))
23+
if (height[left] < height[right]) {
24+
left++
25+
} else {
26+
right--
27+
}
28+
}
29+
return result
30+
}
31+
32+
private fun extent(e1: Element, e2: Element): Int {
33+
return min(e1.first, e2.first) * abs(e1.second - e2.second)
34+
}
35+
36+
@Test
37+
fun `입력받은 높이를 표현하는 정수 배열에서 받을 수 있는 최대의 물의 양을 반환한다`() {
38+
maxArea(intArrayOf(1,8,6,2,5,4,8,3,7)) shouldBe 49
39+
}
40+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from typing import List
2+
3+
4+
class Solution:
5+
def maxArea(self, height: List[int]) -> int:
6+
"""
7+
- Idea: 배열의 양쪽 끝에서 시작하는 두 포인터(left, right)를 이용해 두 선 사이의 최대 영역을 구한다. 둘 중, 높이가 낮은 쪽의 포인터는 중앙 쪽으로 이동시킨다.
8+
- Time Complexity: O(n), n은 주어진 배열(height)의 길이.
9+
- Space Complexity: O(1), 추가 공간은 사용하지 않는다.
10+
"""
11+
left, right = 0, len(height) - 1
12+
result = 0
13+
14+
while left < right:
15+
current_width = right - left
16+
current_height = min(height[left], height[right])
17+
result = max(result, current_width * current_height)
18+
19+
if height[left] < height[right]:
20+
left += 1
21+
else:
22+
right -= 1
23+
24+
return result
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* 시간 복잡도: O(n)
3+
* 공간 복잡도: O(1)
4+
*
5+
* 최대로 많은 물을 저장하기 위해 가장 우선적으로 고려해야 하는 것은 짧은 막대의 길이
6+
* 따라서, 짧은 높이를 가지는 쪽의 포인터를 이동하면서 최대 저장 가능한 값을 비교
7+
*
8+
*/
9+
class Solution {
10+
public int maxArea(int[] height) {
11+
int answer = 0;
12+
int left = 0;
13+
int right = height.length - 1;
14+
15+
while (left < right) {
16+
int water = Math.min(height[left], height[right]) * (right - left);
17+
answer = Math.max(answer, water);
18+
19+
if (height[left] < height[right]) {
20+
left++;
21+
} else {
22+
right--;
23+
}
24+
}
25+
26+
return answer;
27+
}
28+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
function maxArea(height: number[]): number {
2+
let left = 0;
3+
let right = height.length - 1;
4+
let maxSize = 0;
5+
6+
while (left < right) {
7+
maxSize = Math.max(maxSize, getMaxSize(height, left, right));
8+
9+
if (height[left] < height[right]) {
10+
left++;
11+
} else {
12+
right--;
13+
}
14+
}
15+
16+
return maxSize;
17+
}
18+
19+
function getMaxSize(height: number[], left: number, right: number) {
20+
return Math.min(...[height[right], height[left]]) * (right - left);
21+
}
22+
23+
// TC: O(n)
24+
// SC: O(1)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// 시간복잡도
2+
// addWord: O(n) (n은 추가하는 단어의 길이)
3+
// search: O(m^n) (m은 각 노드의 최대 자식 수, n은 검색하는 단어의 길이)
4+
5+
// 공간복잡도
6+
// addWord: O(n) (n은 추가하는 단어의 길이)
7+
// search: O(n) (n은 검색하는 단어의 길이, 재귀 호출 스택의 깊이)
8+
9+
class TrieNode {
10+
constructor() {
11+
this.children = {}
12+
this.endOfWord = false
13+
}
14+
}
15+
16+
class WordDictionary {
17+
constructor() {
18+
this.root = new TrieNode()
19+
}
20+
addWord(word) {
21+
let curNode = this.root
22+
23+
for (let i = 0 ; i < word.length; i++) {
24+
if (!curNode.children[word[i]]) {
25+
curNode.children[word[i]] = new TrieNode();
26+
}
27+
28+
curNode = curNode.children[word[i]];
29+
}
30+
31+
curNode.endOfWord = true
32+
}
33+
search(word) {
34+
return this.searchInNode(word, this.root);
35+
}
36+
37+
searchInNode(word, node) {
38+
let curNode = node;
39+
40+
for (let i = 0; i < word.length; i++) {
41+
if (word[i] === '.') {
42+
for (let key in curNode.children) {
43+
if (this.searchInNode(word.slice(i + 1), curNode.children[key])) return true
44+
}
45+
return false
46+
}
47+
48+
if (word[i] !== '.') {
49+
if (!curNode.children[word[i]]) return false
50+
curNode = curNode.children[word[i]];
51+
}
52+
}
53+
54+
return curNode.endOfWord
55+
}
56+
}
57+
58+
59+
const wordDictionary = new WordDictionary();
60+
wordDictionary.addWord("bad");
61+
wordDictionary.addWord("dad");
62+
wordDictionary.addWord("mad");
63+
console.log(wordDictionary.search("pad")); // return False
64+
console.log(wordDictionary.search("bad")); // return True
65+
console.log(wordDictionary.search(".ad")); // return True
66+
console.log(wordDictionary.search("b..")); // return True
67+
68+
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import leetcode_study.Type.*
5+
import org.junit.jupiter.api.Test
6+
7+
class `design-add-and-search-words-data-structure` {
8+
9+
class Node {
10+
var isEnd: Boolean = false
11+
val next: MutableMap<Char, Node> = mutableMapOf()
12+
}
13+
14+
class WordDictionary {
15+
private val root = Node()
16+
17+
/**
18+
* TC: O(n), SC: O(n)
19+
*/
20+
fun addWord(word: String) {
21+
var now = root
22+
23+
for (index in word.indices) {
24+
val node =
25+
if (now.next.containsKey(word[index])) { now.next[word[index]] }
26+
else Node().also { now.next[word[index]] = it }
27+
node?.let { now = it }
28+
}
29+
now.isEnd = true
30+
}
31+
32+
/**
33+
* TC: O(26^n), SC: O(n)
34+
*/
35+
fun search(word: String): Boolean {
36+
37+
fun dfs(node: Node, word: String, index: Int): Boolean {
38+
return if (index == word.length) node.isEnd
39+
else if (word[index] == '.') {
40+
node.next.values.any { dfs(it, word, index + 1) }
41+
}
42+
else {
43+
node.next[word[index]]?.let { dfs(it, word, index + 1) } ?: false
44+
}
45+
}
46+
47+
return dfs(this.root, word, 0)
48+
}
49+
}
50+
51+
@Test
52+
fun `문자열을 저장하고 검색하는 자료구조를 구현하라`() {
53+
inputCommands(
54+
Command(ADD, "bad"),
55+
Command(ADD, "dad"),
56+
Command(ADD, "mad"),
57+
Command(SEARCH, "pad", false),
58+
Command(SEARCH, "bad", true),
59+
Command(SEARCH, ".ad", true),
60+
Command(SEARCH, "b..", true),
61+
)
62+
inputCommands(
63+
Command(ADD, "at"),
64+
Command(ADD, "and"),
65+
Command(ADD, "an"),
66+
Command(ADD, "add"),
67+
Command(SEARCH, "a", false),
68+
Command(SEARCH, ".at", false),
69+
Command(ADD, "bat"),
70+
Command(SEARCH,".at", true),
71+
Command(SEARCH,"an.", true),
72+
Command(SEARCH,"a.d.", false),
73+
Command(SEARCH,"b.", false),
74+
Command(SEARCH,"a.d", true),
75+
Command(SEARCH,".", false)
76+
)
77+
}
78+
79+
private fun inputCommands(vararg commands: Command) {
80+
val dictionary = WordDictionary()
81+
for (command in commands) {
82+
when(command.type) {
83+
ADD -> dictionary.addWord(command.word)
84+
SEARCH -> dictionary.search(command.word) shouldBe command.expect
85+
}
86+
}
87+
}
88+
}
89+
90+
data class Command(
91+
val type: Type,
92+
val word: String,
93+
val expect : Boolean? = null
94+
)
95+
96+
enum class Type {
97+
ADD, SEARCH;
98+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
class WordDictionary {
2+
3+
private class TrieNode {
4+
Map<Character, TrieNode> children = new HashMap<>();
5+
boolean isEndOfWord = false;
6+
}
7+
8+
private TrieNode root;
9+
10+
public WordDictionary() {
11+
root = new TrieNode();
12+
}
13+
14+
/**
15+
* 시간 복잡도: O(n), n = 단어의 길이
16+
* 공간 복잡도: O(n)
17+
*/
18+
public void addWord(String word) {
19+
TrieNode node = root;
20+
21+
for (int i = 0; i < word.length(); i++) {
22+
char c = word.charAt(i);
23+
node.children.putIfAbsent(c, new TrieNode());
24+
node = node.children.get(c);
25+
}
26+
node.isEndOfWord = true;
27+
}
28+
29+
/**
30+
* 시간 복잡도: O(26^n), n = 단어의 길이
31+
* 공간 복잡도: O(n)
32+
*/
33+
public boolean search(String word) {
34+
return searchInNode(word, 0, root);
35+
}
36+
37+
private boolean searchInNode(String word, int index, TrieNode node) {
38+
if (index == word.length()) {
39+
return node.isEndOfWord;
40+
}
41+
42+
char c = word.charAt(index);
43+
if (c != '.') {
44+
if (node.children.containsKey(c)) {
45+
return searchInNode(word, index + 1, node.children.get(c));
46+
} else {
47+
return false;
48+
}
49+
} else {
50+
for (TrieNode childNode : node.children.values()) {
51+
if (searchInNode(word, index + 1, childNode)) {
52+
return true;
53+
}
54+
}
55+
return false;
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)