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
51 changes: 51 additions & 0 deletions binary-tree-level-order-traversal/hwi-middle.cpp

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.

🏷️ 알고리즘 패턴 분석

  • 패턴: BFS
  • 설명: 이 코드는 큐를 이용한 너비 우선 탐색(BFS)로 트리의 각 레벨을 순회하며 결과를 저장합니다. 레벨별로 노드를 처리하는 방식이 BFS의 특징입니다.

📊 시간/공간 복잡도 분석

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

피드백: 큐를 이용한 BFS로 모든 노드를 한 번씩 방문하며, 노드 수에 비례하는 공간이 필요하다.

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> v;
if (root == nullptr)
{
return v;
}

// BFS로 해결
queue<pair<TreeNode*, int>> q;
q.push({root, 0});
while (!q.empty())
{
TreeNode* cur;
int h;
tie(cur, h) = q.front();
q.pop();

if (v.size() == h)
{
v.push_back(vector<int>());
}

v[h].push_back(cur->val);

if (cur->left != nullptr)
{
q.push({cur->left, h + 1});
}

if (cur->right != nullptr)
{
q.push({cur->right, h + 1});
}
}

return v;
}
};
13 changes: 13 additions & 0 deletions counting-bits/hwi-middle.cpp

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
  • 설명: 이 코드는 비트 조작을 이용하여 각 숫자의 1 비트 개수를 계산하는 방식으로, 비트 연산의 특성을 활용하는 패턴입니다.

📊 시간/공간 복잡도 분석

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

피드백: 단일 반복문으로 i & (i - 1) 연산을 통해 이전 값에 1을 더하는 방식으로 계산하며, 모든 수를 한 번씩 처리한다.

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class Solution {
public:
vector<int> countBits(int n) {
// i & (i - 1)은 가장 오른쪽 비트 1을 지운다는 성질을 이용
vector<int> ans(n + 1); // ans[0]은 0으로 초기화
for (int i = 1; i <= n; ++i)
{
ans[i] = ans[i & (i - 1)] + 1;
}

return ans;
}
};
25 changes: 25 additions & 0 deletions house-robber-ii/hwi-middle.cpp

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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Dynamic Programming
  • 설명: 이 코드는 원형 배열에서 연속된 집을 털 때, 최적의 선택을 위해 DP를 이용한 최댓값 계산 방식을 사용합니다. 각 경우별 최적 해를 구하고 비교하는 방식이 DP 패턴에 속합니다.

📊 시간/공간 복잡도 분석

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

피드백: 두 개의 독립된 DP 계산을 통해 최적 해를 구하며, 각각의 경우에 대해 배열을 한 번씩 순회한다.

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.size() == 1)
{
return nums[0];
}

// 1번째 집과 n번째 집이 이웃하므로, [1, n)과 (1, n]에 대해 탐색 후 최댓값 반환
return max(sol(span(nums).subspan(0, nums.size() - 1)), sol(span(nums).subspan(1)));
}

int sol(span<int> nums) {
int len = nums.size() + 1;
vector<int> d(len);
d[0] = 0;
d[1] = nums[0];
for(int i = 2; i < len; ++i)
{
d[i] = max(d[i - 1], d[i - 2] + nums[i - 1]);
}

return d[len - 1];
}
};
39 changes: 39 additions & 0 deletions meeting-rooms-ii/hwi-middle.cpp

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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Greedy, Interval Scheduling
  • 설명: 이 코드는 회의실 배정을 위해 시작 시간 기준 정렬 후, 가장 먼저 끝나는 회의실을 재사용하는 방식으로 최적의 회의실 수를 찾는 그리디 알고리즘입니다. 회의 종료 시간을 활용하여 효율적으로 자원을 할당하는 전략을 사용합니다.

📊 시간/공간 복잡도 분석

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

