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
28 changes: 28 additions & 0 deletions non-overlapping-intervals/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, Sorting
  • 설명: 이 코드는 종료 시간을 기준으로 정렬 후, 겹치지 않는 구간을 선택하는 그리디 알고리즘을 사용합니다. 정렬과 선택 전략이 핵심 패턴입니다.

📊 시간/공간 복잡도 분석

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

피드백: 입력 배열을 정렬하는 데 O(n log n)가 소요되고, 이후 한 번 순회하며 겹치는 구간을 세기 때문에 전체 시간 복잡도는 O(n log n)입니다. 공간은 정렬을 위한 제자리 정렬 또는 별도 배열 없이 인덱스만 사용하므로 O(1)입니다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end(), [](vector<int>& a, vector<int>& b) {
return a[1] < b[1];
});

int ans = 0;
int k = INT_MIN;

for (int i = 0; i < intervals.size(); i++)
{
int s = intervals[i][0];
int e = intervals[i][1];

if (s >= k)
{
k = e;
}
else
{
ans++;
}
}

return ans;
}
};
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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Union Find
  • 설명: 이 코드는 무향 그래프의 연결 컴포넌트 수를 세기 위해 Union-Find(분리 집합) 자료구조를 사용하여 노드들을 병합하는 방식을 채택했습니다.

📊 시간/공간 복잡도 분석

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

피드백: 유니온-파인드 구조를 통해 각 엣지에 대해 병합 연산을 수행하며, 병합이 일어날 때마다 컴포넌트 수를 감소시킵니다. find와 union 연산은 거의 상수 시간에 수행됩니다. 공간은 부모 배열 저장에 O(n)입니다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
class Solution {
public:
int countComponents(int n, vector<vector<int>>& edges) {
int components = n;
vector<int> p(n, -1);
for (auto& e : edges)
{
if (uni(p, e[0], e[1])) // 이 엣지를 통해 합쳐지면
{
components--; // 컴포넌트 수는 하나 감소
}
}

return components;
}

// union-find
int find(vector<int>&p, int x)
{
if(p[x] < 0)
{
return x;
}

return p[x] = find(p, p[x]);
}

bool uni(vector<int>&p, int u, int v)
{
u = find(p, u);
v = find(p, v);

if (u == v)
{
return false;
}

if (p[v] < p[u])
{
swap(u, v);
}

if (p[u] == p[v])
{
p[u]--;
}

p[v] = u;
return true;
}
};
40 changes: 40 additions & 0 deletions remove-nth-node-from-end-of-list/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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Stack
  • 설명: 이 코드는 스택을 이용하여 리스트를 역순으로 탐색하고 특정 노드를 제거하는 방식으로 구현되어 있습니다. 스택을 활용한 후처리로 노드 위치를 찾는 것이 특징입니다.

📊 시간/공간 복잡도 분석

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

피드백: 리스트를 순회하며 스택에 노드를 저장하고, n번째 노드를 스택에서 pop하여 찾습니다. 이후 제거 작업을 수행하는데, 리스트 길이만큼 공간이 필요합니다. 시간은 리스트 길이와 동일합니다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
// 스택에 넣고 뒤집어서 n번째 노드 찾기
stack<ListNode*> s;
ListNode* cur = head;
while (cur != nullptr)
{
s.push(cur);
cur = cur->next;
}

for (int i = 0; i < n; ++i)
{
cur = s.top();
s.pop();
}

// 스택이 빌 때 까지 pop한 경우는 head를 제거하는 경우
if (s.empty())
{
return head->next;
}

// 그 외에는 prev가 존재
ListNode* prev = s.top();
prev->next = cur->next;
return head;
}
};
28 changes: 28 additions & 0 deletions same-tree/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.

🏷️ 알고리즘 패턴 분석

  • 패턴: DFS
  • 설명: 이 코드는 재귀 호출을 통해 두 트리의 노드를 순회하며 비교하는 방식으로, 깊이 우선 탐색(DFS) 패턴에 속합니다.

