From 6bbd720360ba89fc929dcba1a66d5e5ba901d6c4 Mon Sep 17 00:00:00 2001 From: GangBean Date: Sun, 5 Jan 2025 09:57:40 +0900 Subject: [PATCH 1/5] feat: solve best time to buy and sell stock --- best-time-to-buy-and-sell-stock/GangBean.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 best-time-to-buy-and-sell-stock/GangBean.java diff --git a/best-time-to-buy-and-sell-stock/GangBean.java b/best-time-to-buy-and-sell-stock/GangBean.java new file mode 100644 index 000000000..7f4393f6b --- /dev/null +++ b/best-time-to-buy-and-sell-stock/GangBean.java @@ -0,0 +1,30 @@ +class Solution { + public int maxProfit(int[] prices) { + /** + 1. understanding + - price[i]: i th day's stock price + - to maximize profit, choose a single day to buy, and future day to sell. + - return maximum profit + - [7, 1, 5, 3, 6, 4] -> [0, 0, 4, 4, 5, 5] + - [7, 6, 4, 3, 1] -> [0, 0, 0, 0, 0] + 2. strategy + - profit = (sell price) - (buy price) + 3. complexity + - time: O(N) + - space: O(1) + */ + int minPrice = prices[0]; + for (int i = 0; i Date: Sun, 5 Jan 2025 10:17:59 +0900 Subject: [PATCH 2/5] feat: solve group anagrams --- group-anagrams/GangBean.java | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 group-anagrams/GangBean.java diff --git a/group-anagrams/GangBean.java b/group-anagrams/GangBean.java new file mode 100644 index 000000000..2b4afd29e --- /dev/null +++ b/group-anagrams/GangBean.java @@ -0,0 +1,37 @@ +class Solution { + public List> groupAnagrams(String[] strs) { + /** + 1. understanding + - grouping the anagrams together, and return groups + 2. strategy + - anagram group's identity: same characters with same counts + - so, transform each strs to character and count hashtable, called 'id'. + - if groups contains strs's 'id', then append + - return values list + 3. complexity + - time: O(N * L) where, N is the length of array strs, and L is the max length of each str + - space: O(N * L) + */ + Map, List> groups = new HashMap<>(); + for (String word: strs) { + Map id = idOf(word); + List group = groups.getOrDefault(id, new ArrayList<>()); + group.add(word); + groups.put(id, group); + } + + // System.out.println(groups); + List> ret = new ArrayList<>(); + ret.addAll(groups.values()); + return ret; + } + + private Map idOf(String word) { + Map id = new HashMap<>(); + for (char c: word.toCharArray()) { + id.put(c, id.getOrDefault(c, 0) + 1); + } + return id; + } +} + From 218f757a6b9d1f561a66afa523cc7ab890964850 Mon Sep 17 00:00:00 2001 From: GangBean Date: Sun, 5 Jan 2025 11:50:03 +0900 Subject: [PATCH 3/5] feat: solve encode and decode strings --- encode-and-decode-strings/GangBean.java | 52 +++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 encode-and-decode-strings/GangBean.java diff --git a/encode-and-decode-strings/GangBean.java b/encode-and-decode-strings/GangBean.java new file mode 100644 index 000000000..ddfbb8df6 --- /dev/null +++ b/encode-and-decode-strings/GangBean.java @@ -0,0 +1,52 @@ +import java.util.*; + +public class Codec { + /** + 1. complexity: + - time: O(N * L), where N is the length of strs, L is maximum length of each word in strs + - space: O(N * L) + */ + + // Encodes a list of strings to a single string. + public String encode(List strs) { + // 필요한 정보: 전체 원본 문자열, 각 단어의 위치와 길이 + StringBuilder origin = new StringBuilder(); + StringJoiner meta = new StringJoiner("/"); + StringJoiner encoded = new StringJoiner(";"); + int startIdx = 0; + for (String word: strs) { // O(N) + origin.append(word); + meta.add(String.format("(%d,%d)", startIdx, word.length())); + startIdx += word.length(); + } + + encoded.add(origin.toString()).add(meta.toString()); + return encoded.toString(); + } + + // Decodes a single string to a list of strings. + public List decode(String s) { + List ret = new ArrayList<>(); + int delimeterIdx = s.lastIndexOf(";"); // O(N * L) + String origin = s.substring(0, delimeterIdx); // O(N * L) + String meta = s.substring(delimeterIdx+1); // O(N * L) + String[] wordInfos = meta.split("/"); + for (String wordInfo: wordInfos) { // O(N) + delimeterIdx = wordInfo.indexOf(","); // O(1) + int length = Integer.parseInt(wordInfo.substring(delimeterIdx+1, wordInfo.length() - 1)); // O(1) + String word = ""; + if (length > 0) { + int startIdx = Integer.parseInt(wordInfo.substring(1, delimeterIdx)); + word = origin.substring(startIdx, startIdx + length); + } + ret.add(word); + } + return ret; + } +} + +// Your Codec object will be instantiated and called as such: +// Codec codec = new Codec(); +// codec.decode(codec.encode(strs)); + + From b1f13063db5ee23bf12b66ef50a2069e82d4a3a5 Mon Sep 17 00:00:00 2001 From: GangBean Date: Tue, 7 Jan 2025 19:13:00 +0900 Subject: [PATCH 4/5] feat: solve implement trie prefix tree --- implement-trie-prefix-tree/GangBean.java | 52 ++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 implement-trie-prefix-tree/GangBean.java diff --git a/implement-trie-prefix-tree/GangBean.java b/implement-trie-prefix-tree/GangBean.java new file mode 100644 index 000000000..454078831 --- /dev/null +++ b/implement-trie-prefix-tree/GangBean.java @@ -0,0 +1,52 @@ +class Trie { + /** + 1. understanding + - Trie data structure + - To process at most 3 * 10^4 calls in proper time, each call must be under O(N), where N is the length of word. + - insert: insert data into Trie + - search: find data from inserted Datas + - startsWith: find + 2. strategy + - a) use list to save inserted words + - insert: O(1) + - search: O(L * N), where L is the length of list, N is the length of each words. + - startsWith: O(L * N) + - total call to be 3 * 10^4, i assume each method call count at most 10^4 or linear correlation in 10^4 scale. + - so, L <= 10^4, N <= 10^4 + - space: O(L * N) + - it is enough to pass, but there are duplicates in space and also in excution count. + - b) + */ + + private List words; + public Trie() { + words = new ArrayList<>(); + } + + public void insert(String word) { + words.add(word); + } + + public boolean search(String word) { + for (String w: words) { + if (w.equals(word)) return true; + } + return false; + } + + public boolean startsWith(String prefix) { + for (String w: words) { + if (w.indexOf(prefix) == 0) return true; + } + return false; + } +} + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ + From b1150104fb9d7366e88303c9bc6ba23ff76ab35c Mon Sep 17 00:00:00 2001 From: GangBean Date: Tue, 7 Jan 2025 19:35:20 +0900 Subject: [PATCH 5/5] feat: solve word break --- word-break/GangBean.java | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 word-break/GangBean.java diff --git a/word-break/GangBean.java b/word-break/GangBean.java new file mode 100644 index 000000000..fa55a6ff6 --- /dev/null +++ b/word-break/GangBean.java @@ -0,0 +1,34 @@ +class Solution { + public boolean wordBreak(String s, List wordDict) { + /** + 1. understanding + - check if s's segments are all in wordDict. + - wordDict can be used multiple times + 2. strategy + a) dynamic programming + - dp[k]: substring(0,k+1) can be constructed by wordDict. + - dp[0]: false + - dp[1]: substring(0, 2) in wordDict + - dp[k+1] = substring(0, k+2) in wordDict || Any(dp[k] && substring(k+1, k+2) in wordDict) + - return dp[s.length()] + 3. complexity + - time: O(N^2 * S), where N is the length of s, S is search time each segment in wordDict. You can calculate S in O(1) time, when change wordDict to Set. so O(N) is final time complexity. + - space: O(N + W), W is the size of wordDict + */ + Set bow = new HashSet<>(wordDict); + boolean[] dp = new boolean[s.length() + 1]; + + for (int i = 1; i < dp.length; i++) { // O(N) + String segment = s.substring(0, i); + dp[i] = bow.contains(segment); + for (int j = 0; j < i; j++) { // O(N) + if (dp[i]) break; + segment = s.substring(j, i); + dp[i] = dp[i] || (dp[j] && bow.contains(segment)); // O(1) + } + } + + return dp[s.length()]; + } +} +