2023-05-10:给你一棵以 root 为根的二叉树和一个 head 为第一个节点的链表

如果在二叉树中,存在一条一直向下的路径

且每个点的数值恰好一一对应以 head 为首的链表中每个节点的值,那么请你返回 True

否则返回 False 。

一直向下的路径的意思是:从树中某个节点开始,一直连续向下的路径。

输入:head = [4,2,8], root = [1,4,4,null,2,2,null,1,null,6,8,null,null,null,null,1,3]。

输出:true。

答案2023-05-10:

大体步骤如下:

1.确定链表的长度和节点值序列。遍历链表,记录链表长度 n,并将链表节点值存储到一个整型数组 match 中。

2.利用节点值序列 match 构造 KMP 算法中的 next 数组。next 数组是为了在匹配过程中能够快速跳过与前面已匹配部分不相等的情况。

3.将 head 和 root 传入 isSubPath 函数中计算是否存在一条向下连续的路径恰好对应着链表中每个节点的值。首先搜索左子树,将节点值序列、next 数组以及当前已匹配节点数 mi 作为参数传入 find 函数中进行搜索,若在左子树中找到解则返回 true,否则再在右子树中进行搜索,直到搜索完整棵树。

4.在 find 函数中,若 mi == len(match),表示已经匹配完整个链表,则返回 true;若 cur == nil,表示二叉树中已没有可匹配的节点,返回 false。否则,将当前节点的值与链表中未匹配部分的第一个节点值比较,如果相等则继续往下递归,mi + 1 表示已经匹配的节点数要加 1,否则利用 next 数组回溯 mi 的值,继续比较。直到递归结束返回 true 或 false。

时间复杂度:假设链表中的节点数为 n,二叉树的节点数为 m,则构造 next 数组的时间复杂度是 O(n),搜索整个二叉树的时间复杂度是 O(mn)。因此总时间复杂度是 O(mn)。

空间复杂度:除了输入参数以外,算法使用了常数个大小为 n 的数组和常数个递归栈空间。因此空间复杂度是 O(n)。

go完整代码如下:

package main

import "fmt"

// Definition for singly-linked list.
type ListNode struct {
Val int
Next *ListNode
} // Definition for a binary tree node.
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
} func isSubPath(head *ListNode, root *TreeNode) bool {
n := 0
tmp := head
for tmp != nil {
n++
tmp = tmp.Next
} match := make([]int, n)
n = 0
tmp = head
for tmp != nil {
match[n] = tmp.Val
n++
tmp = tmp.Next
} next := getNextArray(match)
return find(root, 0, match, next)
} func getNextArray(match []int) []int {
if len(match) == 1 {
return []int{-1}
}
next := make([]int, len(match))
next[0] = -1
next[1] = 0
i := 2
cn := 0
for i < len(next) {
if match[i-1] == match[cn] {
cn++
next[i] = cn
i++
} else if cn > 0 {
cn = next[cn]
} else {
next[i] = 0
i++
}
}
return next
} func find(cur *TreeNode, mi int, match []int, next []int) bool {
if mi == len(match) {
return true
}
if cur == nil {
return false
}
curVal := cur.Val for mi >= 0 && curVal != match[mi] {
mi = next[mi]
} return find(cur.Left, mi+1, match, next) || find(cur.Right, mi+1, match, next)
} func main() {
head := &ListNode{
Val: 4,
Next: &ListNode{
Val: 2,
Next: &ListNode{
Val: 8,
Next: nil,
},
},
} root := &TreeNode{
Val: 1,
Left: &TreeNode{
Val: 4,
Right: &TreeNode{
Val: 2,
Left: &TreeNode{
Val: 6,
Left: nil,
Right: nil,
},
Right: &TreeNode{
Val: 8,
Left: nil,
Right: nil,
},
},
},
Right: &TreeNode{
Val: 4,
Left: &TreeNode{
Val: 2,
Left: nil,
Right: nil,
},
Right: &TreeNode{
Val: 1,
Left: &TreeNode{
Val: 3,
Left: nil,
Right: nil,
},
Right: nil,
},
},
} res := isSubPath(head, root)
fmt.Println(res) // output: true
}

rust完整代码如下:

