Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions best-time-to-buy-and-sell-stock/Blossssom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
function maxProfit(prices: number[]): number {
let min = prices[0];
let max = 0;

for (let i = 0; i < prices.length; i++) {
min = Math.min(min, prices[i]);
max = Math.max(max, prices[i] - min);
}

return max;
}

const prices = [3, 3, 5, 0, 0, 3, 1, 4];
maxProfit(prices);


47 changes: 47 additions & 0 deletions encode-and-decode-strings/Blossssom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
class Solution {
private baseStr = "#";
/*
* @param strs: a list of strings
* @return: encodes a list of strings to a single string.
*/
public encode(strs: string[]): string {
let encodedStr = "";
for (const str of strs) {
encodedStr += `${str.length}${this.baseStr}${str}`;
}
return encodedStr;
}

/*
* @param str: A string
* @return: decodes a single string to a list of strings
*/
public decode(str: string): string[] {
const spliter = [];
let idx = 0;
while (idx < str.length) {
let findBase = idx;
// length가 10 이상일 경우를 위해 순회하며 파싱
while (str[findBase] !== this.baseStr) {
findBase++;
}

const contentLength = parseInt(str.substring(idx, findBase));
const content = str.substring(findBase + 1, findBase + contentLength + 1);
spliter.push(content);
idx = findBase + contentLength + 1;
}
return spliter;
}
}

const input = ["lint", "code", "love", "you"];

const solutionInstance = new Solution();

const encoded = solutionInstance.encode(input);
const decoded = solutionInstance.decode(encoded);

console.log(encoded, decoded);


46 changes: 46 additions & 0 deletions group-anagrams/Blossssom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* @param strs - 문자열 배열
* @returns - anagram이 가능한 이중 배열
* @description
* - 배열의 길이는 최대 10^4로 순회는 가능한 적게
* - 문자열의 최대 길이는 100으로 널널
* - 1. 내부 문자열 정렬 (O(N * K log K))
* - 2. 아스키로 변환하여 1번만 순회 (O(N * K))
*
* - 다만 문자열이 작을 경우 (현재 100 이하로 작은편) 정렬보다 배열 생성과 문자열 join이 더 무거워 질 수 있음
* - Map을 쓰는게 조금은 더 빠를듯
*/

// function groupAnagrams(strs: string[]): string[][] {
// const strObj: Record<string, string[]> = {};
// for (let i = 0; i < strs.length; i++) {
// const sortedItem = strs[i].split("").sort().join("");
// strObj[sortedItem] ??= [];
// strObj[sortedItem].push(strs[i]);
// }

// return Object.values(strObj);
// }

function groupAnagrams(strs: string[]): string[][] {
const strObj: Record<string, string[]> = {};
for (let i = 0; i < strs.length; i++) {
const alpha = Array.from({ length: 26 }, () => 0);

for (const st of strs[i]) {
alpha[st.charCodeAt(0) - "a".charCodeAt(0)]++;
}

const joinStr = alpha.join(",");
strObj[joinStr] ??= [];
strObj[joinStr].push(strs[i]);
}

return Object.values(strObj);
}

const strs = ["a"];

groupAnagrams(strs);


99 changes: 99 additions & 0 deletions implement-trie-prefix-tree/Blossssom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// 단순 구현 시 효율이 낮게 나옴
// class Trie {
// private word: Set<string>;
// constructor() {
// this.word = new Set();
// }

// insert(word: string): void {
// this.word.add(word);
// }

// search(word: string): boolean {
// return this.word.has(word);
// }

// startsWith(prefix: string): boolean {
// for (const str of this.word) {
// if (prefix.length > str.length) {
// continue;
// }
// let check = true;
// for (let i = 0; i < prefix.length; i++) {
// if (str[i] !== prefix[i]) {
// check = false;
// break;
// }
// }
// if (check) {
// return true;
// }
// }
// return false;
// }
// }

// 노드 구조를 개선
class TrieNode {
children: { [key: string]: TrieNode };
isEndOfWord: boolean;
constructor() {
this.children = {};
this.isEndOfWord = false;
}
}

class Trie {
private root: TrieNode;
constructor() {
this.root = new TrieNode();
}

insert(word: string): void {
// 글자 하나씩 TrieNode 타입으로 저장
let currentNode = this.root;
for (const char of word) {
if (!currentNode.children[char]) {
currentNode.children[char] = new TrieNode();
}

currentNode = currentNode.children[char];
}
currentNode.isEndOfWord = true;
console.log(this.root);
}

// 각 글자를 TrieNode에서 서칭하며 판단
search(word: string): boolean {
let currentNode = this.root;
for (const char of word) {
if (!currentNode.children[char]) {
return false;
}
currentNode = currentNode.children[char];
}
return currentNode.isEndOfWord;
}

// 동일 로직이지만 prefix 만큼만 존재하면 true
startsWith(prefix: string): boolean {
let currentNode = this.root;
for (const char of prefix) {
if (!currentNode.children[char]) {
return false;
}
currentNode = currentNode.children[char];
}
return true;
}
}

const trie = new Trie();
trie.insert("apple");
trie.search("apple"); // true
trie.search("app"); // false
trie.startsWith("app"); // true
trie.insert("app");
trie.search("app"); // true


35 changes: 35 additions & 0 deletions word-break/Blossssom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @param s - 타겟 문자열
* @param wordDict - 문자열 배열
* @returns - wordDict의 요소를 조합해 타겟 문자열을 만들 수 있는지 return
* @description
* - wordDict의 요소는 중복 사용 가능
* - dp 까진 생각했지만 세부 구현까진 힘들었음
*/

function wordBreak(s: string, wordDict: string[]): boolean {
// 각 요소별 남은 단어를 저장한다면?
const dictSet = new Set(wordDict);
const dp = Array.from({ length: s.length + 1 }, () => false);

dp[0] = true;

for (let i = 1; i <= s.length; i++) {
for (let j = 0; j < i; j++) {
if (dp[j] && dictSet.has(s.slice(j, i))) {
dp[i] = true;
break;
}
}
}

return dp[s.length];
}

const s = "catsandog";
const wordDict = ["cats", "dog", "sand", "and", "cat"];

const answer = wordBreak(s, wordDict);
console.log("is answer :", answer);