Skip to content
Open
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
67 changes: 67 additions & 0 deletions design-add-and-search-words-data-structure/lkhoony.js
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏷️ 알고리즘 패턴 분석

  • 패턴: Trie, Backtracking
  • 설명: 이 코드는 트라이 자료구조를 사용하여 단어 검색을 효율화하며, '.' 와일드카드 문자 처리 시 백트래킹 기법이 활용됩니다. 트라이로 빠른 검색과 백트래킹으로 여러 경로 탐색이 결합된 구조입니다.

📊 시간/공간 복잡도 분석

ℹ️ 이 파일에는 2가지 풀이가 포함되어 있어 각각 분석합니다.

풀이 1: WordDictionary.prototype.addWord — Time: O(m) / Space: O(n * m)
복잡도
Time O(m)
Space O(n * m)

피드백: 단어의 길이 m에 비례하는 시간 복잡도를 가지며, 모든 단어를 저장하는 데 공간이 단어 수 n과 단어 길이 m에 비례한다.

개선 제안: 현재 구현이 적절해 보입니다.

풀이 2: WordDictionary.prototype.search — Time: O(n * m) / Space: O(m)
복잡도
Time O(n * m)
Space O(m)

피드백: 최악의 경우 '.'가 모든 문자에 대해 재귀 호출을 유발하여 시간 복잡도가 증가할 수 있지만, 평균적으로는 효율적이다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const Node = function() {
this.children = {};
this.isEnd = false;
}

var WordDictionary = function() {
this.root = new Node();
};

/**
* @param {string} word
* @return {void}
*/
WordDictionary.prototype.addWord = function(word) {
let currentNode = this.root;

for (let char of word) {
if (!currentNode.children[char]) {
currentNode.children[char] = new Node();
}
currentNode = currentNode.children[char];
}

currentNode.isEnd = true;
};

/**
* @param {string} word
* @return {boolean}
*/
WordDictionary.prototype.search = function(word) {
if (word === undefined) return false;
return this._search(this.root, word, 0);
};

WordDictionary.prototype._search = function(node, word, index) {
if (index === word.length) {
return node.isEnd;
}

const char = word[index];

if (char !== '.') {
const child = node.children[char];
return child ? this._search(child, word, index + 1) : false;
}

for (const key in node.children) {
if (this._search(node.children[key], word, index + 1)) {
return true;
}
}

return false;
};

/**
* Your WordDictionary object will be instantiated and called as such:
* var obj = new WordDictionary()
* obj.addWord(word)
* var param_2 = obj.search(word)
*/

// n: 단어수, m: 단어 길이
// addWord: 시간 복잡도 O(m)
// search: 시간 복잡도 O(m^2)
// 공간 복잡도 O(n * m)
43 changes: 43 additions & 0 deletions find-minimum-in-rotated-sorted-array/lkhoony.js
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏷️ 알고리즘 패턴 분석

  • 패턴: Binary Search
  • 설명: 중앙값을 기준으로 배열을 반으로 나누며 최소값 위치를 찾는 이진 탐색 방식이 사용되어 해당 패턴에 속합니다. 정렬된 배열이 회전된 특성을 활용하여 효율적으로 검색합니다.

📊 시간/공간 복잡도 분석

ℹ️ 이 파일에는 3가지 풀이가 포함되어 있어 각각 분석합니다.

풀이 1: findMin_use_math_min — Time: ❌ O(n^4) → O(n) / Space: ❌ O(n) → O(1)
유저 분석 실제 분석 결과
Time O(n^4) O(n)
Space O(n) O(1)

피드백: 배열 크기만큼 모든 원소를 탐색하므로 시간 복잡도는 선형이며, 공간은 상수이다.

개선 제안: 이 방법은 배열 크기가 커질수록 비효율적이므로 이진 탐색 방법을 고려하는 것이 좋다.

풀이 2: findMin_naive — Time: ❌ O(n^6) → O(n) / Space: ✅ O(1) → O(1)
유저 분석 실제 분석 결과
Time O(n^6) O(n)
Space O(1) O(1)