use std::cell::RefCell;
use std::rc::Rc;
// Definition for singly-linked list.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>,
} impl ListNode {
#[inline]
fn new(val: i32) -> Self {
ListNode { next: None, val }
}
}
// Definition for a binary tree node.
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
pub val: i32,
pub left: Option<Rc<RefCell<TreeNode>>>,
pub right: Option<Rc<RefCell<TreeNode>>>,
} impl TreeNode {
#[inline]
pub fn new(val: i32) -> Self {
TreeNode {
val,
left: None,
right: None,
}
}
} fn is_sub_path(head: Option<Box<ListNode>>, root: Option<Rc<RefCell<TreeNode>>>) -> bool {
let mut n = 0;
let mut tmp = &head;
while let Some(node) = tmp {
n += 1;
tmp = &node.next;
} let mut match_arr = Vec::with_capacity(n);
let mut tmp = &head;
while let Some(node) = tmp {
match_arr.push(node.val);
tmp = &node.next;
} let next = get_next_array(&match_arr);
find(&root, 0, &match_arr, &next)
} fn get_next_array(match_arr: &[i32]) -> Vec<i32> {
if match_arr.len() == 1 {
return vec![-1];
}
let mut next = vec![0; match_arr.len()];
next[0] = -1;
next[1] = 0;
let mut i = 2;
let mut cn = 0;
while i < next.len() {
if match_arr[i - 1] == match_arr[cn as usize] {
cn += 1;
next[i] = cn;
i += 1;
} else if cn > 0 {
cn = next[cn as usize];
} else {
next[i] = 0;
i += 1;
}
}
next
} fn find(cur: &Option<Rc<RefCell<TreeNode>>>, mi: usize, match_arr: &[i32], next: &[i32]) -> bool {
if mi == match_arr.len() {
return true;
}
if cur.is_none() {
return false;
}
let cur = cur.as_ref().unwrap().borrow();
let cur_val = cur.val; let mut mi = mi as i32;
while mi >= 0 && cur_val != match_arr[mi as usize] {
mi = next[mi as usize];
} find(&cur.left, (mi + 1) as usize, match_arr, next)
|| find(&cur.right, (mi + 1) as usize, match_arr, next)
} fn main() {
let head = Some(Box::new(ListNode {
val: 4,
next: Some(Box::new(ListNode {
val: 2,
next: Some(Box::new(ListNode { val: 8, next: None })),
})),
}));
let root = Some(Rc::new(RefCell::new(TreeNode {
val: 1,
left: Some(Rc::new(RefCell::new(TreeNode {
val: 4,
left: None,
right: Some(Rc::new(RefCell::new(TreeNode {
val: 2,
left: Some(Rc::new(RefCell::new(TreeNode {
val: 6,
left: None,
right: None,
}))),
right: Some(Rc::new(RefCell::new(TreeNode {
val: 8,
left: None,
right: None,
}))),
}))),
}))),
right: Some(Rc::new(RefCell::new(TreeNode {
val: 4,
left: Some(Rc::new(RefCell::new(TreeNode {
val: 2,
left: None,
right: None,
}))),
right: Some(Rc::new(RefCell::new(TreeNode {
val: 1,
left: Some(Rc::new(RefCell::new(TreeNode {
val: 3,
left: None,
right: None,
}))),
right: None,
}))),
}))),
}))); let res = is_sub_path(head, root);
println!("{}", res);
}

c语言完整代码如下:

