Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mallayon] Week 5 #873

Merged
merged 5 commits into from
Jan 10, 2025
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
24 changes: 24 additions & 0 deletions best-time-to-buy-and-sell-stock/mmyeon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
*
* 접근 방법 :
* - max profit을 구하는 문제로 O(n)으로 풀기
* - 현재 가격에서 가장 낮은 가격을 뺀 값을 max profit으로 설정
*
* 시간복잡도 : O(n)
* - n은 prices 길이, 요소 1회 순회하니까 O(n)
*
* 공간복잡도 : O(1)
* - 변수 2개 사용하니까 O(1)
*/

function maxProfit(prices: number[]): number {
let minPrice = prices[0],
maxProfit = 0;

for (const price of prices) {
minPrice = Math.min(price, minPrice);
maxProfit = Math.max(maxProfit, price - minPrice);
}

return maxProfit;
}
67 changes: 67 additions & 0 deletions encode-and-decode-strings/mmyeon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 시간복잡도 : O(n)
* - 배열 1회 순회하면서 문자열 합치기
*
* 공간복잡도 : O(1)
*/
function encode(strs: string[]): string {
let result = strs[0];

for (let i = 1; i < strs.length; i++) {
result += "#" + strs[i];
}
return result;
}
/*
* 시간복잡도 : O(n)
* - 문자 순회하면서 # 기준으로 나눔
*
* 공간복잡도 : O(n)
* - 문자열 길이만큼 생성해서 리턴
*/
function decode(encoded: string): string[] {
return encoded.split("#");
}

// 스택 활용하는 방법
/*
* 시간복잡도 : O(n)
*
* 공간복잡도 : O(1)
*/

// ["Hello","World"] => 5#Hello5#World
function encode(strs: string[]): string {
let result = "";
for (const str of strs) {
result += `${str.length}#${str}`;
}
return result;
}

/*
* 접근 방법 :
* - 배열 길이를 포함해서 encode한 뒤 decode할 때 길이 활용헤서 stack에 담는 방식
*
* 시간복잡도 : O(n)
* - 인코딩된 문자열 1회 순회
*
* 공간복잡도 : O(n)
* - n은 result 길이
*/

// 5#Hello5#World => ["Hello","World"]
function decode(encoded: string): string[] {
const result: string[] = [];
let index = 0;
while (index < encoded.length) {
const separatorIndex = encoded.indexOf("#", index);
const length = parseInt(encoded.slice(index, separatorIndex), 10);
index = separatorIndex + 1;
const str = encoded.slice(index, index + length);
result.push(str);
index += length;
}

return result;
}
31 changes: 31 additions & 0 deletions group-anagrams/mmyeon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
*
* 접근 방법 :
* - group anagrams 저장할 map 선언하기
* - 단어 문자열 strs 순회하면서 단어 정렬하기
* - map에 존재하지 않는 경우, 배열 형태로 맵에 저장하기.
* - map에 존재하는 경우, 기존 값에 현재 단어 추가하기
* - map의 값들만 리턴하기
*
* 시간복잡도 : O(n * klogk)
* - n은 strs 길이, k는 단어 길이
* - strs 배열 n번 순회 : O(n)
* - 각 단어 정렬 : O(klogk)
*
* 공간복잡도 : O(n)
* - map에 strs 길이만큼 저장하니까
*/
function groupAnagrams(strs: string[]): string[][] {
const map = new Map<string, string[]>();

for (const str of strs) {
const sortedWord = str.split("").sort().join("");
if (map.get(sortedWord)) {
map.get(sortedWord)!.push(str);
} else {
map.set(sortedWord, [str]);
}
}

return [...map.values()];
}
76 changes: 76 additions & 0 deletions implement-trie-prefix-tree/mmyeon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
class TrieNode {
children: Map<string, TrieNode>;
isEndOfWord: boolean;

constructor() {
// 키 : 문자, 값 : 다음 문자 노드
this.children = new Map();
this.isEndOfWord = false;
}
}

/**
* @link https://leetcode.com/problems/implement-trie-prefix-tree/description/
*
* 접근 방법 :
* - root 노드에서 시작해서 각 문자열을 children노드에 저장한다.
* - 문자열의 마지막 문자일 때 끝을 나타내기 위해서 isEndOfWord값을 true로 변경해준다.
* - insert : 각 문자열 순회하면서, 문자에 대한 children노드가 없으면 생성해서 문자와 다음 노드를 연결해준다.
*
* 시간복잡도 : O(n)
* - 문자 길이 n 만큼 문자 삽입함
*
* 공간복잡도 : O(n)
* - 최대 문자열 길이만큼 노드 추가됨
*/

class Trie {
root: TrieNode;

constructor() {
this.root = new TrieNode();
}

insert(word: string): void {
let currentNode = this.root;

for (const letter of word) {
// 현재 문자가 자식 노드에 있으면 이동
// 없으면 새 노드 생성해서 추가하기
if (!currentNode.children.has(letter)) {
currentNode.children.set(letter, new TrieNode());
}
// 자식 노드로 이동
currentNode = currentNode.children.get(letter) as TrieNode;
}
currentNode.isEndOfWord = true;
}

search(word: string): boolean {
let currentNode = this.root;

for (const letter of word) {
if (!currentNode.children.has(letter)) return false;
currentNode = currentNode.children.get(letter) as TrieNode;
}
return currentNode.isEndOfWord;
}

startsWith(prefix: string): boolean {
let currentNode = this.root;

for (const letter of prefix) {
if (!currentNode.children.has(letter)) return false;
currentNode = currentNode.children.get(letter) as TrieNode;
}
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)
*/
32 changes: 32 additions & 0 deletions word-break/mmyeon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// "leetcode"
// [ true, false, false, false, true, false, false, false, true ]
/**
* 접근 방법 : DP 바텀업 방식
* - 문자열 늘려가면서, 부분 문자열에 wordDict에 포함되는지 체크
*
* 시간복잡도 : O(n^2)
* - n은 문자열 s의 길이
* - 외부 반복문에서 문자열 순회(n번), 내부 반복문에서 최대 n번 순회
*
* 공간복잡도 : O(n)
* - 문자열 길이 n만큼 dp 배열 저장
*/
function wordBreak(s: string, wordDict: string[]): boolean {
const set = new Set(wordDict);
const dp = Array(s.length + 1).fill(false);
// 빈 문자열은 항상 나눌 수 있으니까 true
dp[0] = true;

// i는 문자열의 끝 인덱스
for (let i = 1; i <= s.length; i++) {
// j는 문자열의 시작 인덱스
for (let j = 0; j < i; j++) {
if (dp[j] && set.has(s.substring(j, i))) {
dp[i] = true;
break;
}
}
}

return dp[s.length];
}
Loading