diff --git a/best-time-to-buy-and-sell-stock/Baekwangho.ts b/best-time-to-buy-and-sell-stock/Baekwangho.ts new file mode 100644 index 000000000..facc4ca99 --- /dev/null +++ b/best-time-to-buy-and-sell-stock/Baekwangho.ts @@ -0,0 +1,68 @@ +/** +일단 가장 단순하게 생각했을 때, +n^2 의 시간 복잡도를 가지면 모든 경우의 수를 확인가능하다. + +function maxProfit(prices: number[]): number { + let maximum = 0 + for(let i=0; i maximum) maximum = prices[j] - prices[i] + } + } + return maximum +}; + */ + +/** +하지만 시간 초과가 발생하니, 다른 방법을 써보자. +이익을 구하기 위해서는 가장 낮은 지점과 가장 큰 지점에 대한 탐색이 필요하다. +가장 낮은 지점은 큰 지점보다 앞에 위치해야 한다. + +만약 투 포인터로 양 끝에서 오면서 왼쪽은 가장 낮은 것, 오른쪽은 가장 높은 것을 확인해서 +두 포인터가 만날 때 차분을 구한다면? + +function maxProfit(prices: number[]): number { + let left = prices[0]; + let right = prices[prices.length-1]; + for (let i=0; i (prices.length - 1 - i)) { + break + } + + if (prices[i] < left) { + left = prices[i] + } + + if (prices[prices.length - 1 - i] > right) { + right = prices[prices.length - 1 - i] + } + } + + return left > right ? 0 : right - left +}; +*/ + +/** +[3,2,6,5,0,3] 와 같은 경우에 일반화 되지 못한다. +정답을 기준으로, 큰 값 이후에는 그보다 큰 값이 없어야 하고, +작은 값 이전에는 그보다 작은 값이 없어야 한다. + +그렇다면 포인터를 이 기준에 맞게 급격히 옮겨볼까? +... +힌트를 보고 왔다. 단순하게 최저값을 항상 갱신해주면 되는구나. + */ +function maxProfit(prices: number[]): number { + let min = 10000; + let max = 0; + for (let i = 0; i < prices.length; i++) { + if (prices[i] < min) { + min = prices[i]; + continue; + } + + if (prices[i] - min > max) { + max = prices[i] - min; + } + } + return max; +} diff --git a/group-anagrams/Baekwangho.ts b/group-anagrams/Baekwangho.ts new file mode 100644 index 000000000..65eccec3a --- /dev/null +++ b/group-anagrams/Baekwangho.ts @@ -0,0 +1,22 @@ +/** +3글자씩으로 구성된 각 문자열 배열을 순회하며, 각 문자열을 알파벳 순서로 정렬한 순서를 기준으로 +동일하다면 원래의 문자열을 key 로 하는 해시에 포함시켜보자 + +시간 복잡도: O(n log n) 공간 복잡도: O(n) 정도 나오지 않을까? + */ +function groupAnagrams(strs: string[]): string[][] { + const anaMap = new Map(); + + for (let i = 0; i < strs.length; i++) { + const hashKey = strs[i].split("").sort().join(""); + + const arr = anaMap.get(hashKey); + if (!arr) { + anaMap.set(hashKey, [strs[i]]); + } else { + anaMap.set(hashKey, [...arr, strs[i]]); + } + } + + return [...anaMap.values()]; +} diff --git a/implement-trie-prefix-tree/Baekwangho.ts b/implement-trie-prefix-tree/Baekwangho.ts new file mode 100644 index 000000000..e8bd7b5f1 --- /dev/null +++ b/implement-trie-prefix-tree/Baekwangho.ts @@ -0,0 +1,65 @@ +/** +test case 를 분석해본 결과, 결국 문자열에 대한 트리를 구성해야 하는 것으로 보임 +트리는 노드로 구성할 수 있을 듯 하지만, 구현하지 않고 hash 의 연속을 만들어보는 것으로 하자. + +오래걸렸지만 한번에 성공! 시간 복잡도: O(n), 공간 복잡도: O(1) 정도인 듯 + */ +class Trie { + constructor(private letterHash: any = {}) {} + + insert(word: string): void { + let currentHash = this.letterHash; + + for (let i = 0; i < word.length; i++) { + const existHash = currentHash[word[i]]; + if (existHash) { + currentHash = existHash; + } else { + currentHash[word[i]] = {}; + currentHash = currentHash[word[i]]; + } + } + + currentHash["count"] = currentHash["count"] ? currentHash["count"] + 1 : 1; + } + + search(word: string): boolean { + let currentHash = this.letterHash; + + for (let i = 0; i < word.length; i++) { + const existHash = currentHash[word[i]]; + // console.log(`search ${word}`, JSON.stringify(existHash), word[i]) + if (existHash) { + currentHash = existHash; + } else { + return false; + } + } + + return !!currentHash["count"]; + } + + startsWith(prefix: string): boolean { + let currentHash = this.letterHash; + + for (let i = 0; i < prefix.length; i++) { + const existHash = currentHash[prefix[i]]; + // console.log(`startsWith ${prefix}`, JSON.stringify(existHash), prefix[i]) + if (existHash) { + currentHash = existHash; + } else { + return false; + } + } + + return true; + } +} + +/** + * Your Trie object will be instantiated and called as such: + * var obj = new Trie() + * obj.insert(word) + * var param_2 = obj.search(word) + * var param_3 = obj.startsWith(prefix) + */