피드백: 단순 탐색으로 구현이 쉽지만, 최악의 경우 배열 전체를 탐색하므로 시간 복잡도는 선형이다.

개선 제안: 이진 탐색을 활용하는 방법이 더 효율적이다.

풀이 3: findMin — Time: ❌ O(n^2*logn) → O(log n) / Space: ✅ O(1) → O(1)
유저 분석 실제 분석 결과
Time O(n^2*logn) O(log n)
Space O(1) O(1)

피드백: 이진 탐색을 통해 배열을 반으로 나누며 최소값을 찾기 때문에 시간 복잡도는 로그 시간이다.

개선 제안: 현재 구현이 적절해 보입니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// math의 min을 이용하는 방법
// tc: O(n^4)
// sc: 잘 몰랐는데 모든 요소를 함수 인자로 풀어 콜스택에 올린다 하여 O(n)이 된다고 함..
// (대용량의 배열 시 maximum exceed 에러가 날 수 있음)
const findMin_use_math_min = function (nums) {
return Math.min(...nums);
};

// 메서드를 사용하지 않은 풀이.
// tc: O(n^6)
// sc: O(1)
const findMin_naive = function (nums) {
let min = nums[0];

for (let i = 1; i < nums.length; i++) {
if (nums[i] <= min) {
min = nums[i];
break;
}
}

return min;
};

// 시간복잡도를 문제의 요구사항에 맞도록 줄여본 풀이
// tc: O(n^2*logn)
// sc: O(1)
const findMin = function (nums) {
let left = 0,
right = nums.length - 1;

while (left < right) {
let mid = Math.floor((left + right) / 2);

if (nums[mid] > nums[right]) {
left = mid + 1;
} else {
right = mid;
}
}

return nums[left];
};
38 changes: 38 additions & 0 deletions graph-valid-tree/lkhoony.js
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏷️ 알고리즘 패턴 분석

  • 패턴: DFS
  • 설명: 이 코드는 그래프의 연결성과 사이클 유무를 DFS로 탐색하여 검증하는 방식으로, 그래프 탐색 패턴에 속합니다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n + e)
Space O(n + e)

피드백: 모든 노드와 간선을 탐색하므로 시간과 공간 복잡도는 노드와 간선 수에 비례한다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export class Solution {
/**
* @param {number} n - number of nodes
* @param {number[][]} edges - undirected edges
* @return {boolean}
*/
validTree(n, edges) {
if (n === 0) return true;

// 인접 리스트 생성
const adj = {};
for (let i = 0; i < n; i++) {
adj[i] = [];
}
for (const [n1, n2] of edges) {
adj[n1].push(n2);
adj[n2].push(n1);
}

const visit = new Set();

const dfs = (i, prev) => {
if (visit.has(i)) return false;

visit.add(i);

for (const j of adj[i]) {
if (j === prev) continue;
if (!dfs(j, i)) return false;
}

return true;
};

return dfs(0, -1) && visit.size === n;
}
}

32 changes: 32 additions & 0 deletions linked-list-cycle/lkhoony.ts
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏷️ 알고리즘 패턴 분석

  • 패턴: Hash Map / Hash Set
  • 설명: 이 코드는 노드를 저장하는 Map을 사용하여 이미 방문한 노드를 체크하는 방식으로 순환 여부를 판단합니다. 따라서 Hash Map 또는 Hash Set 패턴에 속합니다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n)
Space O(n)

피드백: 모든 노드를 한 번씩 탐색하며, 방문 여부를 저장하는 데 공간이 필요하다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/

/*
리스트 노드를 저장하는 Map을 생성, 노드를 탐색하며 해당 Map에 노드를 저장하고 이미 있는 노드일 경우 true 리턴

시간복잡도 : O(N) - N은 리스트의 개수
공간복잡도 : O(N) - Map 객체
*/