피드백: 이중 루프로 회의실을 찾기 때문에 최악의 경우 O(n^2) 시간이 소요되며, 회의실 리스트는 최대 n개까지 유지한다.

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
class Solution {
public:
int minMeetingRooms(vector<vector<int>>& intervals) {
// 시작 시간이 빠른 순으로 정렬
int n = intervals.size();
sort(intervals.begin(), intervals.end(), [](vector<int>& a, vector<int>& b)
{
return a[0] < b[0];
});

// 회의실이 부족할 때 마다 하나씩 추가
// rooms에는 각 회의실을 마지막으로 이용한 회의의 종료 시간이 들어있음
vector<int> rooms;
rooms.push_back({intervals[0][1]});

for (int i = 1; i < n; ++i)
{
bool found = false;
for (auto& room : rooms)
{
// 빈 회의실을 찾은 경우
if (room <= intervals[i][0])
{
room = intervals[i][1];
found = true;
break;
}
}

// 빈 회의실을 찾지 못한 경우
if (!found)
{
rooms.push_back(intervals[i][1]);
}
}

return rooms.size();
}
};
148 changes: 148 additions & 0 deletions word-search-ii/hwi-middle.cpp

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
  • 설명: 이 코드는 트라이 구조를 활용하여 단어 검색을 효율화하고, DFS 기반 백트래킹으로 보드 내 탐색을 수행합니다. 두 패턴이 결합되어 문제 해결에 적합합니다.

📊 시간/공간 복잡도 분석

복잡도
Time O(M * 4^L)
Space O(N * L)

피드백: 트라이를 이용한 DFS로 효율적으로 탐색하며, 불필요한 경로를 제거하는 최적화도 포함되어 있다.

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
class Solution {
private:
// 트라이(Trie)를 활용
struct Node
{
bool isWord = false;
Node* children[26];
Node() : isWord(false)
{
fill(children, children + 26, nullptr);
}

bool isEmpty()
{
for (int i = 0; i < 26; ++i)
{
if (children[i] != nullptr)
{
return false;
}
}

return true;
}
};

// 각 노드는 배열로 관리
static constexpr size_t POOL_SIZE = 300001;
Node pool[POOL_SIZE];
int poolIdx = 0;

Node* newNode()
{
pool[poolIdx] = Node();
return &pool[poolIdx++];
}

Node* root;
vector<string> ans;
int row;
int col;

public:
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
// 트라이 구성 시작
poolIdx = 0;
ans.clear();
root = newNode();
for (auto& word : words)
{
Node* cur = root;
for (auto ch : word)
{
auto& child = cur->children[ch - 'a'];
if (child == nullptr)
{
child = newNode();
}

cur = child;
}

cur->isWord = true;
}

// 한 칸씩 탐색 시작
row = board.size();
col = board[0].size();
for (int r = 0; r < row; ++r)
{
for (int c = 0; c < col; ++c)
{
string s = "";
solve(board, root, s, r, c);
}
}

return ans;
}

void solve(vector<vector<char>>& board, Node*& node, string& s, int r, int c)
{
// 경로가 제거된 경우
if (node == nullptr)
{
return;
}

// 범위를 벗어난 경우
if (r < 0 || r >= row || c < 0 || c >= col)
{
return;
}

// 이미 방문한 경우
char ch = board[r][c];
if (ch == '?')
{
return;
}

// 트라이에 이 문자가 없는 경우 (찾을 단어에 포함되지 않음)
if (node->children[ch - 'a'] == nullptr)
{
return;
}

// 이 문자가 하나의 단어를 구성하는 경우
if (node->children[ch - 'a']->isWord)
{
s.push_back(ch);
ans.push_back(s);
s.pop_back();
node->children[ch - 'a']->isWord = false; // 중복 마킹 방지
}

board[r][c] = '?'; // 이미 방문한 곳으로 돌아오지 않도록 입력으로 들어오지 않는 문자로 치환

// 상하좌우 탐색
static int dr[4] = { 1, 0, -1, 0 };
static int dc[4] = { 0, 1, 0, -1 };

for (int dir = 0; dir < 4; ++dir)
{
int nr = r + dr[dir];
int nc = c + dc[dir];
s.push_back(ch);
solve(board, node->children[ch - 'a'], s, nr, nc);
s.pop_back();
}

board[r][c] = ch; // 원래 문자로 되돌리기

// 더 이상 탐색이 필요 없는 곳은 경로 자체를 제거
// 일단 자식 먼저 판단
Node*& child = node->children[ch - 'a'];
if (child != nullptr && !child->isWord && child->isEmpty())
{
child = nullptr;
}

// 자신도 지울 수 있으면 지움
if (!node->isWord && node->isEmpty())
{
node = nullptr;
}
}
};
Loading