From 278485cbbf628b3bb677e39dcee5e0f7c638ae4d Mon Sep 17 00:00:00 2001
From: whewchews <whewchews@gmail.com>
Date: Sun, 15 Sep 2024 00:58:53 +0900
Subject: [PATCH 1/5] 1. Best Time to Buy And Sell Stock

---
 best-time-to-buy-and-sell-stock/whewchews.ts | 76 ++++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100644 best-time-to-buy-and-sell-stock/whewchews.ts

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)

From aa435cf7b8f3b55cd51594c1eafeb2c9dd8df29e Mon Sep 17 00:00:00 2001
From: whewchews <whewchews@gmail.com>
Date: Sun, 15 Sep 2024 01:28:00 +0900
Subject: [PATCH 2/5] 2. Group Anagrams

---
 group-anagrams/whewchews.ts | 45 +++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 group-anagrams/whewchews.ts

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<string, string[]>();
+
+  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)

From f0175c7ffd6bdf939a764c2ee84e768621b0e63c Mon Sep 17 00:00:00 2001
From: whewchews <whewchews@gmail.com>
Date: Sun, 15 Sep 2024 01:35:11 +0900
Subject: [PATCH 3/5] 4. Implement Trie Prefix Tree

---
 implement-trie-prefix-tree/whewchews.ts | 46 +++++++++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 implement-trie-prefix-tree/whewchews.ts

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<string>;
+  prefixSet: Set<string>;
+
+  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)
+ */

From 8deb5e52801f71629147e17546c285399792cb7a Mon Sep 17 00:00:00 2001
From: whewchews <whewchews@gmail.com>
Date: Sun, 15 Sep 2024 02:18:26 +0900
Subject: [PATCH 4/5] 5. Word Break

---
 word-break/whewchews.ts | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)
 create mode 100644 word-break/whewchews.ts

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<string, boolean> = {};
+  return isBreak(s, wordDict, memo);
+}
+
+function isBreak(s: string, wordDict: string[], memo: Record<string, boolean>) {
+  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

From 6fdca7f868d83a0fccdaab1b75eb6a1d8a444c21 Mon Sep 17 00:00:00 2001
From: whewchews <whewchews@gmail.com>
Date: Sun, 15 Sep 2024 02:36:48 +0900
Subject: [PATCH 5/5] 3. 3Sum

---
 3sum/whewchews.ts | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 3sum/whewchews.ts

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)