1367. 二叉树中的链表:深度优先搜索的应用
在算法领域,二叉树和链表是两种基本的数据结构。今天,我们将探讨一个结合了这两种数据结构的问题:“1367. 二叉树中的链表”。这个问题在 LeetCode 上被标记为中等难度。
题目描述
题目链接:LeetCode 1367. 二叉树中的链表
给定一棵二叉树和一个链表,判断链表是否是二叉树中的一条路径,路径可以从二叉树的任意节点开始,且每个节点的值需要与链表中的对应节点值相等。
题目难度
- 难度:中等
题目标签
- 标签:树、深度优先搜索、链表、二叉树
题目限制
- 二叉树和链表中的每个节点的值都满足 1 <= node.val <= 100。
- 链表包含的节点数目在 1 到 100 之间。
- 二叉树包含的节点数目在 1 到 2500 之间。
解题思路
思路:深度优先搜索(DFS)
- 问题定义:
- 我们需要判断链表是否可以作为二叉树中的一条路径,这条路径可以从二叉树的任意节点开始。
- 核心算法:
- 使用深度优先搜索(DFS)遍历二叉树,对于树中的每个节点,检查从该节点开始的路径是否与链表匹配。
- 关键步骤:
- 从二叉树的根节点开始,递归地检查每个节点是否可以作为链表的起始点。
- 如果当前节点的值与链表头节点的值相等,则进一步检查其子树中是否存在与链表剩余部分匹配的路径。
代码实现
以下是 Java 代码实现:
/**
* 1367.二叉树中的链表
* @param head 链表
* @param root 二叉树
* @return 是否存在一条一直向下的路径
*/
public boolean isSubPath(ListNode head, TreeNode<Integer> root) {
if(head == null){
return true; // 如果链表为空,则认为匹配成功
}
if (root == null){ // 如果树为空,则匹配失败
return false;
}
// 检查当前节点开始是否匹配,或者左子树或右子树中是否存在匹配路径
return isSub(head, root) || isSubPath(head, root.left) || isSubPath(head, root.right);
}
/**
* 辅助函数,检查链表是否从当前树节点开始匹配
* @param head 链表的头节点
* @param root 当前树的节点
* @return 是否匹配
*/
public boolean isSub(ListNode head, TreeNode<Integer> root){
if(head == null){
return true; // 如果链表为空,则认为匹配成功
}
if(root == null){
return false; // 如果树为空,则匹配失败
}
if(head.val.equals(root.val)){ // 使用equals来比较Integer对象
return isSub(head.next, root.left) || isSub(head.next, root.right);
}
else return false;
}
代码解读
- 递归检查:
isSubPath方法递归地检查每个节点是否可以作为链表的起始点。 - 路径匹配:
isSub方法递归地检查从当前树节点开始的路径是否与链表匹配。
性能分析
- 时间复杂度:O(n * m),其中 n 是二叉树节点的数量,m 是链表节点的数量。最坏情况下,我们需要对每个树节点调用
isSub方法。 - 空间复杂度:O(h),其中 h 是二叉树的高度,这是由于递归调用栈的深度。
测试用例
你可以使用以下测试用例来验证代码的正确性:
// 测试用例1
ListNode head1 = new ListNode(4);
TreeNode<Integer> root1 = new TreeNode<>(4);
root1.left = new TreeNode<>(2);
root1.right = new TreeNode<>(6);
root1.left.left = new TreeNode<>(1);
root1.left.right = new TreeNode<>(3);
root1.right.left = new TreeNode<>(5);
root1.right.right = new TreeNode<>(7);
boolean result1 = isSubPath(head1, root1);
System.out.println(result1); // 输出: true
// 测试用例2
ListNode head2 = new ListNode(1);
TreeNode<Integer> root2 = new TreeNode<>(4);
root2.left = new TreeNode<>(2);
root2.right = new TreeNode<>(6);
root2.left.left = new TreeNode<>(1);
root2.left.right = new TreeNode<>(3);
root2.right.left = new TreeNode<>(5);
root2.right.right = new TreeNode<>(7);
boolean result2 = isSubPath(head2, root2);
System.out.println(result2); // 输出: true
// 测试用例3
ListNode head3 = new ListNode(1);
TreeNode<Integer> root3 = new TreeNode<>(4);
root3.left = new TreeNode<>(2);
root3.right = new TreeNode<>(6);
root3.left.left = new TreeNode<>(0);
root3.left.right = new TreeNode<>(3);
root3.right.left = new TreeNode<>(5);
root3.right.right = new TreeNode<>(7);
boolean result3 = isSubPath(head3, root3);
System.out.println(result3); // 输出: false
这些测试用例覆盖了链表是二叉树路径的一部分、链表不是二叉树路径的一部分以及链表只有一个节点的情况。
总结
通过深度优先搜索,我们可以有效地解决这个问题。在实现过程中,需要注意递归的终止条件和边界情况的处理。这个问题不仅考察了对二叉树和链表的理解,还考察了递归算法的设计能力。希望这篇技术博客能够帮助你更好地理解和解决“1367. 二叉树中的链表”这个问题。

3187

被折叠的 条评论
为什么被折叠?



