-
-
Notifications
You must be signed in to change notification settings - Fork 336
[hwi-middle] WEEK 12 solutions #2609
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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; | ||
| } | ||
| }; |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 유니온-파인드 구조를 통해 각 엣지에 대해 병합 연산을 수행하며, 병합이 일어날 때마다 컴포넌트 수를 감소시킵니다. 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; | ||
| } | ||
| }; |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 리스트를 순회하며 스택에 노드를 저장하고, 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; | ||
| } | ||
| }; |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 각 노드에 대해 재귀적으로 비교하며, 최악의 경우 트리 높이만큼 호출 스택이 쌓입니다. 모든 노드를 한 번씩 방문하므로 시간 복잡도는 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; | ||
| } | ||
| }; |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
풀이 1:
|
| 복잡도 | |
|---|---|
| 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)); |
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.
🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 입력 배열을 정렬하는 데 O(n log n)가 소요되고, 이후 한 번 순회하며 겹치는 구간을 세기 때문에 전체 시간 복잡도는 O(n log n)입니다. 공간은 정렬을 위한 제자리 정렬 또는 별도 배열 없이 인덱스만 사용하므로 O(1)입니다.
개선 제안: 현재 구현이 적절해 보입니다.