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. Asp.Net Core 网站使用TinyMCE实现上传图片

    1.下载TinyMCE https://www.tiny.cloud/get-tiny/self-hosted/ 解压缩后放在网站wwwroot目录 2.下载中文语言包 https://www.tin ...

  2. 多线程JUC练习

    package com.aliyun.test.learn; import java.util.concurrent.*; import java.util.concurrent.locks.Reen ...

  3. 上位机-串口通信详解(以RS232为例))

    1.什么是串口通信? 写这个的时候我在想应该怎么解释串口通信,因为串口通信很多朋友不了解的原因是涉及到硬件的知识,对于没有相关专业知识的朋友很难理解串口通信.所以我这里只做部分的解释,需要了解更多硬件 ...

  4. 01-第一个Spring程序

    1.导包 所有和spring有关的包(有mybatis包的忽略),后期会使用maven引入 2. 引入spring的配置文件 可命名为applicationContext-service.xml或sp ...

  5. Java-10接口与抽象类

    Java-10接口与抽象类 抽象方法 abstract method机制 这是一个不完整的方法,它只有一个声明,没有方法体 abstract void f(); 包含抽象方法的类被称为抽象类:如果一个 ...

  6. Linux 用户密码不能设置问题

    当我们有时候要更改linux账户密码时,有时候会遇到下面这种情况: Password has been already used. Choose another.passwd: Have exhaus ...

  7. 详解AQS的7个同步组件

    摘要:AQS的全称为Abstract Queued Synchronizer,是在J.U.C(java.util.concurrent)下子包中的类. 本文分享自华为云社区<[高并发]AQS案例 ...

  8. 使用nw.js打包以后的web项目 发布客户端

    一.下载nw.js 直接前往官网下载即可 https://nwjs.io/downloads/ 二.封装最简单的客户端 nw.js下载完成后,在任意位置新建文件夹,例如nwtest,然后在文件夹中新建 ...

  9. 关于Docker compose值IP与域名的映射 之 extra_host

    公司的所有项目都是采用Docker容器化部署,最近有一个项目需要使用定时任务调用第三方Api,正式web环境服务器的网络与第三方网络是通畅的,但是当将代码发布到正式环境,调用接口却显示 System. ...

  10. golang pprof 监控系列(4) —— goroutine thread 统计原理

    golang pprof 监控系列(4) -- goroutine thread 统计原理 大家好,我是蓝胖子. 在之前 golang pprof监控 系列文章里我分别介绍了go trace以及go ...