【力扣4行代码解题】572另一棵树的子树 | C++

本文介绍了如何使用递归和深度优先搜索在二叉树中查找是否存在与给定子树(subRoot)结构和节点值相同的子树。通过compare和isSubtree函数实现判断,isSubtree函数利用递归遍历root的子节点进行比较。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

总结:本题可以使用递归和迭代法,但平时还是建议两种方法都掌握,感兴趣的同学可以看看原题。

1 题目

力扣链接 ==> 572.另一棵树的子树
给你两棵二叉树 rootsubRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

2 知识点

二叉树、深度优先搜索

在这里插入图片描述

3 代码及解释

class Solution {
public:
    bool compare(TreeNode* p, TreeNode* q) {
        if (!p || !q) return p == q;
        return p->val == q->val && compare(p->left, q->left) && compare(p->right, q->right);
    }

    bool isSubtree(TreeNode* root, TreeNode* subRoot) {
        if (!root) return false;
        return compare(root, subRoot) || isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
    }
};

compare函数 的作用是对比两棵树是否相同:
第一行:处理两棵树存在某一为空或者二者都为空的情况(都为空自然是true);
第二行:既然排除了两棵树存在空树的情况,那么剩下的一种就是两棵树都不为空,这个时候直接比较值,值相同则说明根节点一样,继续比较子节点,这里使用递归比较。

isSubtree函数 的作用是递归被查树的各个节点:
第一行:如果节点为空,那也就没有和subRoot比较的必要了;
第二行:比较两棵树的各个节点,如果不一致,就去左右子树继续比较。
由于是(|| )或的关系,所以只要有任意一个子树满足条件都结束执行。

能力有限,不当之处,欢迎批评指正!

以下是针对力扣LeetCode)上“两数相加”问题的完整 C++ 解决方案,包含详细注释和优化建议: ### 力扣题目链接 [2. 两数相加](https://leetcode-cn.com/problems/add-two-numbers/) ### 解决方案代码 ```cpp /** * 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* addTwoNumbers(ListNode* l1, ListNode* l2) { ListNode dummy(0); // 哑节点简化操作 ListNode* current = &dummy; int carry = 0; // 进位初始化为0 // 遍历两个链表,直到都到达末尾且没有进位 while (l1 != nullptr || l2 != nullptr || carry != 0) { int sum = carry; // 初始化为上一次的进位 // 处理l1当前节点 if (l1 != nullptr) { sum += l1->val; l1 = l1->next; } // 处理l2当前节点 if (l2 != nullptr) { sum += l2->val; l2 = l2->next; } // 计算当前位值和新的进位 carry = sum / 10; current->next = new ListNode(sum % 10); current = current->next; } return dummy.next; // 返回哑节点的下一个节点 } }; ``` ### 代码优化点 1. **内存管理**: - 使用 `new` 动态分配节点,但力扣测试用例会自动释放内存 - 实际项目中建议使用智能指针(如 `std::unique_ptr`) 2. **边界处理**: - 循环条件 `|| carry != 0` 确保处理最后的进位(如 5 + 5 = 10 的情况) 3. **性能优化**: - 时间复杂度 O(max(m,n)),空间复杂度 O(max(m,n)) - 无需额外空间存储数字,直接在链表上操作 ### 测试用例示例 ```cpp // 在main函数中测试(力扣提交时不需要) #include <iostream> using namespace std; void printList(ListNode* head) { while (head) { cout << head->val << " -> "; head = head->next; } cout << "nullptr" << endl; } int main() { Solution sol; // 测试用例1: 342 + 465 = 807 ListNode* l1 = new ListNode(2, new ListNode(4, new ListNode(3))); ListNode* l2 = new ListNode(5, new ListNode(6, new ListNode(4))); ListNode* res = sol.addTwoNumbers(l1, l2); printList(res); // 输出: 7 -> 0 -> 8 -> nullptr // 测试用例2: 0 + 0 = 0 ListNode* l3 = new ListNode(0); ListNode* l4 = new ListNode(0); ListNode* res2 = sol.addTwoNumbers(l3, l4); printList(res2); // 输出: 0 -> nullptr // 测试用例3: 9999999 + 9999 = 10009998 ListNode* l5 = new ListNode(9, new ListNode(9, new ListNode(9, new ListNode(9, new ListNode(9, new ListNode(9, new ListNode(9))))))); ListNode* l6 = new ListNode(9, new ListNode(9, new ListNode(9, new ListNode(9)))); ListNode* res3 = sol.addTwoNumbers(l5, l6); printList(res3); // 输出: 8 -> 9 -> 9 -> 9 -> 0 -> 0 -> 0 -> 1 -> nullptr return 0; } ``` ### 常见问题解答 1. **为什么使用哑节点?** - 简化链表操作,避免单独处理头节点为空的情况 - 最后返回 `dummy.next` 即可得到正确结果 2. **如何处理不同长度的链表?** - 循环条件包含 `l1 || l2`,当某个链表提前结束时自动补0(通过 `sum += 0` 实现) 3. **如何处理最后的进位?** - 循环条件包含 `carry != 0`,确保像 5 + 5 = 10 这样的进位被处理 4. **与数组实现的区别?** - 链表实现更节省空间(不需要预先分配最大长度) - 数组实现需要先计算总长度,可能浪费空间 ### 提交注意事项 1. 在力扣提交时只需提交 `Solution` 类 2. 不要包含 `main()` 函数和测试代码 3. 确保代码通过所有测试用例(包括边界情况) ### 复杂度分析 - **时间复杂度**:O(max(m,n)),其中 m 和 n 分别是 l1 和 l2 的长度 - **空间复杂度**:O(max(m,n)),结果链表的长度最多为 max(m,n)+1 这个解决方案完全符合力扣的题目要求,能够高效处理所有测试用例,包括大数相加和边界情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿知

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值