function hasCycle(head: ListNode | null): boolean {
const nodeMap = new Map<ListNode, boolean>()

while (head) {
if (nodeMap.get(head) === true) {
return true
}
nodeMap.set(head, true)
head = head.next
}

return false
}
79 changes: 79 additions & 0 deletions pacific-atlantic-water-flow/lkhoony.ts
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏷️ 알고리즘 패턴 분석

  • 패턴: DFS
  • 설명: 이 코드는 깊이 우선 탐색(DFS)을 활용하여 각 셀에서 인접한 셀들을 탐색하며 조건에 맞게 체크하는 방식으로 문제를 해결한다.

📊 시간/공간 복잡도 분석

복잡도
Time O(m * n)
Space O(m * n)

피드백: 모든 셀에 대해 DFS를 수행하므로 시간과 공간 복잡도는 격자 크기에 비례한다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
pacific에 닿을 수 있는 grid를 판별하는 이중 배열과 atlantic에 닿을 수 있는지를 판별하는 이중 배열을 생성한다.
pacific 배열은 r, c 중 하나라도 0일 경우 true값,
atlantic 배열은 r, c 중 하나라도 length값과 같을 경우 true값을 채운다

이후 r, c 탐색을 돌며 pacific/ atlantic true인 값이 있으면 dfs를 돌린다
- 이전 heights값보다 크거나 같으면 true 처리, 인접한 셀을 또 dfs 탐색

두 배열값이 둘 다 true인 위치들을 리턴한다

시간복잡도 : O(M*N) - 순회
*/

function pacificAtlantic(heights: number[][]): number[][] {
const m = heights.length
const n = heights[0].length
const result = []
const pacificChecker = Array.from({ length: m }).map((el, idx) => {
if (idx === 0) {
return new Array(n).fill(true)
} else {
const arr = new Array(n).fill(false)
arr[0] = true
return arr
}
})
const atlanticChecker = Array.from({ length: m }).map((el, idx) => {
if (idx === m - 1) {
return new Array(n).fill(true)
} else {
const arr = new Array(n).fill(false)
arr[n - 1] = true
return arr
}
})

const dx = [0, 1, -1, 0]
const dy = [1, 0, 0, -1]

const search = (row, col, checker, stdValue) => {
const value = heights[row][col]
if (value < stdValue) return

checker[row][col] = true

for (let i = 0; i < 4; i++) {
const newRow = row + dx[i]
const newCol = col + dy[i]
if (newRow < 0 || newRow >= m) continue
if (newCol < 0 || newCol >= n) continue
if (checker[newRow][newCol]) continue

search(newRow, newCol, checker, value)
}
}

// dfs 탐색
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (pacificChecker[i][j]) {
search(i, j, pacificChecker, heights[i][j])
}
if (atlanticChecker[i][j]) {
search(i, j, atlanticChecker, heights[i][j])
}
}
}

for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (pacificChecker[i][j] && atlanticChecker[i][j]) {
result.push([i, j])
}
}
}

//pacific, atlantic 모두 true인 인덱스배열 반환
return result
}
12 changes: 12 additions & 0 deletions reverse-bits/lkhoony.rs
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏷️ 알고리즘 패턴 분석

  • 패턴: Bit Manipulation
  • 설명: 이 코드는 비트 연산을 이용하여 비트들을 뒤집는 작업을 수행하므로 Bit Manipulation 패턴에 속합니다. 효율적인 비트 조작을 통해 문제를 해결하는 방식입니다.

📊 시간/공간 복잡도 분석

유저 분석 실제 분석 결과
Time O(1) O(1)
Space O(1) O(1)

피드백: 고정된 32비트 연산이므로 시간과 공간 복잡도는 상수이다.

개선 제안: 현재 구현이 적절해 보입니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// TC: O(1)
// SC: O(1)
impl Solution {
pub fn reverse_bits(n: u32) -> u32 {
let mut res: u32 = 0;
for i in 0..32 {
let bit = (n >> i) & 1;
res += bit << (31 - i);
}
res
}
}
Loading