📊 시간/공간 복잡도 분석

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

피드백: 각 노드에 대해 재귀적으로 비교하며, 최악의 경우 트리 높이만큼 호출 스택이 쌓입니다. 모든 노드를 한 번씩 방문하므로 시간 복잡도는 O(n)입니다. 공간은 재귀 호출 스택에 따라 달라집니다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* 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:
bool isSameTree(TreeNode* p, TreeNode* q) {
if (p == nullptr || q == nullptr)
{
return p == q;
}

bool l = isSameTree(p->left, q->left);
bool r = isSameTree(p->right, q->right);
bool cur = p->val == q->val;

return l && r && cur;
}
};
116 changes: 116 additions & 0 deletions serialize-and-deserialize-binary-tree/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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Breadth-First Search
  • 설명: 이 코드는 레벨 순회 방식으로 트리를 직렬화하고 역직렬화하여 BFS 패턴을 사용합니다. 큐를 활용하여 노드들을 차례로 처리하는 구조입니다.

📊 시간/공간 복잡도 분석

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

풀이 1: Codec.serialize — Time: O(n) / Space: O(n)
복잡도
Time O(n)
Space O(n)

피드백: 모든 노드를 큐에 넣으며 직렬화하고, 마지막 null 값들을 제거합니다. 시간과 공간 모두 노드 수에 비례하며, 큐와 문자열 저장에 O(n) 공간이 필요합니다.

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

풀이 2: Codec.deserialize — Time: O(n) / Space: O(n)
복잡도
Time O(n)
Space O(n)

피드백: 문자열을 분리하여 큐에 저장하고, 순차적으로 노드를 생성하며 트리를 복원합니다. 모든 노드에 대해 한 번씩 처리하므로 시간 복잡도는 O(n), 공간은 O(n)입니다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/

// 그래야할 필요는 없다고 명시하지만, LeetCode 형식과 동일하게 직렬화/역직렬화 구현
class Codec {
public:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
vector<string> tokens;
queue<TreeNode*> q;
q.push(root);
while (!q.empty())
{
auto node = q.front();
q.pop();
if (node == nullptr)
{
tokens.push_back("null");
continue;
}

tokens.push_back(to_string(node->val));
q.push(node->left);
q.push(node->right);
}

// 굳이 지우지 않아도 역직렬화가 가능
// 하지만 LeetCode와 동일하게 구현하기 위한 처리
while (!tokens.empty() && tokens.back() == "null")
{
tokens.pop_back();
}

string s = "[";
for (int i = 0; i < tokens.size(); i++)
{
if (i)
{
s += ",";

}
s += tokens[i];
}

s += "]";
//cout << s;
return s;
}

// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
if (data == "[]")
{
return nullptr;
}

data = data.substr(1, data.size() - 2); // '[', ']' 제거
stringstream ss(data);
string token;

queue<string> v;
while (getline(ss, token, ','))
{
v.push(token);
}

TreeNode* root = new TreeNode(stoi(v.front()));
v.pop();
queue<TreeNode*> q;
q.push(root);
while (!q.empty())
{
auto cur = q.front();
q.pop();

// 만약 직렬화 과정에서 null을 제거하지 않았다면 이러한 확인은 필요없어짐
if (v.empty())
{
break;
}

string l = v.front();
v.pop();
if (l != "null")
{
cur->left = new TreeNode(stoi(l));
q.push(cur->left);
}

if (v.empty())
{
break;
}

string r = v.front();
v.pop();
if (r != "null")
{
cur->right = new TreeNode(stoi(r));
q.push(cur->right);
}
}
return root;
}
};

// Your Codec object will be instantiated and called as such:
// Codec ser, deser;
// TreeNode* ans = deser.deserialize(ser.serialize(root));
Loading