From 8909a3ebe3193c1b2f1734a3bf941d4d21371295 Mon Sep 17 00:00:00 2001 From: Yelingyuan Date: Thu, 16 Oct 2025 21:01:57 +0800 Subject: [PATCH] 20251016 --- ..._\350\251\271\345\271\277\350\266\205.cpp" | 39 ++++++++++ ..._\350\251\271\345\271\277\350\266\205.cpp" | 46 +++++++++++ ..._\350\251\271\345\271\277\350\266\205.cpp" | 78 +++++++++++++++++++ ..._\350\251\271\345\271\277\350\266\205.cpp" | 61 +++++++++++++++ ..._\350\251\271\345\271\277\350\266\205.cpp" | 54 +++++++++++++ 5 files changed, 278 insertions(+) create mode 100644 "topic04/submit/LC1080_\350\251\271\345\271\277\350\266\205.cpp" create mode 100644 "topic04/submit/LC1443_\350\251\271\345\271\277\350\266\205.cpp" create mode 100644 "topic04/submit/LC310_\350\251\271\345\271\277\350\266\205.cpp" create mode 100644 "topic04/submit/LC3249_\350\251\271\345\271\277\350\266\205.cpp" create mode 100644 "topic04/submit/LC687_\350\251\271\345\271\277\350\266\205.cpp" diff --git "a/topic04/submit/LC1080_\350\251\271\345\271\277\350\266\205.cpp" "b/topic04/submit/LC1080_\350\251\271\345\271\277\350\266\205.cpp" new file mode 100644 index 0000000..fcea59e --- /dev/null +++ "b/topic04/submit/LC1080_\350\251\271\345\271\277\350\266\205.cpp" @@ -0,0 +1,39 @@ +#include +using namespace std; + +//【题目】1080.根到叶路径上的不足节点 +//【难度】中等 +//【提交】https://leetcode.cn/problems/insufficient-nodes-in-root-to-leaf-paths/submissions/671193661/ +//【标签】树;深度优先搜索;二叉树 +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: + TreeNode* sufficientSubset(TreeNode* root, int limit) + { + limit -= root->val; + if (root->left == NULL && root->right == NULL) + { + return limit > 0 ? NULL : root; + } + if (root->left) root->left = sufficientSubset(root->left, limit); + if (root->right) root->right = sufficientSubset(root->right, limit); + return root->left || root->right ? root : nullptr; + } +}; + +/* +学习总结: +从根节点开始,每次递归将limit减去当前节点值,当到达叶子节点时,如果limit仍大于0说明路径和不足,返回nullptr进行删除 +对于非叶子节点,递归处理左右子树后,如果左右子树都被删除(都返回nullptr),则当前节点也需删除。 +这种自底向上的处理方式确保了只有所有根到叶路径和都小于limit的节点才会被删除,高效地完成了树的修剪 +*/ \ No newline at end of file diff --git "a/topic04/submit/LC1443_\350\251\271\345\271\277\350\266\205.cpp" "b/topic04/submit/LC1443_\350\251\271\345\271\277\350\266\205.cpp" new file mode 100644 index 0000000..7863fab --- /dev/null +++ "b/topic04/submit/LC1443_\350\251\271\345\271\277\350\266\205.cpp" @@ -0,0 +1,46 @@ +#include +#include +using namespace std; + +//【题目】1443.收集树上所有苹果的最少时间 +//【难度】中等 +//【提交】https://leetcode.cn/problems/minimum-time-to-collect-all-apples-in-a-tree/submissions/671188314/ +//【标签】树;深度优先搜索;广度优先搜索;哈希表 +class Solution +{ +public: + int dfs(int node, const vector>& tree, const vector& hasApple, vector& visited) + { + visited[node] = true; + int time = 0; + for (int child : tree[node]) + { + if (!visited[child]) + { + time += dfs(child, tree, hasApple, visited); + } + } + if (node != 0 && (hasApple[node] || time > 0)) + { + time += 2; + } + return time; + } + int minTime(int n, vector>& edges, vector& hasApple) + { + vector>tree(n); + for (auto& edge : edges) + { + tree[edge[0]].push_back(edge[1]); + tree[edge[1]].push_back(edge[0]); + } + vectorvisited(n, false); + return dfs(0, tree, hasApple, visited); + } +}; +/* +学习总结: +自底向上统计需要访问的路径:对于每个节点,累加所有子树所需的访问时间 +如果当前节点有苹果或其子树需要访问(time > 0),则需要在父节点往返该分支,额外增加2个单位时间 +这种方法巧妙地避免了不必要的路径遍历,只计算实际需要采集苹果的边 +*/ \ No newline at end of file diff --git "a/topic04/submit/LC310_\350\251\271\345\271\277\350\266\205.cpp" "b/topic04/submit/LC310_\350\251\271\345\271\277\350\266\205.cpp" new file mode 100644 index 0000000..b15040a --- /dev/null +++ "b/topic04/submit/LC310_\350\251\271\345\271\277\350\266\205.cpp" @@ -0,0 +1,78 @@ +#include +#include +#include +using namespace std; + +//【题目】力扣310..最小高度树 +//【难度】中等 +//【提交】https://leetcode.cn/problems/minimum-height-trees/submissions/671167458/ +//【标签】深度优先搜索;广度优先搜索;图;拓扑排序 +class Solution +{ +public: + int findLongdist(int u, vector& parent, vector>& adj) + { + int n = adj.size(); + queueq; + q.emplace(u); + vectorvisited(n); + visited[u] = true; + int node = -1; + while (!q.empty()) + { + int cur = q.front(); + q.pop(); + node = cur; + for (auto& v : adj[cur]) + { + if (!visited[v]) + { + visited[v] = true; + parent[v] = cur; + q.emplace(v); + } + } + } + return node; + } + vector findMinHeightTrees(int n, vector>& edges) + { + if (n == 1) + { + return { 0 }; + } + vector>adj(n); + for (auto& edge : edges) + { + adj[edge[0]].emplace_back(edge[1]); + adj[edge[1]].emplace_back(edge[0]); + } + + vectorparent(n, -1); + int x = findLongdist(0, parent, adj); + int y = findLongdist(x, parent, adj); + vectorpath; + parent[x] = -1; + while (y != -1) + { + path.emplace_back(y); + y = parent[y]; + } + int m = path.size(); + if (m % 2 == 0) + { + return { path[m / 2 - 1],path[m / 2] }; + } + else + { + return { path[m / 2] }; + } + } +}; + +/* +学习总结: +通过两次BFS找到树的最长路径(直径),然后取直径的中点(一个或两个节点)作为根节点,这样就能保证树的高度最小。 +其核心思想是,最小高度树的根节点必然位于树的最长路径的中点上。 +这种方法高效地利用了树的直径性质,将问题转化为寻找直径和中间节点,避免了暴力尝试所有根节点的高复杂度。 +*/ \ No newline at end of file diff --git "a/topic04/submit/LC3249_\350\251\271\345\271\277\350\266\205.cpp" "b/topic04/submit/LC3249_\350\251\271\345\271\277\350\266\205.cpp" new file mode 100644 index 0000000..39dffd8 --- /dev/null +++ "b/topic04/submit/LC3249_\350\251\271\345\271\277\350\266\205.cpp" @@ -0,0 +1,61 @@ +#include +#include +#include +using namespace std; + +//【题目】3249.统计好节点的数目 +//【难度】中等 +//【提交】https://leetcode.cn/problems/count-the-number-of-good-nodes/submissions/671179617/ +//【标签】树;深度优先搜索 +class Solution +{ +public: + int dfs(int node, int parent, vector>& adj, int& res) + { + bool val = true; + int treeSize = 0; + int subTreeSize = 0; + for (int child : adj[node]) + { + if (child != parent) + { + int size = dfs(child, node, adj, res); + if (subTreeSize == 0) + { + subTreeSize = size; + } + else if (size != subTreeSize) + { + val = false; + } + treeSize += size; + } + } + if (val) + { + res++; + } + return treeSize + 1; + } + int countGoodNodes(vector>& edges) + { + int n = edges.size() + 1; + int res = 0; + vector>adj(n); + for (auto& edge : edges) + { + adj[edge[0]].push_back(edge[1]); + adj[edge[1]].push_back(edge[0]); + } + + dfs(0, -1, adj, res); + return res; + } +}; + +/* +学习总结: +对于每个节点,递归计算所有子树的大小,如果所有子树包含的节点数都相同,则该节点是好节点 +算法的时间复杂度是O(n),因为它需要遍历所有节点和边一次。 +这种利用子树大小信息自底向上判断节点性质的方法,是处理树结构问题的典型模式,体现了分治思想和后序遍历在树问题中的巧妙应用。 +*/ \ No newline at end of file diff --git "a/topic04/submit/LC687_\350\251\271\345\271\277\350\266\205.cpp" "b/topic04/submit/LC687_\350\251\271\345\271\277\350\266\205.cpp" new file mode 100644 index 0000000..1f2361c --- /dev/null +++ "b/topic04/submit/LC687_\350\251\271\345\271\277\350\266\205.cpp" @@ -0,0 +1,54 @@ +#include +using namespace std; + +//【题目】力扣687.最长同值路径 +//【难度】中等 +//【提交】https://leetcode.cn/problems/longest-univalue-path/submissions/670632333/ +//【标签】树;深度优先搜索;二叉树 +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: + int res = 0; + int dfs(TreeNode* root) + { + if (root == NULL) + { + return 0; + } + int left = dfs(root->left), right = dfs(root->right); + int l = 0, r = 0; + if (root->left && root->left->val == root->val) + { + l = left + 1; + } + if (root->right && root->right->val == root->val) + { + r = right + 1; + } + res = max(res, l + r); + return max(l, r); + } + int longestUnivaluePath(TreeNode* root) + { + dfs(root); + return res; + } +}; + +/* +学习总结: +核心思路是通过深度优先搜索(DFS)递归遍历每个节点, +并计算以当前节点为起点的左右同值分支长度。 +关键在于:当子节点与当前节点值相同时,才能延续路径,否则长度重置为0。 +在递归过程中,同时更新全局最大值res,该值记录的是以当前节点为转折点的路径长度(即左右分支长度之和), +而返回值则是当前节点单侧的最大同值路径长度,供父节点使用。 +*/ \ No newline at end of file -- Gitee