Skip to content

Commit 94720e1

Browse files
authored
Merge branch 'DaleStudy:main' into main
2 parents 681a47d + 67ab0cd commit 94720e1

File tree

26 files changed

+1180
-0
lines changed

26 files changed

+1180
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// TC:
2+
// SC:
3+
class Solution {
4+
public int maxArea(int[] height) {
5+
int max = 0;
6+
7+
int start = 0;
8+
int end = height.length-1;
9+
10+
while (start < end) {
11+
int heightLeft = height[start];
12+
int heightRight = height[end];
13+
14+
int hei = Math.min(heightLeft, heightRight);
15+
int wid = end - start;
16+
17+
max = Math.max(max, hei*wid);
18+
19+
if (heightRight > heightLeft) start += 1;
20+
else end -= 1;
21+
}
22+
return max;
23+
}
24+
}

container-with-most-water/haklee.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
"""TC: O(n), SC: O(1)
2+
3+
아이디어:
4+
높이 리스트 l이 주어졌다고 하자. 그리고 이 안에 있는 최대 수조 면적을 f(l)이라고 하자.
5+
6+
□ □ □
7+
□ □ □ □
8+
□ □ □ □ □ □ □ □ □
9+
□ □ □ □ □ □ □ □ □ □ □ □
10+
□ □ □ □ □ □ □ □ □ □ □ □ □ □
11+
2,5,3,3,1,3,1,2,2,5,3,5,3,4
12+
^
13+
l
14+
15+
16+
그러면 다음이 항상 성립한다.
17+
18+
- l의 양 끝의 값 중 작은 값 x가 앞쪽에 있었다고 해보자. x를 뺀 리스트 l`을 만든다.
19+
- 이때 작은 값이 뒷쪽에 있었어도 일반성을 잃지 않는다.
20+
21+
│□ □ □
22+
│□ □ □ □
23+
│□ □ □ □ □ □ □ □ □
24+
□│□ □ □ □ □ □ □ □ □ □ □
25+
□│□ □ □ □ □ □ □ □ □ □ □ □ □
26+
2│5,3,3,1,3,1,2,2,5,3,5,3,4
27+
^ ^
28+
x l`
29+
30+
31+
- f(l)은 그렇다면
32+
- f(l`)이거나(즉, x를 쓰지 않았거나)
33+
- x를 써서 만든 수조 면적 중에 있다.
34+
35+
- 그런데 x는 l의 양 끝 값 중에 작은 값이므로, 아래와 같은 분석을 할 수 있다.
36+
1) x를 써서 만드는 수조의 높이는 아무리 높아도 x다. x보다 작아질 수는 있어도, x보다 커질 수는 없다.
37+
2) x를 써서 만드는 수조의 폭은 l의 다른쪽 끝에 있는 높이를 선택했을때 최대가 된다.
38+
- 그러므로, x를 써서 만들 수 있는 수조의 최대 크기는 l의 다른쪽 끝에 있는 높이를 선택한 경우 나온다.
39+
40+
위의 내용을 아래의 설명을 통해 시각적으로 확인할 수 있다.
41+
42+
- 양 끝을 선택한 경우 x로 만들 수 있는 최대 면적이다.
43+
44+
│□ □ □
45+
│□ □ □ □
46+
│□ □ □ □ □ □ □ □ □
47+
■│■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
48+
■│■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
49+
2│5,3,3,1,3,1,2,2,5,3,5,3,4
50+
^ ^
51+
52+
- x는 그대로 둔 채 다른쪽 끝을 안쪽으로 더 이동하면 수조 높이는 동일한데 폭은 더 작아진다.
53+
54+
│□ □ □
55+
│□ □ □ □
56+
│□ □ □ □ □ □ □ □ □
57+
■│■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ □ □
58+
■│■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ □ □
59+
2│5,3,3,1,3,1,2,2,5,3,5,3,4
60+
^ ^
61+
62+
- 심지어 x보다 작은 높이 값을 선택한 경우 수조 높이도 작아지고 폭도 작아지는 일이 일어난다.
63+
64+
│□ □ □
65+
│□ □ □ □
66+
│□ □ □ □ □ □ □ □ □
67+
□│□ □ □ □ □ □ □ □ □ □ □
68+
■│■ ■ ■ ■ ■ ■ □ □ □ □ □ □ □
69+
2│5,3,3,1,3,1,2,2,5,3,5,3,4
70+
71+
72+
즉, 위의 내용을 종합하면 다음을 확인할 수 있다.
73+
- f(l) = max( (l의 양 끝 높이를 선택해서 만든 수조 넓이), f(l`) )
74+
- 그런데 f(l`)도 f(l)을 구한 것과 같은 방식으로 구할 수 있다. 즉, 새로 만들어진 l`의 양 끝 높이 중
75+
짧은 쪽을 뺀 리스트 l``을 만들어서 위의 과정을 반복할 수 있다.
76+
- 즉, f(l)은 아래의 과정을 반복하여 구할 수 있다.
77+
- l의 양 끝 높이를 써서 수조 넓이를 구하고, 기존 최대 넓이와 비교하여 더 큰 값을 최대 넓이에 대입한다.
78+
- l에서 짧은 쪽 높이를 뺀다.
79+
- 위 과정을 l에 아이템이 하나만 남을 때까지 반복.
80+
81+
82+
SC:
83+
- 투 포인터를 써서 l의 시작, 끝 인덱스를 관리하면 O(1).
84+
- 수조 최대 넓이값 관리, O(1).
85+
- 종합하면 O(1).
86+
87+
TC:
88+
- 리스트의 양 끝 높이를 통해 면적 구하기, O(1).
89+
- 포인터 이동 O(1).
90+
- 포인터 이동시 두 포인터 사이의 거리가 1씩 항상 감소하므로 위 과정을 최대 n-2번 반복.
91+
- 종합하면 O(n).
92+
"""
93+
94+
95+
class Solution:
96+
def maxArea(self, height: List[int]) -> int:
97+
max_area = -1
98+
s, e = 0, len(height) - 1
99+
while s < e:
100+
max_area = max(max_area, (e - s) * min(height[s], height[e]))
101+
if height[s] > height[e]:
102+
e -= 1
103+
else:
104+
s += 1
105+
return max_area
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
class SolutionMaxArea {
2+
public int maxArea(int[] height) {
3+
// A와 B 간 면적 = (A와 B의 X축 차이) * (A와 B Y축 중 더 작은 Y축 길이)
4+
// 1번째 풀이 방법: 선택할 수 있는 모든 경우에 대해 위 값을 구한다, 시간복잡도: O(N^2) / 공간복잡도: O(1)
5+
// (최종) 2번째 풀이 방법: 양쪽 끝에서 투포인터로 좁혀오면서 면적을 구한다, 시간복잡도: O(N) / 공간복잡도: O(1)
6+
// 전체 너비를 고려하면서 움직여야한다.
7+
// 매번 면적을 계산하고, 더 크면 저장한다.
8+
// lt와 rt 중 더 낮은쪽을 좁힌다
9+
10+
var lt = 0;
11+
var rt = height.length-1;
12+
var maxArea = 0;
13+
14+
while(lt < rt) {
15+
var x = rt - lt;
16+
var y = Math.min(height[lt], height[rt]);
17+
var currentArea = x * y;
18+
if (maxArea < currentArea) {
19+
maxArea = currentArea;
20+
}
21+
22+
if (height[lt] < height[rt]) {
23+
lt++;
24+
} else {
25+
rt--;
26+
}
27+
}
28+
29+
return maxArea;
30+
}
31+
}

