diff --git a/3sum/whewchews.ts b/3sum/whewchews.ts new file mode 100644 index 000000000..119b91296 --- /dev/null +++ b/3sum/whewchews.ts @@ -0,0 +1,33 @@ +function threeSum(nums: number[]): number[][] { + let result: [number, number, number][] = []; + const TARGET = 0; + // TC: O(NlogN) + nums.sort((a, b) => a - b); + + for (let i = 0; i < nums.length - 2; i++) { + if (i > 0 && nums[i] === nums[i - 1]) continue; + + let left = i + 1; + let right = nums.length - 1; + + while (left < right) { + let sum = nums[i] + nums[left] + nums[right]; + + if (sum === TARGET) { + result.push([nums[i], nums[left], nums[right]]); + while (nums[left] === nums[left + 1]) left++; + while (nums[right] === nums[right - 1]) right--; + left++; + right--; + } else if (sum < TARGET) { + left++; + } else { + right--; + } + } + } + + return result; +} +// TC: O(n^2) +// SC: O(n) diff --git a/best-time-to-buy-and-sell-stock/whewchews.ts b/best-time-to-buy-and-sell-stock/whewchews.ts new file mode 100644 index 000000000..fa18e809a --- /dev/null +++ b/best-time-to-buy-and-sell-stock/whewchews.ts @@ -0,0 +1,76 @@ +/* + * 아이디어 + * 수익을 얻기 위해서는 index보다 뒤에 오는 값 중에 현재 값보다 큰 값이 있어야 한다 + * 차이가 가장 큰 두 값을 찾으면 되는데, 그 값의 순서가 작은값 다음 큰 값 순이어야 한다 + * 가격의 차이를 어떻게 구할 수 있을까? + * for문을 두번 돌면서 값의 차이를 저장해둔다.(순서가 일치해야함) + * 값의 차이 중 가장 큰 값을 리턴한다. + * 리턴할 값이 없으면 0을 리턴한다. + * ====> 이 방법으로 풀었더니 타임초과가 나왔다. + * 어떻게 시간복잡도를 줄일 수 있을까? + * for문을 두번돌면 O(n^2)이 드니 for문을 한번만 돌게 하면 좋을 것 같다. + * for문을 돌면서 가장 작은 구매가, 최대 이익 두가지 변수를 업데이트 하자 + * ===> 연습삼아 투포인터로도 풀어보자 + */ + +function maxProfit1(prices: number[]): number { + let profit = 0; + + for (let i = 0; i <= prices.length - 2; i++) { + const x = prices[i]; + for (let j = i + 1; j <= prices.length - 1; j++) { + const y = prices[j]; + const diff = y - x; + if (x < y && profit < diff) { + profit = diff; + } + } + } + + return profit; +} +// TC: O(n^2) +// SC: O(1) + +function maxProfit2(prices: number[]): number { + let buyPrice = prices[0]; + let profit = 0; + + for (let i = 0; i <= prices.length - 1; i++) { + const todayPrice = prices[i]; + const diff = todayPrice - buyPrice; + + if (todayPrice <= buyPrice) { + buyPrice = todayPrice; + } else { + if (profit < diff) { + profit = todayPrice - buyPrice; + } + } + } + + return profit; +} +// TC: O(n) +// SC: O(1) + +function maxProfit3(prices: number[]): number { + let left = 0; + let right = 1; + let maxProfit = 0; + + while (right <= prices.length - 1) { + if (prices[left] > prices[right]) { + left = right; + } else { + const profit = prices[right] - prices[left]; + maxProfit = Math.max(profit, maxProfit); + } + + right++; + } + + return maxProfit; +} +// TC: O(n) +// SC: O(1) diff --git a/group-anagrams/whewchews.ts b/group-anagrams/whewchews.ts new file mode 100644 index 000000000..0e857a251 --- /dev/null +++ b/group-anagrams/whewchews.ts @@ -0,0 +1,45 @@ +/* +* 조건 +* 문자열은 영어 소문자 +* 서로 anagram이 되는 쌍을 배열로 묶어서 리턴 +* 자기 자신은 anagram 혼자서 가능함 +* return 하는 배열 순서는 관계없음 + +* 아이디어 +* strs를 돌면서 str에 어떤 알파벳이 몇개씩 있는지를 계산한다 +* 알파벳 개수가 같은 문자열끼리 몹는다 +*/ +function groupAnagrams(strs: string[]): string[][] { + const anagramMap = new Map(); + + for (const str of strs) { + const sortedStr = generateAnagramKey2(str); + if (!anagramMap.has(sortedStr)) { + anagramMap.set(sortedStr, []); + } + + anagramMap.get(sortedStr)!.push(str); + } + + return Array.from(anagramMap.values()); +} +// TC: O(N * M) +// SC: O(N * M) + +function generateAnagramKey1(str: string): string { + return str.split("").sort().join(""); +} +// TC: O(NlogN) +// SC: O(N) + +function generateAnagramKey2(str: string): string { + let count = new Array(26).fill(0); + + for (let c of str) { + count[c.charCodeAt(0) - "a".charCodeAt(0)]++; + } + + return count.join("-"); +} +// TC: O(N) +// SC: O(1) diff --git a/implement-trie-prefix-tree/whewchews.ts b/implement-trie-prefix-tree/whewchews.ts new file mode 100644 index 000000000..1c5ef2f2a --- /dev/null +++ b/implement-trie-prefix-tree/whewchews.ts @@ -0,0 +1,46 @@ +/* + * 아이디어 + * 삽입된 전체 word를 저장해둔다. => wordSet + * 삽입된 단어의 1글자 ~ 단어길이 글자 만큼을 전부 각각 prefix로 저장해둔다. => prefixSet + * 중복처리를 위해 Set을 사용한다. + */ +class Trie { + wordSet: Set; + prefixSet: Set; + + constructor() { + this.wordSet = new Set(); + this.prefixSet = new Set(); + } + + // TC: O(n) // n = word.length + // SC: O(n) + insert(word: string): void { + let result = ""; + for (let i = 0; i < word.length; i++) { + result += word[i]; + this.prefixSet.add(result); + } + this.wordSet.add(word); + } + + // TC: O(1) + // SC: O(1) + search(word: string): boolean { + return this.wordSet.has(word); + } + + // TC: O(1) + // SC: O(1) + startsWith(prefix: string): boolean { + return this.prefixSet.has(prefix); + } +} + +/** + * 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) + */ diff --git a/word-break/whewchews.ts b/word-break/whewchews.ts new file mode 100644 index 000000000..02d1021bb --- /dev/null +++ b/word-break/whewchews.ts @@ -0,0 +1,34 @@ +/* +* 조건 +* 영어소문자로만 구성되어있음 +* wordDict안에 있는 문자를 가지고 s를 만들 수 있으면 true return + +* 아이디어 +* wordDict안에 있는 단어들 중 s의 prefix 단어를 찾는다. +* prefix가 되는 단어를 뺀, 나머지 뒤의 문자열이 wordDict안에 있는 단어로 시작되는지 찾는다. +* 이 과정을 반복해서, s의 길이가 0이 되면 true를 리턴한다. +* wordDict안에 있는 단어를 다 조회해도 s가 남아있다면 false를 리턴한다. +*/ + +function wordBreak(s: string, wordDict: string[]): boolean { + const memo: Record = {}; + return isBreak(s, wordDict, memo); +} + +function isBreak(s: string, wordDict: string[], memo: Record) { + if (s.length === 0) return true; + if (s in memo) return memo[s]; + for (const word of wordDict) { + const length = word.length; + if (s.startsWith(word) && isBreak(s.slice(length), wordDict, memo)) { + memo[s] = true; + return true; + } + } + + memo[s] = false; + return false; +} +// TC: O(s*w) +// SC: O(s) +// s: s.length, w: wordDict.length