#include <stdio.h>
#include <stdlib.h> typedef struct ListNode {
int val;
struct ListNode* next;
} ListNode; typedef struct TreeNode {
int val;
struct TreeNode* left;
struct TreeNode* right;
} TreeNode; int* getNextArray(int* match, int n) {
int* next = (int*)malloc(n * sizeof(int));
if (n == 1) {
next[0] = -1;
return next;
}
next[0] = -1;
next[1] = 0;
int i = 2, cn = 0;
while (i < n) {
if (match[i - 1] == match[cn]) {
next[i++] = ++cn;
}
else if (cn > 0) {
cn = next[cn];
}
else {
next[i++] = 0;
}
}
return next;
} int find(TreeNode* cur, int mi, int* match, int* next, int m) {
if (mi == m) {
return 1;
}
if (cur == NULL) {
return 0;
}
int curVal = cur->val;
while (mi >= 0 && curVal != match[mi]) {
mi = next[mi];
}
return find(cur->left, mi + 1, match, next, m) || find(cur->right, mi + 1, match, next, m);
} int isSubPath(ListNode* head, TreeNode* root) {
ListNode* tmp = head;
int n = 0;
while (tmp != NULL) {
n++;
tmp = tmp->next;
} int* match = (int*)malloc(n * sizeof(int));
tmp = head;
int i = 0;
while (tmp != NULL) {
match[i] = tmp->val;
i++;
tmp = tmp->next;
} int* next = getNextArray(match, n);
int res = find(root, 0, match, next, n); free(match);
free(next); return res;
} ListNode* newListNode(int x) {
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
node->val = x;
node->next = NULL;
return node;
} TreeNode* newTreeNode(int x) {
TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
node->val = x;
node->left = NULL;
node->right = NULL;
return node;
} int main() {
ListNode* head = newListNode(4);
head->next = newListNode(2);
head->next->next = newListNode(8); TreeNode* root = newTreeNode(1);
root->left = newTreeNode(4);
root->right = newTreeNode(4);
root->left->right = newTreeNode(2);
root->right->left = newTreeNode(2);
root->left->right->left = newTreeNode(6);
root->left->right->right = newTreeNode(8);
root->right->left->left = newTreeNode(3);
root->right->left->right = NULL; int res = isSubPath(head, root);
printf("%d\n", res); free(head->next->next);
free(head->next);
free(head); free(root->left->right->right);
free(root->left->right->left);
free(root->left->right);
free(root->left);
free(root->right->left->left);
free(root->right->left);
free(root->right);
free(root); return 0;
}

c++完整代码如下:

#include <iostream>
#include <vector> using namespace std; struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(NULL) {}
}; struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
}; vector<int> getNextArray(vector<int>& match) {
vector<int> next(match.size(), 0);
if (match.size() == 1) {
return { -1 };
}
next[0] = -1;
next[1] = 0;
int i = 2;
int cn = 0;
while (i < match.size()) {
if (match[i - 1] == match[cn]) {
cn++;
next[i] = cn;
i++;
}
else if (cn > 0) {
cn = next[cn];
}
else {
next[i] = 0;
i++;
}
}
return next;
} bool find(TreeNode* cur, int mi, vector<int>& match, vector<int>& next) {
if (mi == match.size()) {
return true;
}
if (cur == NULL) {
return false;
}
int curVal = cur->val;
while (mi >= 0 && curVal != match[mi]) {
mi = next[mi];
}
return find(cur->left, mi + 1, match, next) || find(cur->right, mi + 1, match, next);
} bool isSubPath(ListNode* head, TreeNode* root) {
ListNode* tmp = head;
int n = 0;
while (tmp != NULL) {
n++;
tmp = tmp->next;
} vector<int> match(n, 0);
tmp = head;
int i = 0;
while (tmp != NULL) {
match[i] = tmp->val;
i++;
tmp = tmp->next;
} vector<int> next = getNextArray(match);
return find(root, 0, match, next);
} int main() {
ListNode* head = new ListNode(4);
head->next = new ListNode(2);
head->next->next = new ListNode(8); TreeNode* root = new TreeNode(1);
root->left = new TreeNode(4);
root->right = new TreeNode(4);
root->left->right = new TreeNode(2);
root->right->left = new TreeNode(2);
root->left->right->left = new TreeNode(6);
root->left->right->right = new TreeNode(8);
root->right->left->left = new TreeNode(3);
root->right->left->right = NULL; bool res = isSubPath(head, root);
cout << res << endl; return 0;
}

