[LeetCode] 1367. Linked List in Binary Tree 二叉树中的链表
Given a binary tree root
and a linked list with head
as the first node.
Return True if all the elements in the linked list starting from the head
correspond to some downward path connected in the binary tree otherwise return False.
In this context downward path means a path that starts at some node and goes downwards.
Example 1:
Input: head = [4,2,8], root = [1,4,4,null,2,2,null,1,null,6,8,null,null,null,null,1,3]
Output: true
Explanation: Nodes in blue form a subpath in the binary Tree.
Example 2:
Input: head = [1,4,2,6], root = [1,4,4,null,2,2,null,1,null,6,8,null,null,null,null,1,3]
Output: true
Example 3:
Input: head = [1,4,2,6,8], root = [1,4,4,null,2,2,null,1,null,6,8,null,null,null,null,1,3]
Output: false
Explanation: There is no path in the binary tree that contains all the elements of the linked list from head
.
Constraints:
- The number of nodes in the tree will be in the range
[1, 2500]
. - The number of nodes in the list will be in the range
[1, 100]
. 1 <= Node.val <= 100
for each node in the linked list and binary tree.
这道题说是给了一棵二叉树,还给了一个链表,问能不能在二叉树中找到一条路径 path,使得其正好是给定的结点链表,题目中例子中的图很好的解释了题意。这里的二叉树的路径并没有限制要从根节点开始,结束位置也不一定要是叶结点,那么理论上不同路径的数量就太多了。如果是想先求出二叉树的所有路径后,再来跟结点链表比较的话,一是太麻烦了,二是效率也不高。最好的办法还是在遍历的过程中就直接开始比较了,比较的方法就是当遇到和此时链表头结点相同的结点时,开始进行下一个结点的比较,由于路径可以去左子结点或者右子结点,所以左右子结点都要去尝试,这里用递归就非常合适了,只要左右子结点任意一个返回 true 了,那么就说明成功匹配了。如果当前的结点和链表头结点的值不相同的话,则分别再去左右子结点进行尝试,此时左右子结点还是跟原来的链表首结点去比较,因为之前没有匹配上,同样,只要左右子结点的递归任意一个返回 true 了,就说明成功匹配上了。根据这种思路写出的代码如下(注意这种下面这种解法是错误的,之后会分析):
// Wrong Solution
class Solution {
public:
bool isSubPath(ListNode* head, TreeNode* root) {
if (!head) return true;
if (!root) return false;
if (head->val == root->val) {
return isSubPath(head->next, root->left) || isSubPath(head->next, root->right);
}
return isSubPath(head, root->left) || isSubPath(head, root->right);
}
};
上面的解法虽然简洁,但实际上是错误的解法,这里可以举一个反例:head = [4,2,2], root = [4,2,null,4,null,2],二叉树的结构如下所示:
4
/
2
/
4
/
2
上面解法错误的原因是当 head 匹配完4和2之后,下一个2匹配不上了,因为二叉树中是4,但此时却没有从开头的4重新匹配,而是继续匹配链表中剩下的那个2,这样在跳过二叉树中的第二个4之后,最后一个2就匹配上了,整个就返回了 true。但实际上是错误的,给定的二叉树中并没有一个连续的 4->2->2 路径,相当于找到了类似于字符串中的子序列,而要求的却是子串。正确的做法实际上是对每个结点都当做起始点来匹配一下,这里用一个子函数 dfs 来匹配,匹配的方法就是看链表和二叉树的当前结点值是否相等,是的话再对左右子结点调用递归,只要任意一个返回 true 就行了。在主函数中,调用完 dfs 后,还要分别对左右子结点调用主函数的递归,这样才能保证把每个结点都当起始点来匹配,才能避免上面那个反例的情况,参见代码如下:
class Solution {
public:
bool isSubPath(ListNode* head, TreeNode* root) {
if (!head) return true;
if (!root) return false;
return dfs(head, root) || isSubPath(head, root->left) || isSubPath(head, root->right);
}
bool dfs(ListNode* head, TreeNode* root) {
if (!head) return true;
if (!root) return false;
return head->val == root->val && (dfs(head->next, root->left) || dfs(head->next, root->right));
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/1367
参考资料:
https://leetcode.com/problems/linked-list-in-binary-tree
https://leetcode.com/problems/linked-list-in-binary-tree/solutions/524821/c-simple-recursion/
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
2019-08-18 [LeetCode] 850. Rectangle Area II 矩形面积之二
2016-08-18 [LeetCode] Shuffle an Array 数组洗牌
2015-08-18 [LeetCode] Add Digits 加数字