-
-
Notifications
You must be signed in to change notification settings - Fork 195
[clara-shin] WEEK 05 solutions #1392
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
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
a48ed05
Best Time to Buy and Sell Stock solution
clara-shin a01fdcf
update Best Time to Buy and Sell Stock solution
clara-shin 830a03e
Group Anagrams solution
clara-shin aeabb3d
Word Search solution
clara-shin 6530354
Encode and Decode Strings solution
clara-shin 2c6c1d7
Implement Trie (Prefix Tree) solution
clara-shin aaeb0b1
Word Break solution
clara-shin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/** | ||
* 시간 복잡도 O(n) | ||
* 공간 복잡도 O(1) | ||
* | ||
* 그리디 알고리즘 | ||
* 현재까지의 최저 가격을 기억하고, 그 가격에 샀을 때의 이익을 계속 계산하여 최대 이익을 구함 | ||
*/ | ||
|
||
/** | ||
* @param {number[]} prices | ||
* @return {number} | ||
*/ | ||
var maxProfit = function (prices) { | ||
let minPrice = prices[0]; // 최저 가격 초기화 (첫 날 가격) | ||
let maxProfit = 0; // 최대 이익 초기화 (아직 이익 없음) | ||
|
||
// 두 번째 날부터 | ||
for (let i = 1; i < prices.length; i++) { | ||
minPrice = Math.min(minPrice, prices[i]); // 최저 가격 갱신 | ||
maxProfit = Math.max(maxProfit, prices[i] - minPrice); // 최대 이익 갱신 | ||
} | ||
|
||
return maxProfit; | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/** | ||
* 문자열 리스트를 하나의 문자열로 인코딩하고, 다시 디코딩 하기 | ||
* | ||
* 접근 방법: | ||
* 길이 기반 인코딩 => 각 문자열마다 "길이#문자열" 형식으로 인코딩 | ||
* "#"을 기준으로 문자열을 나누고, 길이를 이용해 원래 문자열을 복원하여 디코딩 | ||
*/ | ||
|
||
/** | ||
* @param {string[]} strs - 인코딩할 문자열 리스트 | ||
* @return {string} - 인코딩된 문자열 | ||
*/ | ||
var encode = function (strs) { | ||
if (!strs || strs.length === 0) return ''; | ||
return strs.map((str) => str.length + '#' + str).join(''); | ||
}; | ||
|
||
/** | ||
* @param {string} s - 디코딩할 인코딩된 문자열 | ||
* @return {string[]} - 원래의 문자열 리스트 | ||
*/ | ||
var decode = function (s) { | ||
if (!s || s.length === 0) return []; | ||
|
||
const result = []; | ||
let i = 0; | ||
|
||
while (i < s.length) { | ||
const delimiterIndex = s.indexOf('#', i); // '#'의 위치 찾기 | ||
const length = parseInt(s.slice(i, delimiterIndex)); // 길이 추출 | ||
|
||
const start = delimiterIndex + 1; // 문자열 시작 위치 | ||
result.push(s.slice(start, start + length)); // 알아낸 길이만큼 문자열 추출 후 결과에 추가 | ||
i = start + length; // 다음 문자열 시작 위치로 포인터 이동 | ||
} | ||
|
||
return result; | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/** | ||
* 문자열 배열 strs가 주어졌을 때, 애너그램끼리 그룹화하는 문제 | ||
* 애너그램: 같은 문자를 재배열하여 만들 수 있는 단어들 | ||
* | ||
* 접근 방법: 각 문자 출현빈도를 카운팅하는 방식 | ||
* 1. 각 문자열을 알파벳 개수로 변환하여 키를 생성 | ||
* 2. Map을 사용하여 키를 기준으로 문자열을 그룹화 | ||
* 3. Map의 값들을 배열로 변환하여 반환 | ||
* | ||
* 시간복잡도: O(n * k) (n: 문자열 개수, k: 문자열 길이) -> 단순 카운팅 | ||
* 공간복잡도: O(n * k) -> 모든 문자열을 저장해야 하므로 | ||
*/ | ||
|
||
/** | ||
* @param {string[]} strs | ||
* @return {string[][]} | ||
*/ | ||
var groupAnagrams = function (strs) { | ||
const map = new Map(); | ||
|
||
for (let str of strs) { | ||
const count = new Array(26).fill(0); // 알파벳 개수 초기화 | ||
for (let i = 0; i < str.length; i++) { | ||
const index = str.charCodeAt(i) - 'a'.charCodeAt(0); // 알파벳 인덱스 계산 | ||
count[index]++; // 해당 알파벳 개수 증가 | ||
} | ||
const key = count.join('#'); // 알파벳 개수를 문자열로 변환하여 키 생성 | ||
if (!map.has(key)) { | ||
map.set(key, []); // 키가 없으면 새로운 배열 생성 | ||
} | ||
map.get(key).push(str); // 해당 키에 문자열 추가 | ||
} | ||
|
||
return Array.from(map.values()); // Map의 값들을 배열로 변환하여 반환 | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// TrieNode 클래스 정의: 트라이의 각 노드를 표현 | ||
var TrieNode = function () { | ||
this.children = new Map(); // 자식 노드를 Map으로 저장 | ||
this.isEnd = false; // 단어의 끝을 표시하는 플래그 | ||
}; | ||
|
||
// Trie 클래스 정의: 트라이 자료구조를 표현 | ||
var Trie = function () { | ||
this.root = new TrieNode(); // 루트 노드 | ||
}; | ||
|
||
/** | ||
* @param {string} word | ||
* @return {void} | ||
*/ | ||
Trie.prototype.insert = function (word) { | ||
let node = this.root; // 현재 노드를 루트로 초기화 | ||
|
||
for (let i = 0; i < word.length; i++) { | ||
const char = word[i]; // 현재 문자 | ||
|
||
// 현재 문자에 대한 자식 노드가 없으면 새로 생성 | ||
if (!node.children.has(char)) { | ||
node.children.set(char, new TrieNode()); | ||
} | ||
|
||
// 다음 자식 노드로 이동 | ||
node = node.children.get(char); | ||
} | ||
node.isEnd = true; // 단어의 끝을 표시 | ||
}; | ||
|
||
/** | ||
* @param {string} word | ||
* @return {boolean} | ||
*/ | ||
Trie.prototype.search = function (word) { | ||
const node = this._searchPrefix(word); // 주어진 단어의 노드를 찾음 | ||
return node !== null && node.isEnd === true; // 경로가 존재하고, 마지막 노드가 단어의 끝인지 확인 | ||
}; | ||
|
||
/** | ||
* @param {string} prefix | ||
* @return {boolean} | ||
*/ | ||
Trie.prototype.startsWith = function (prefix) { | ||
return this._searchPrefix(prefix) !== null; // 경로가 존재하는지만 확인 | ||
}; | ||
|
||
/** | ||
* 헬퍼 메서드: 주어진 접두사에 대한 경로를 찾는 메서드 | ||
* @param {string} str | ||
* @return {TrieNode|null} 경로의 마지막 노드 또는 null | ||
* @private | ||
*/ | ||
Trie.prototype._searchPrefix = function (str) { | ||
let node = this.root; // 현재 노드를 루트로 초기화 | ||
|
||
// 주어진 문자열의 각 문자에 대해 노드 탐색 | ||
for (let i = 0; i < str.length; i++) { | ||
const char = str[i]; // 현재 문자 | ||
|
||
// 현재 문자에 대한 자식 노드가 없으면 null 리턴 | ||
if (!node.children.has(char)) { | ||
return null; | ||
} | ||
|
||
// 다음 자식 노드로 이동 | ||
node = node.children.get(char); | ||
} | ||
return node; // 경로의 마지막 노드 반환 | ||
}; | ||
/** | ||
* 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) | ||
*/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/** | ||
* 문자열 s가 주어진 단어 사전 wordDict의 단어들로 분리될 수 있는지 확인하는 문제 | ||
* 다이나믹 프로그래밍(DP) | ||
* 시간 복잡도: O(n * k) (k: 최대 단어 길이) | ||
* 공간 복잡도: O(n) (DP 배열 + 단어 집합) | ||
*/ | ||
|
||
/** | ||
* @param {string} s | ||
* @param {string[]} wordDict | ||
* @return {boolean} | ||
*/ | ||
var wordBreak = function (s, wordDict) { | ||
const n = s.length; | ||
const dp = new Array(n + 1).fill(false); // DP 배열 초기화 | ||
dp[0] = true; // 빈 문자열은 항상 분리 가능 | ||
|
||
const wordSet = new Set(wordDict); // 단어 사전을 Set으로 변환: 검색시간 O(1) | ||
|
||
const maxWordLength = Math.max(...wordDict.map((word) => word.length)); // 단어의 최대 길이 찾기 | ||
|
||
for (let i = 0; i <= n; i++) { | ||
// 가능한 단어 길이만 검사 | ||
for (let j = Math.max(0, i - maxWordLength); j < i; j++) { | ||
if (dp[j] && wordSet.has(s.substring(j, i))) { | ||
// dp[j]가 true이고, j부터 i까지의 부분 문자열이 단어 사전에 존재하는 경우 | ||
dp[i] = true; | ||
break; | ||
} | ||
} | ||
} | ||
|
||
return dp[n]; | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/** | ||
* 주어진 격자(board)에서 특정 단어(word)가 존재하는지 확인하는 함수 | ||
* | ||
* 접근 방식:DFS(깊이 우선 탐색) + 백트래킹 | ||
* 시간 복잡도: O(m * n * 4^k) (m: 행, n: 열, k: 단어 길이) | ||
* 공간 복잡도: O(m * n) (최대 깊이 m*n) | ||
* | ||
*/ | ||
|
||
/** | ||
* @param {character[][]} board | ||
* @param {string} word | ||
* @return {boolean} | ||
*/ | ||
var exist = function (board, word) { | ||
const m = board.length; | ||
const n = board[0].length; | ||
|
||
const directions = [ | ||
[-1, 0], | ||
[1, 0], | ||
[0, -1], | ||
[0, 1], | ||
]; | ||
|
||
function dfs(row, col, index) { | ||
if (index === word.length) { | ||
return true; | ||
} | ||
|
||
if (row < 0 || row >= m || col < 0 || col >= n || board[row][col] !== word[index]) { | ||
return false; | ||
} | ||
|
||
// 현재 셀 방문 표시 (임시로 변경) | ||
const temp = board[row][col]; | ||
board[row][col] = '#'; // 방문한 셀을 특수 문자로 표시 | ||
|
||
// 네 방향 탐색 | ||
for (const [dx, dy] of directions) { | ||
const newRow = row + dx; | ||
const newCol = col + dy; | ||
|
||
if (dfs(newRow, newCol, index + 1)) { | ||
// 단어를 찾았으면 원래 값 롤백 후 true 반환 | ||
board[row][col] = temp; | ||
return true; | ||
} | ||
} | ||
|
||
// 백트래킹(현재 셀의 원래 값 롤백) | ||
board[row][col] = temp; | ||
|
||
return false; | ||
} | ||
|
||
// 격자의 모든 셀에서 시작점으로 시도 | ||
for (let i = 0; i < m; i++) { | ||
for (let j = 0; j < n; j++) { | ||
if (board[i][j] === word[0] && dfs(i, j, 0)) { | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
// 모든 시작점에서 실패하면 | ||
return false; | ||
}; |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
alphabet index 를 활용하여 key 값을 만든 부분이 흥미롭습니다.
저는 sort 를 사용해서 Time Complexity 가 O(nklogk) 가 되었는데, 이 방식을 이용하면 O(nk) 로 줄일 수 있겠네요. 👍