From a648b9711e4c9711f4e6eb7db27736eb16f2cc63 Mon Sep 17 00:00:00 2001 From: yeoju Date: Thu, 12 Jun 2025 18:14:29 +0900 Subject: [PATCH 1/2] Feat: #235 #247 #262 #278 solved --- graph-valid-tree/crumbs22.cpp | 57 +++++++++++++++++++++++++++++++++++ merge-intervals/crumbs22.cpp | 31 +++++++++++++++++++ missing-number/crumbs22.cpp | 18 +++++++++++ reorder-list/crumbs22.cpp | 38 +++++++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 graph-valid-tree/crumbs22.cpp create mode 100644 merge-intervals/crumbs22.cpp create mode 100644 missing-number/crumbs22.cpp create mode 100644 reorder-list/crumbs22.cpp diff --git a/graph-valid-tree/crumbs22.cpp b/graph-valid-tree/crumbs22.cpp new file mode 100644 index 000000000..d947c9d9a --- /dev/null +++ b/graph-valid-tree/crumbs22.cpp @@ -0,0 +1,57 @@ +/* + valid tree 조건 + 1. 사이클이 없어야한다 + 2. 모든 각 노드들은 적어도 하나의 다른 노드와 연결되어 있어야 한다 + + 인접 리스트 형식으로 무방향 간선 정보를 저장하고, + dfs 재귀 탐색으로 방문 체크 후 자식 노드를 재귀적으로 방문하면서 사이클 판단 +*/ + +class Solution { + public: + /** + * @param n: An integer + * @param edges: a list of undirected edges + * @return: true if it's a valid tree, or false + */ + bool validTree(int n, vector> &edges) { + if (edges.size() != n - 1) + return false; + + // 인접한 노드들을 요소로 가지는 adj 배열 생성 + vector> adj(n); + + for (auto edge : edges) { + int u = edge[0]; + int v = edge[1]; + adj[u].push_back(v); + adj[v].push_back(u); + } + + // 방문 기록 + vector visited(n, false); + if (!dfs(0, -1, adj, visited)) + return false; + + // 모든 노드가 방문되었는지 (연결되는지) 확인 + for (bool v : visited) { + if (!v) + return false; + } + return true; + } + + bool dfs(int node, int parent, vector>& adj, vector visited) { + visited[node] = true; + + for (int neighbor : adj[node]) { + if (neighbor == parent) + continue ; // 바로 이전 노드는 무시(왕복 방지) + if (visited[neighbor]) + return false; // 사이클 탐지 + if (!dfs(neighbor, node, adj, visited)) + return false; + } + return true; + } + }; diff --git a/merge-intervals/crumbs22.cpp b/merge-intervals/crumbs22.cpp new file mode 100644 index 000000000..437593263 --- /dev/null +++ b/merge-intervals/crumbs22.cpp @@ -0,0 +1,31 @@ +/* + 이전 interval의 끝점과 현재 interval의 시작점을 비교해서 구간 겹침을 판단 + 구간이 겹친다면 prev를 갱신 + 구간이 겹치지 않을 때 반환 벡터 res에 prev 추가하고 기준점 갱신 + intervals를 한 번 반복하므로 시간복잡도 O(n)과 처음 정렬에 O(nlogn) 소요되므로 + 최종 시간 복잡도는 O(nlogn) + 추가적으로 사용하는 공간은 반환배열밖에 없으므로 O(1)의 공간복잡도 가짐 +*/ + +class Solution { + public: + vector> merge(vector>& intervals) { + vector> res; + + sort(intervals.begin(), intervals.end()); + + vector prev = intervals[0]; + for (auto i : intervals) { + if (i[0] <= prev[1]) { + prev[0] = min(prev[0], i[0]); + prev[1] = max(prev[1], i[1]); + } else { + res.push_back(prev); // 이전 병합 구간 저장 + prev = i; // 새로운 기준 시작 + } + } + res.push_back(prev); + + return res; + } + }; diff --git a/missing-number/crumbs22.cpp b/missing-number/crumbs22.cpp new file mode 100644 index 000000000..006b21957 --- /dev/null +++ b/missing-number/crumbs22.cpp @@ -0,0 +1,18 @@ +/* + 풀이방법: 0부터 n까지의 합은 n*(n + 1)/2 이라는 수학적 사실을 활용, + nums 배열을 한 번만 순회하므로 시간복잡도는 O(n) + 추가적으로 사용하는 공간 없으므로 공간복잡도는 O(1)이다. +*/ + +class Solution { +public: + int missingNumber(vector& nums) { + int n = nums.size(); + int res = n * (n + 1) / 2; + + for (int num : nums) { + res -= num; + } + return (res); + } +}; diff --git a/reorder-list/crumbs22.cpp b/reorder-list/crumbs22.cpp new file mode 100644 index 000000000..c0fc8256a --- /dev/null +++ b/reorder-list/crumbs22.cpp @@ -0,0 +1,38 @@ +/* + 큐와 스택구조를 활용해 노드의 주소를 각각 저장해놓고 + 큐에서 한 번, 스택에서 한 번 요소를 빼와서 재정렬한다 + 링크드리스트를 한 번 순회하면서 push하고 같은 길이만큼 한 번 더 순회하므로 O(2n)의 시간복잡도와 + 노드 길이만큼의 자료구조를 2개 더 사용하므로 O(2n)의 공간복잡도를 사용 +*/ + +class Solution { +public: + void reorderList(ListNode* head) { + ListNode* tmp = head; + queue q; + stack s; + + while (tmp) { + s.push(tmp); + q.push(tmp); + tmp = tmp->next; + } + + // 큐 - 스택 - 큐 - 스택 ... + // 큐는 앞에서 1/2을, 스택은 뒤에서 1/2을 반복하며 요소 추출 + int len = q.size(); + tmp = q.front(); + q.pop(); + + for (int i = 0; i < len / 2; i++) { + tmp->next = s.top(); + s.pop(); + tmp = tmp->next; + tmp->next = q.front(); + q.pop(); + tmp = tmp->next; + } + tmp->next = nullptr; + + } +}; From 3f6e23ad43196624e944a66ce36178ec1c9ce089 Mon Sep 17 00:00:00 2001 From: yeoju Date: Sat, 14 Jun 2025 17:05:11 +0900 Subject: [PATCH 2/2] Feat: #287 --- binary-tree-maximum-path-sum/crumbs22.cpp | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 binary-tree-maximum-path-sum/crumbs22.cpp diff --git a/binary-tree-maximum-path-sum/crumbs22.cpp b/binary-tree-maximum-path-sum/crumbs22.cpp new file mode 100644 index 000000000..2195468c1 --- /dev/null +++ b/binary-tree-maximum-path-sum/crumbs22.cpp @@ -0,0 +1,27 @@ +class Solution { + public: + int maxPathSum(TreeNode* root) { + int res = INT_MIN; + + dfs(root, res); + return res; + } + + int dfs(TreeNode* root, int& res) { + if (!root) + return 0; + + // 좌측 부분트리, 우측 부분트리를 각각 계산할 때 dfs의 '반환값'을 활용 + // 음수값이 나올 경우는 0으로 대체함 + int left = max(0, dfs(root->left, res)); + int right = max(0, dfs(root->right, res)); + + // 최종 반환할 값 업데이트 + // 좌측 트리, 우측 트리, 루트 노드를 모두 통과하는 경로가 현재까지 최댓값인지 비교해서 갱신 + res = max(res, root->val + left + right); + + // 상위 노드로 전달되는 값은 root의 값을 포함하는 경로의 값이다 + // 따라서 좌측 트리 혹은 우측 트리 중 하나의 경로만을 선택해서 통과할 수 있다 + return root->val + max(left, right); + } + };