题目
题目来源:力扣(LeetCode)
给你一棵以 root 为根的二叉树和一个 head 为第一个节点的链表。
如果在二叉树中,存在一条一直向下的路径,且每个点的数值恰好一一对应以 head 为首的链表中每个节点的值,那么请你返回 True ,否则返回 False 。
一直向下的路径的意思是:从树中某个节点开始,一直连续向下的路径。
示例 1:
输入:head = [4,2,8], root = [1,4,4,null,2,2,null,1,null,6,8,null,null,null,null,1,3]
输出:true
解释:树中蓝色的节点构成了与链表对应的子路径。
示例 2:
输入:head = [1,4,2,6], root = [1,4,4,null,2,2,null,1,null,6,8,null,null,null,null,1,3]
输出:true
示例 3:
输入:head = [1,4,2,6,8], root = [1,4,4,null,2,2,null,1,null,6,8,null,null,null,null,1,3]
输出:false
解释:二叉树中不存在一一对应链表的路径。
思路分析
主要思想
遍历每一个节点,判断是否存在以当前节点为起点的路径,其路径上每一节点都与给定的链表节点值一一对应。
二叉树中的每个节点为起点往下的路径是否有与链表相匹配的路径。为了判断是否匹配我们设计一个递归函数 judge(root, head) ,其中 表示当前匹配到的二叉树节点,head 表示当前匹配到的链表节点,整个函数返回布尔值表示是否有一条该节点往下的路径与 head 节点开始的链表匹配,如匹配返回 true,否则返回 false ,一共有四种情况:
- 链表已经全部匹配完,匹配成功,返回 true
- 二叉树访问到了空节点,匹配失败,返回 false
- 当前匹配的二叉树上节点的值与链表节点的值不相等,匹配失败,false
- 前三种情况都不满足,说明匹配成功了一部分,我们需要继续递归匹配,所以先调用函数judge(root.left, head.next) ,其中root.left 表示该节点的左儿子节点,head.next 表示下一个链表节点,如果返回的结果是 false,说明没有找到相匹配的路径,需要继续在右子树中匹配,继续递归调用函数 judge(root.right, head.next) 去找是否有相匹配的路径,其中root.right 表示该节点的右儿子节点, head.next 表示下一个链表节点。
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {ListNode} head
* @param {TreeNode} root
* @return {boolean}
*/
var isSubPath = function (head, root) {
// 在一颗树上面找一条空链表肯定能找到
if (head == null) return true;
if (root == null) return false;
// 从root开始捋着比较,是否能找到连续的符合题意的链表
if (root.val == head.val && judge(root, head)) return true;
//否则就递归地比较 用树中的每一个节点依次比较链表中的头节点
return isSubPath(head, root.left) || isSubPath(head, root.right);
};
var judge = function (root, head) {
// 检查到了链表的末尾,说明找到了一个完整匹配的序列,返回 true
if (head == null) return true;
// 链表还未遍历到末尾,树已经遍历到叶子节点,所以不能完全匹配,返回false
if (root == null) return false;
// 如果树中的节点已经不匹配了,那么直接返回false
if (root.val != head.val) return false;
// 这里证明root节点的值,等于head节点的值
// 接着向下比较左子树,向下比较右子树
// 在左右子树中 找到任意一条路径 能够匹配到 链表剩余部分的节点 证明能够匹配成功
return judge(root.left, head.next) || judge(root.right, head.next);
}