Skip to content

Commit eece4a7

Browse files
author
eunhwa99
committed
Merge remote-tracking branch 'origin/main'
2 parents 9404081 + fc2aaad commit eece4a7

File tree

10 files changed

+724
-0
lines changed

10 files changed

+724
-0
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
input : array of integer height
3+
output : maximum amount of water a container can store.
4+
5+
we can build container with two different line (height[i], height[j] when i < j)
6+
7+
example
8+
1 8 6 2 5 4 8 3 7
9+
choose i = 1.
10+
choose j = 4
11+
8 ______5
12+
amount of water == (j - i) * min(height[i], height[j])
13+
= 3 * 5 = 15
14+
15+
we have to maximize amount of water.
16+
17+
constraints:
18+
1) is the input array valid?
19+
length of array is in range [2, 10^5]
20+
2) positive integers?
21+
no. range of height is [0, 10 ^4]
22+
>> check amount can be overflow. 10^4 * 10 ^ 5 = 10^9 < Integer range
23+
edge:
24+
1) if length is 2
25+
return min(height[0], height[1]).
26+
...
27+
28+
solution 1) brute force;
29+
iterate through the array from index i = 0 to n-1
30+
when n is the length of input array
31+
iterate through the array from index j = i + 1 to n;
32+
calculate the amount of water and update max amount
33+
ds : array
34+
algo : x
35+
tc : O(n^2) ~= 10^10 TLE
36+
space : O(1)
37+
38+
solution 2) better
39+
ds : array
40+
algo: two pointer?
41+
42+
two variant for calculating amount of water
43+
1. height 2. width
44+
45+
set width maximum at first, check heights
46+
decrease width one by one
47+
48+
- at each step width is maximum.
49+
so we have to maximize
50+
the minimum between left and right pointer
51+
52+
use left and right pointer
53+
while left < right
54+
55+
calculate amount
56+
compare
57+
if height[left] < height[right]
58+
move left by one
59+
else
60+
vice versa
61+
62+
return max
63+
tc : O(n)
64+
sc : O(1)
65+
66+
*/
67+
class Solution {
68+
public int maxArea(int[] height) {
69+
int left = 0;
70+
int right = height.length - 1;
71+
int maxAmount = 0;
72+
while(left < right) {
73+
int curAmount = (right - left) * Math.min(height[left], height[right]);
74+
maxAmount = Math.max(maxAmount, curAmount);
75+
if(height[left] < height[right]) {
76+
left++;
77+
} else {
78+
right--;
79+
}
80+
}
81+
return maxAmount;
82+
}
83+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
solution 1. brute force
3+
Time Complexity: O(n^2)
4+
Space Complexity: O(1)
5+
모든 선분 i에 대해, 가장 많은 물을 담을 수 있는 반대쪽 선분 j를 찾는다.
6+
7+
8+
solution 2. PQ
9+
Time Complexity: O(nlogn)
10+
- 정렬 : O(nlogn)
11+
- i번째 선분에 대해 (자신보다 크거나 같은) 가장 멀리있는 선분 탐색(O(logn)) * n = O(nlogn)
12+
Space Complexity: O(n)
13+
14+
(사고의 흐름을 적기 위해 편의상 반말로 적었습니다... ^^)
15+
brute force 에서 불필요한 탐색을 줄여보자.
16+
일단 어떤 선분 i가 주어졌다고 가정하자. i를 한쪽 벽으로 해서 가장 많은 물을 담는 방법을 찾으려면, 반드시 나머지 모든 선분을 탐색해야만 할까?
17+
18+
(1) 자신보다 작은 선분은 탐색하지 않는다.
19+
20+
자신보다 큰 선분만을 탐색해도 충분하다.
21+
왜냐하면, 설령 자신보다 더 작은 선분 중에 정답이 있었다고 하더라도, 그 선분을 기준으로 탐색할 때 정답에 해당하는 쌍을 확인하게 될 것이기 때문이다.
22+
23+
(2) 자신보다 크거나 같은 선분만을 탐색 대상으로 삼는다면, 가장 멀리있는 선분만 확인하면 된다.
24+
25+
탐색 대상이 자신보다 크거나 같은 선분들이라면, 어차피 담을 수 있는 물의 높이는 자신의 높이로 일정하다.
26+
따라서, 멀리있는 선분일수록 더 많은 물을 담게 된다.
27+
즉, "자신보다 크거나 같으면서", "가장 멀리 있는(오른쪽이든 왼쪽이든)" 선분만을 후보로 삼아 확인하면 충분하다.
28+
(그 외의 나머지, 즉 자신보다 크거나 같으면서, 가장 멀리있지 않은 나머지 선분들은, 자연스럽게 탐색하지 않을 수 있다.)
29+
30+
정리하자면, 주어진 선분 i에 대해서, 단 2번(오른쪽, 왼쪽)의 탐색만 하면 충분하다.
31+
32+
(3) 내림차순 정렬과 2개의 PQ를 아래처럼 활용하면, 위 탐색을 O(logn) 시간에 수행할 수 있다.
33+
PQ는 각각 x 좌표 기준 max heap(가장 오른쪽의 선분을 찾기 위함), x 좌표 기준 min heap(가장 왼쪽의 선분을 찾기 위함)을 사용한다.
34+
선분들을 길이 내림차순으로 정렬해놓고, 하나씩 순회하면서 (say, i번째 선분), 아래 과정을 반복한다.
35+
- 자신보다 크거나 같으면서 가장 오른쪽으로 멀리 있는 선분의 위치를 찾아서(= 현재 PQ(max heap)의 root), 최대 물의 양을 계산한다.
36+
- 자신보다 크거나 같으면서 가장 왼쪽으로 멀리 있는 선분의 위치를 찾아서(= 현재 PQ(min heap)의 root), 최대 물의 양을 계산한다.
37+
- i번째 선분을 PQ 2개에 각각 넣는다.
38+
39+
40+
solution 3. two pointers
41+
(AlgoDale 풀이를 참고함)
42+
43+
Time Complexity: O(n)
44+
Space Complexity: O(1)
45+
46+
2 포인터를 활용하면, PQ도 없이 시간 복잡도를 O(n)으로 줄일 수 있었다.
47+
단순히 "큰 쪽을 줄이기보다는, 작은 쪽을 줄이는 게 유리하겠지" 정도의 greedy한 논리는 충분하지 않은 것 같고, 더 명확한 근거가 있을 것 같은데 시간 관계상 고민해보지는 못했다.
48+
49+
To-Do : 풀이가 대강 이해는 되었지만, 이게 왜 되는지, 엄밀하게 이해하기 위해 PQ를 사용했던 논리를 좀 더 발전시켜볼 필요가 있다.
50+
51+
*/
52+
class Solution {
53+
public int maxArea(int[] height) {
54+
int i = 0, j = height.length - 1;
55+
56+
int ans = 0;
57+
while (i < j) {
58+
int area = (j - i) * Math.min(height[i], height[j]);
59+
if (area > ans) {
60+
ans = area;
61+
}
62+
63+
if (height[i] <= height[j]) {
64+
i++;
65+
} else {
66+
j--;
67+
}
68+
}
69+
70+
return ans;
71+
}
72+
73+
////// 아래는 solution 2
74+
private static class Tuple {
75+
private int x;
76+
private int h;
77+
78+
Tuple(int x, int h) {
79+
this.x = x;
80+
this.h = h;
81+
}
82+
}
83+
84+
public int maxArea2(int[] height) {
85+
List<Tuple> tuples = IntStream.range(0, height.length)
86+
.mapToObj(i -> new Tuple(i, height[i]))
87+
.collect(Collectors.toList());
88+
Collections.sort(tuples, (a, b) -> b.h - a.h);
89+
90+
PriorityQueue<Tuple> minPq = new PriorityQueue<>((a, b) -> a.x - b.x);
91+
PriorityQueue<Tuple> maxPq = new PriorityQueue<>((a, b) -> b.x - a.x);
92+
93+
int ans = 0;
94+
for (int i = 0; i < height.length; i++) {
95+
minPq.add(tuples.get(i));
96+
maxPq.add(tuples.get(i));
97+
98+
Tuple curr = tuples.get(i);
99+
100+
Tuple left = minPq.peek();
101+
int leftArea = (curr.x - left.x) * curr.h;
102+
if (leftArea > ans) {
103+
ans = leftArea;
104+
}
105+
106+
Tuple right = maxPq.peek();
107+
int rightArea = (right.x - curr.x) * curr.h;
108+
if (rightArea > ans) {
109+
ans = rightArea;
110+
}
111+
}
112+
113+
return ans;
114+
}
115+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
design ds that supports add, find
3+
find if string matches any previously added string.
4+
>> some kind of dictionary
5+
6+
example
7+
add bad
8+
add dad
9+
add mad
10+
search pad >> false
11+
search bad >> true
12+
search .ad >> true . can be 'b' or 'd' or 'm'
13+
search b.. >> true .. can be "ad"
14+
15+
constraints:
16+
1) empty string can be valid input?
17+
nope. lenght of string is in range of [1, 25]
18+
2) string only contiains alphanumeric? or alphabet
19+
only lowercase English letters
20+
3) how many queries can be given as input?
21+
at most 10^4
22+
23+
solution 1) brute force
24+
save to data structure. for add
25+
check every character for all the saved words
26+
O(kn) when k is the number of saved words,
27+
n is the length of input word token
28+
25 * 25 * 10^4
29+
tc : O(kn) + O(kn)
30+
add : O(1)
31+
search : O(kn)
32+
sc : O(kn)
33+
34+
solution 2) trie?
35+
36+
save words to trie.
37+
when searching
38+
do bfs or backtracking dfs
39+
if current charcter is . add all childs
40+
else add matching childs
41+
overall tc : O(sum(m)) + O(n),
42+
add : O(m), when m is the length of saved word
43+
search : O(n), when n is the length of searh word
44+
sc : O(sum(m))
45+
46+
if volume of search query is much bigger than add query
47+
trie solution would be better
48+
O(n) search time vs O(mn) search time
49+
*/
50+
class WordDictionary {
51+
class TrieNode {
52+
TrieNode[] childs;
53+
boolean isEnd;
54+
TrieNode() {
55+
childs = new TrieNode[26];
56+
isEnd = false;
57+
}
58+
}
59+
TrieNode root;
60+
public WordDictionary() {
61+
root = new TrieNode();
62+
}
63+
64+
public void addWord(String word) {
65+
TrieNode curNode = root;
66+
for(char c : word.toCharArray()) {
67+
if(curNode.childs[c-'a'] == null) {
68+
curNode.childs[c-'a'] = new TrieNode();
69+
}
70+
curNode = curNode.childs[c-'a'];
71+
}
72+
curNode.isEnd = true;
73+
}
74+
75+
public boolean search(String word) {
76+
return dfsHelper(root, word, 0);
77+
}
78+
79+
public boolean dfsHelper(TrieNode node, String word, int p) {
80+
//end clause
81+
if(p == word.length()) {
82+
return node.isEnd;
83+
}
84+
85+
char curC = word.charAt(p);
86+
if(curC == '.') {
87+
for(TrieNode next : node.childs) {
88+
if(next != null) {
89+
if(dfsHelper(next, word, p + 1)) return true;
90+
}
91+
}
92+
return false;
93+
} else {
94+
if(node.childs[curC-'a'] != null) {
95+
if(dfsHelper(node.childs[curC - 'a'], word, p + 1)) return true;
96+
}
97+
return false;
98+
}
99+
100+
101+
}
102+
}
103+
104+
/**
105+
* Your WordDictionary object will be instantiated and called as such:
106+
* WordDictionary obj = new WordDictionary();
107+
* obj.addWord(word);
108+
* boolean param_2 = obj.search(word);
109+
*/
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
Time Complexity:
3+
- add: O(w)
4+
- search: O(26^2 * w) = O(w)
5+
Space Complexity: O(w)
6+
7+
Trie를 활용하되, '.'의 탐색이 필요한 경우에는 for문을 사용한다.
8+
9+
*/
10+
class WordDictionary {
11+
class Node {
12+
public char ch;
13+
public boolean ends;
14+
public Map<Character, Node> children;
15+
16+
Node() {
17+
this.children = new HashMap<>();
18+
}
19+
20+
Node(char ch) {
21+
this.ch = ch;
22+
this.children = new HashMap<>();
23+
}
24+
}
25+
26+
Node root;
27+
28+
public WordDictionary() {
29+
this.root = new Node();
30+
}
31+
32+
public void addWord(String word) {
33+
Node curr = this.root;
34+
35+
for (int i = 0; i < word.length(); i++) {
36+
char ch = word.charAt(i);
37+
if (!curr.children.containsKey(ch)) {
38+
curr.children.put(ch, new Node(ch));
39+
}
40+
41+
curr = curr.children.get(ch);
42+
}
43+
44+
curr.ends = true;
45+
}
46+
47+
public boolean search(String word) {
48+
return searchChar(word, 0, this.root);
49+
}
50+
51+
private boolean searchChar(String word, int idx, Node curr) {
52+
if (curr == null) {
53+
return false;
54+
} else if (idx == word.length()) {
55+
return curr.ends;
56+
}
57+
58+
char ch = word.charAt(idx);
59+
60+
if (ch == '.') {
61+
for (Character key : curr.children.keySet()) {
62+
if (searchChar(word, idx + 1, curr.children.get(key))) {
63+
return true;
64+
}
65+
}
66+
return false;
67+
} else {
68+
return searchChar(word, idx + 1, curr.children.get(ch));
69+
}
70+
}
71+
}
72+
73+
/**
74+
* Your WordDictionary object will be instantiated and called as such:
75+
* WordDictionary obj = new WordDictionary();
76+
* obj.addWord(word);
77+
* boolean param_2 = obj.search(word);
78+
*/

0 commit comments

Comments
 (0)