container-with-most-water/kayden.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# 시간복잡도: O(N)
2+
# 공간복잡도: O(N)
3+
class Solution:
4+
def maxArea(self, height: List[int]) -> int:
5+
l, r = 0, len(height) - 1
6+
answer = 0
7+
8+
while l < r:
9+
10+
if height[l] < height[r]:
11+
answer = max(answer, (r - l) * height[l])
12+
l += 1
13+
else:
14+
answer = max(answer, (r - l) * height[r])
15+
r -= 1
16+
17+
return answer

container-with-most-water/sunjae95.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* @description
3+
* brainstorming:
4+
* 1. brute force -> time limited
5+
* 2. two pointer
6+
*
7+
* n: length of height
8+
* time complexity: O(n)
9+
* space complexity: O(1)
10+
*/
11+
var maxArea = function (height) {
12+
let answer = 0;
13+
let start = 0;
14+
let end = height.length - 1;
15+
16+
while (start !== end) {
17+
const w = end - start;
18+
const h = Math.min(height[start], height[end]);
19+
answer = Math.max(answer, w * h);
20+
if (height[start] >= height[end]) {
21+
end--;
22+
} else if (height[start] < height[end]) {
23+
start++;
24+
}
25+
}
26+
27+
return answer;
28+
};

container-with-most-water/wogha95.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* TC: O(H)
3+
* SC: O(1)
4+
* H: height.length
5+
*/
6+
7+
/**
8+
* @param {number[]} height
9+
* @return {number}
10+
*/
11+
var maxArea = function (height) {
12+
let maximumWater = 0;
13+
let left = 0;
14+
let right = height.length - 1;
15+
16+
// 1. 투포인터를 이용하여 양끝에서 모입니다.
17+
while (left < right) {
18+
// 2. 최대 너비값을 갱신해주고
19+
const h = Math.min(height[left], height[right]);
20+
const w = right - left;
21+
22+
maximumWater = Math.max(maximumWater, w * h);
23+
24+
// 3. 왼쪽과 오른쪽 높이 중 더 낮은 쪽의 pointer를 옮깁니다.
25+
if (height[left] < height[right]) {
26+
left += 1;
27+
} else {
28+
right -= 1;
29+
}
30+
}
31+
32+
return maximumWater;
33+
};
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// SC: O(n)
2+
// -> n is the length of the given String
3+
// TC: O(n * 26)
4+
// -> n is the length of the given String * the number of alphabets
5+
class TrieNode {
6+
TrieNode[] childNode;
7+
boolean isEndOfWord;
8+
9+
public TrieNode() {
10+
childNode = new TrieNode[26];
11+
isEndOfWord = false;
12+
}
13+
}
14+
15+
class WordDictionary {
16+
17+
private TrieNode root;
18+
19+
public WordDictionary() {
20+
root = new TrieNode();
21+
}
22+
23+
public void addWord(String word) {
24+
TrieNode node = root;
25+
26+
for (char c : word.toCharArray()) {
27+
int idx = c - 'a';
28+
if (node.childNode[idx] == null) {
29+
node.childNode[idx] = new TrieNode();
30+
}
31+
node = node.childNode[idx];
32+
}
33+
node.isEndOfWord = true;
34+
}
35+
36+
public boolean search(String word) {
37+
return searchInNode(word.toCharArray(), 0, root);
38+
}
39+
40+
private boolean searchInNode(char[] word, int idx, TrieNode node) {
41+
if (idx == word.length) return node.isEndOfWord;
42+
43+
char c = word[idx];
44+
45+
if (c == '.') {
46+
for (TrieNode child : node.childNode) {
47+
if (child != null && searchInNode(word, idx+1, child)) return true;
48+
}
49+
return false;
50+
} else {
51+
int childIdx = c - 'a';
52+
if (node.childNode[childIdx] == null) return false;
53+
return searchInNode(word, idx+1, node.childNode[childIdx]);
54+
}
55+
}
56+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"""search시: TC: O(n), SC: O(n)
2+
3+
word의 max length가 w, `addWord`를 통해 만들어진 노드 개수가 n개라고 하자.
4+
5+
아이디어:
6+
`implement-trie-prefix-tree` 문제에서 구현한 trie에서 search 부분만 recursive한 dfs 구현으로 수정.
7+
8+
SC:
9+
- trie의 노드 개수 O(n).
10+
- dfs시 스택 깊이는 최대 w. 즉, O(w). 그런데 스택 깊이는 노드 개수보다 클 수 없다. 즉, O(w) < O(n).
11+
- 종합하면, O(n) + O(w) < O(n) + O(n) = O(n).
12+
13+
TC:
14+
- 최악의 경우 모든 노드 순회. O(n).
15+
16+
"""
17+
18+
19+
class WordDictionary:
20+
21+
def __init__(self):
22+
self.next: dict[str, WordDictionary] = {}
23+
self.end: bool = False
24+
25+
def addWord(self, word: str) -> None:
26+
cur = self
27+
28+
for c in word:
29+
cur.next[c] = cur.next.get(c, WordDictionary())
30+
cur = cur.next[c]
31+
32+
cur.end = True
33+
34+
def search(self, word: str) -> bool:
35+
cur = self
36+
37+
return self._search(cur, word, 0)
38+
39+
def _search(self, trie, word: str, ind: int) -> bool:
40+
if ind == len(word):
41+
return trie.end
42+
43+
c = word[ind]
44+
45+
if c == ".":
46+
return any(
47+
[self._search(node, word, ind + 1) for node in trie.next.values()]
48+
)
49+
50+
if c not in trie.next:
51+
return False
52+
53+
return self._search(trie.next[c], word, ind + 1)
54+
55+
56+
# Your WordDictionary object will be instantiated and called as such:
57+
# obj = WordDictionary()
58+
# obj.addWord(word)
59+
# param_2 = obj.search(word)

0 commit comments

Comments
 (0)