diff --git a/best-time-to-buy-and-sell-stock/eunhwa99.java b/best-time-to-buy-and-sell-stock/eunhwa99.java
new file mode 100644
index 000000000..70a251e40
--- /dev/null
+++ b/best-time-to-buy-and-sell-stock/eunhwa99.java
@@ -0,0 +1,55 @@
+// 풀이 방법
+// 1. 인덱스 x까지의 최소값을 저장하는 배열 1개와, 인덱스 x부터의 최대값을 저장하는 배열 1개를 만든다.
+// 2. 1번에서 만든 두 배열에 값을 채운다.
+// 3. 두 배열을 각각 인덱스 별로 차를 구하고, 그 중 최댓값을 구한다.
+
+// 시간 복잡도
+// O(n) : 배열을 2번 순회하므로 O(n)이다.
+// 공간 복잡도
+// O(n) : 최소값과 최대값을 저장하는 배열을 만들었으므로 O(n)이다.
+
+class Solution {
+    public int maxProfit(int[] prices) {
+        int len = prices.length;
+        int[] minArr = new int[len];
+        int[] maxArr = new int[len];
+
+        for(int i=0;i<len;i++){
+            if(i==0){
+                minArr[i] = prices[i];
+                maxArr[len-i-1] = prices[len-i-1];
+            }else{
+                minArr[i] = Math.min(minArr[i-1], prices[i]);
+                maxArr[len-i-1] = Math.max(maxArr[len-i], prices[len-i-1]);
+            }
+        }
+
+        int result = 0;
+        for(int i=0;i<len;i++){
+            result = Math.max(result, maxArr[i]-minArr[i]);
+        }
+        return result;
+    }
+}
+
+
+// 2nd solution 
+// 시간 복잡도: O(n)
+// 공간 복잡도: O(1) 
+
+class Solution{
+    public int maxProfit(int[] prices){
+        int len = prices.length;
+        int buy = prices[0];
+        int result = 0;
+
+        for(int i=1;i<len;i++){
+            if(prices[i]<buy){ // 더 저렴한 주식이 있으므로
+                buy = prices[i]; // 이 주식을 산다.
+            }else{
+                result = Math.max(result, prices[i]-buy); // 현재 주식을 팔았을 때 이득이 더 크다면 판다.
+            }
+        }
+        return result;
+    }
+}
diff --git a/encode-and-decode-strings/eunhwa99.java b/encode-and-decode-strings/eunhwa99.java
new file mode 100644
index 000000000..de06b5744
--- /dev/null
+++ b/encode-and-decode-strings/eunhwa99.java
@@ -0,0 +1,48 @@
+import java.util.ArrayList;
+import java.util.List;
+// n: 문자열 리스트 길이, m: 각 문자열의 길이. 
+
+// 시간 복잡도
+// Encoding: O(n * m) 
+// Decoding: O(n * m)
+// 공간 복잡도
+// Encoding: O(n * m),
+// Decoding: O(n * m) 
+class Solution {
+
+    // 받아온 string 들을 한 문자열로 합침
+    // (문자열길이)#(문자열) 형식
+    public String encode(List<String> strs) {
+        StringBuilder encodedStr = new StringBuilder();
+        for (String str : strs) {
+            encodedStr.append(str.length()).append('#').append(str);
+        }
+        return encodedStr.toString();
+    }
+
+    // Decodes a single string to a list of strings
+    public List<String> decode(String s) {
+        List<String> result = new ArrayList<>();
+        int i = 0;
+        
+        while (i < s.length()) {
+            
+            int j = i;
+            while (s.charAt(j) != '#') { // # 문자 찾기
+                j++;
+            }
+            
+            // 문자열 길이 추출
+            int length = Integer.parseInt(s.substring(i, j));
+            
+            // 위에서 구한 문자열 길이만큼 문자열 추출
+            result.add(s.substring(j + 1, j + 1 + length));
+            
+            // i 위치 변경
+            i = j + 1 + length;
+        }
+        
+        return result;
+    }
+
+}
diff --git a/group-anagrams/eunhwa99.java b/group-anagrams/eunhwa99.java
new file mode 100644
index 000000000..4e969ccdb
--- /dev/null
+++ b/group-anagrams/eunhwa99.java
@@ -0,0 +1,31 @@
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+// 해결법
+// 1. 배열 안의 월소들을 순회한다.
+// 2. 각 원소에 대하여 문자열을 정렬한 후, hashmap에 넣는다. 이 때 hashMap 자료구조는 <String, List<String>> 형태로 만든다.
+
+// 시간 복잡도: 
+// 1. 크기가 m인 문자열을 정렬할 때 O(mlogm)이 소요
+// 2. 배열의 크기가 n 이므로 순회하는데 O(n)
+// 3. hashmap 삽입은 O(1)
+// 위 사실들을 조합하면 총 O(nmlogm)이 소요된다.
+// 참고로, 전체 배열 크기는 최대 10^4 이고, 각 문자열의 길이는 최대 100이므로, 위와 같이 접근할 경우, 최대 10^6의 시간 복잡도를 가진다.
+
+// 공간 복잡도: hashmap 크기만큼 사용 -> O(nm)
+
+class Solution{
+    public List<List<String>> groupAnagrams(String[] strs) {
+        Map<String, List<String>> map = new HashMap<>();
+        for(String str: strs){
+            char[] charArr = str.toCharArray();
+            Arrays.sort(charArr);
+
+            map.computeIfAbsent(String.valueOf(charArr), key -> new ArrayList<>()).add(str);
+        }
+        return map.values().stream().toList();
+    }
+}
diff --git a/implement-trie-prefix-tree/eunhwa99.java b/implement-trie-prefix-tree/eunhwa99.java
new file mode 100644
index 000000000..051ce7126
--- /dev/null
+++ b/implement-trie-prefix-tree/eunhwa99.java
@@ -0,0 +1,35 @@
+import java.util.HashMap;
+import java.util.Map;
+
+// insert 시, 문자열의 prefix를 다 Map에 저장하고, 해당 문자열은 prefix 이므로 boolean false 로 설정
+// prefix가 아닌 온전한 문자열 삽입은 true 로 저장
+
+// search 시, Map에 해당 단어가 있는지 확인하고, boolean 값이 true 인지 확인
+// startsWith는 그냥 Map 에 해당 문자열이 있는지 확인하면 된다.
+
+// 공간 복잡도: Map 크기 -> O(N)
+// 시간 복잡도: 전체 호출 수 * String 길이 -> O(N*M)
+// 참고) 최대 시간 복잡도 : 2000 * 3*10^4 = 6*10^7
+class Trie {
+
+    Map<String,Boolean> stringSet;
+    public Trie() {
+        stringSet = new HashMap<>();
+    }
+    
+    public void insert(String word) {
+        for(int i=0;i<word.length();i++){
+            stringSet.putIfAbsent(word.substring(0, i), false);
+        }
+      stringSet.put(word, true);
+    }
+    
+    public boolean search(String word) {
+        return stringSet.containsKey(word) && stringSet.get(word)==true;
+    }
+    
+    public boolean startsWith(String prefix) {
+       
+        return stringSet.containsKey(prefix);
+    }
+}
diff --git a/word-break/eunhwa99.java b/word-break/eunhwa99.java
new file mode 100644
index 000000000..0ceac9de6
--- /dev/null
+++ b/word-break/eunhwa99.java
@@ -0,0 +1,36 @@
+import java.util.List;
+
+
+// 풀이
+// dfs + memo 
+// memo[i] = true/false : i 인덱스에서 시작해서 wordDict에 존재하는 모든 부분문자열 찾을 수 있는 경로가 있는지 유무
+//시간 복잡도: O(n*n) = start~end(재귀) + start~end(반복문)
+// 공간 복잡도: O(n) - 재귀 깊이
+
+class Solution {
+    
+    public boolean wordBreak(String s, List<String> wordDict) {
+        return dfs(0, s.length(), s, wordDict, new Boolean[s.length()]);
+
+    }
+    public boolean dfs(int start,  int len, String s, List<String> wordDict, Boolean[] memo){
+        if(start==len){
+            return true;
+        }
+
+        if(memo[start]!=null) return memo[start]; 
+
+        for(int end=start+1; end<=len;end++){
+            if(wordDict.contains(s.substring(start, end))){
+                if(dfs(end, len, s, wordDict, memo)){
+                    memo[start] = true; 
+                    return true;
+                }
+            }
+        }
+
+       memo[start]=false;
+       return false;
+
+    }
+}