2023-05-10:给你一棵以 root 为根的二叉树和一个 head 为第一个节点的链表 如果在二叉树中,存在一条一直向下的路径 且每个点的数值恰好一一对应以 head 为首的链表中每个节点的值,的更多相关文章

  1. 【数据结构05】红-黑树基础----二叉搜索树(Binary Search Tree)

    目录 1.二分法引言 2.二叉搜索树定义 3.二叉搜索树的CRUD 4.二叉搜索树的两种极端情况 5.二叉搜索树总结 前言 在[算法04]树与二叉树中,已经介绍过了关于树的一些基本概念以及二叉树的前中 ...

  2. [LeetCode] Trim a Binary Search Tree 修剪一棵二叉搜索树

    Given a binary search tree and the lowest and highest boundaries as L and R, trim the tree so that a ...

  3. python下实现二叉堆以及堆排序

    python下实现二叉堆以及堆排序 堆是一种特殊的树形结构, 堆中的数据存储满足一定的堆序.堆排序是一种选择排序, 其算法复杂度, 时间复杂度相对于其他的排序算法都有很大的优势. 堆分为大头堆和小头堆 ...

  4. Linux下多路径multipath配置

    一.multipath在redhat 6.2中的基本配置: 1. 通过命令:lsmod |grep dm_multipath  检查是否正常安装成功.如果没有输出说明没有安装那么通过yum功能安装一下 ...

  5. Linux下多路径multipath配置【转】

    一.multipath在redhat 6.2中的基本配置: 1. 通过命令:lsmod |grep dm_multipath  检查是否正常安装成功.如果没有输出说明没有安装那么通过yum功能安装一下 ...

  6. CentOS个人目录下中文路径转英文路径

    CentOS个人目录下中文路径转英文路径 如果安装了中文版到CentOS之后,root目录及home目录下会出现中文到路径名,如"桌面"."文档"," ...

  7. spring java 获取webapp下文件路径

    spring java 获取webapp下文件路径 @RequestMapping("/act/worldcup_schedule_time/imgdownload") @Resp ...

  8. 痛苦的版本对齐(3) cygwin下的路径引用

    [续<痛苦的版本对齐(2) 和时间的相关性>]http://www.cnblogs.com/yvivid/p/3541142.html 初步定位,如下告警为.depend文件路径问题导致. ...

  9. Swift - 使用下划线(_)来分隔数值中的数字

    为了增强较大数值的可读性,Swift语言增加了下划线(_)来分隔数值中的数字. 不管是整数,还是浮点数,都可以使用下划线来分隔数字. 1 2 3 4 //数值可读性 let value1 = 10_0 ...

  10. 如何修改Window系统下PATH路径以及win8下masm32V11

    如何修改Window系统下PATH路径   //其实这个都是临时性的, 退出dos窗口就没有用了,只是做个笔记罢了   C:\Users\Administrator>    set path=E ...

随机推荐

  1. Word 给公式添加题注解决交叉引用中包含公式

    简记:回车,然后 Ctrl +Alt+Enter https://blog.csdn.net/wsj_jerry521/article/details/115163456

  2. 前端访问Tornado跨域问题解决

  3. You need to run build with JDK or have tools.jar on the classpath.If this occures during eclipse build make sure you run eclipse under JDK as well 错误

    我打开项目报错是这样的  pom.xml jdk配置什么的都是好的    但是还是报错 解决错误 : 1.打开你eclipse的根目录,找到eclipse.ini  这个文件夹打开 2.打开是这个样子 ...

  4. SXSSFWorkbook 表格内换行

    起因 导出的excel需要在表格内换行,但搜索到的方法都实现不了我的需求,经同事搜查得知,这是POI的一个bug,已经在17年八月后被解决. 生成方式 pom依赖 <dependency> ...

  5. mysql索引类型详解

    转载网址: http://c.biancheng.net/view/7897.html

  6. 利用MVC三层架构做一个案例(利用MyBatis实现增删改查)

    查询所有 利用昨天学习到的MyBatis知识,再加上servlet页面的跳转, demo1.jsp UserMapper.java(接口) servletDemo.java MyBatisDemo.j ...

  7. 太坑了,我竟然从RocketMQ源码中扒出了7种导致消息重复消费的原因

    大家好,我是三友~~ 在众多关于MQ的面试八股文中有这么一道题,"如何保证MQ消息消费的幂等性". 为什么需要保证幂等性呢?是因为消息会重复消费. 为什么消息会重复消费? 明明已经 ...

  8. 简述SpringAOP的实现原理

    ​ Spring默认采取的动态代理机制实现AOP,当动态代理不可用时 (代理类无接口)会使用CGlib机制. Spring提供了两种方式来生成代理对象:JDKProxy和Cglib,具体使用哪种方式生 ...

  9. 剑指 offer 第 24 天

    第 24 天 数学(中等) 剑指 Offer 14- I. 剪绳子 给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m.n都是整数,n>1并且m>1),每段绳子的长度记为 k[ ...

  10. CSS3新特性值逻辑选择器

    1. :is 解释::is() CSS伪类函数将选择器列表作为参数,并选择该列表中任意一个选择器可以选择的元素. 例如 对于多个不同父容器的同个子元素的一些共性样式设置,传统写法如下 header p ...