LeetCode 1367. 二叉树中的链表 Java实现

1367. 二叉树中的链表:深度优先搜索的应用

在算法领域,二叉树和链表是两种基本的数据结构。今天,我们将探讨一个结合了这两种数据结构的问题:“1367. 二叉树中的链表”。这个问题在 LeetCode 上被标记为中等难度。

题目描述

题目链接LeetCode 1367. 二叉树中的链表
给定一棵二叉树和一个链表,判断链表是否是二叉树中的一条路径,路径可以从二叉树的任意节点开始,且每个节点的值需要与链表中的对应节点值相等。

题目难度

  • 难度:中等

题目标签

  • 标签:树、深度优先搜索、链表、二叉树

题目限制

  • 二叉树和链表中的每个节点的值都满足 1 <= node.val <= 100。
  • 链表包含的节点数目在 1 到 100 之间。
  • 二叉树包含的节点数目在 1 到 2500 之间。

解题思路

思路:深度优先搜索(DFS)

  1. 问题定义
    • 我们需要判断链表是否可以作为二叉树中的一条路径,这条路径可以从二叉树的任意节点开始。
  2. 核心算法
    • 使用深度优先搜索(DFS)遍历二叉树,对于树中的每个节点,检查从该节点开始的路径是否与链表匹配。
  3. 关键步骤
    • 从二叉树的根节点开始,递归地检查每个节点是否可以作为链表的起始点。
    • 如果当前节点的值与链表头节点的值相等,则进一步检查其子树中是否存在与链表剩余部分匹配的路径。

代码实现

以下是 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. 二叉树中的链表”这个问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值