2023-05-10:给你一棵以 root 为根的二叉树和一个 head 为第一个节点的链表 如果在二叉树中,存在一条一直向下的路径 且每个点的数值恰好一一对应以 head 为首的链表中每个节点的值,
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 为首的链表中每个节点的值,的更多相关文章
- 【数据结构05】红-黑树基础----二叉搜索树(Binary Search Tree)
目录 1.二分法引言 2.二叉搜索树定义 3.二叉搜索树的CRUD 4.二叉搜索树的两种极端情况 5.二叉搜索树总结 前言 在[算法04]树与二叉树中,已经介绍过了关于树的一些基本概念以及二叉树的前中 ...
- [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 ...
- python下实现二叉堆以及堆排序
python下实现二叉堆以及堆排序 堆是一种特殊的树形结构, 堆中的数据存储满足一定的堆序.堆排序是一种选择排序, 其算法复杂度, 时间复杂度相对于其他的排序算法都有很大的优势. 堆分为大头堆和小头堆 ...
- Linux下多路径multipath配置
一.multipath在redhat 6.2中的基本配置: 1. 通过命令:lsmod |grep dm_multipath 检查是否正常安装成功.如果没有输出说明没有安装那么通过yum功能安装一下 ...
- Linux下多路径multipath配置【转】
一.multipath在redhat 6.2中的基本配置: 1. 通过命令:lsmod |grep dm_multipath 检查是否正常安装成功.如果没有输出说明没有安装那么通过yum功能安装一下 ...
- CentOS个人目录下中文路径转英文路径
CentOS个人目录下中文路径转英文路径 如果安装了中文版到CentOS之后,root目录及home目录下会出现中文到路径名,如"桌面"."文档"," ...
- spring java 获取webapp下文件路径
spring java 获取webapp下文件路径 @RequestMapping("/act/worldcup_schedule_time/imgdownload") @Resp ...
- 痛苦的版本对齐(3) cygwin下的路径引用
[续<痛苦的版本对齐(2) 和时间的相关性>]http://www.cnblogs.com/yvivid/p/3541142.html 初步定位,如下告警为.depend文件路径问题导致. ...
- Swift - 使用下划线(_)来分隔数值中的数字
为了增强较大数值的可读性,Swift语言增加了下划线(_)来分隔数值中的数字. 不管是整数,还是浮点数,都可以使用下划线来分隔数字. 1 2 3 4 //数值可读性 let value1 = 10_0 ...
- 如何修改Window系统下PATH路径以及win8下masm32V11
如何修改Window系统下PATH路径 //其实这个都是临时性的, 退出dos窗口就没有用了,只是做个笔记罢了 C:\Users\Administrator> set path=E ...
随机推荐
- 在VS中C#工程操作Mysql数据库
1.实现mysql数据库与VS的连接,需要安装两个插件,作者装的是mysql-connector-net-6.9.9.msi和 mysql-for-visualstudio-1.2.6.msi. 2. ...
- Matlab - 在Figure界面去掉图像的坐标刻度
Matlab版本:2018b 经过一番尝试,发现有两种方法 第一种:修改坐标轴的Visible属性,去掉坐标轴数字和坐标轴标签 第二种:删除Tick,只去掉坐标轴数字 第一种 ①原图 ②如果有多个子图 ...
- AI来实现代码转换!Python转Java,Java转Go不在话下?
今天看到个有趣的网站,给大家分享一下. 该网站的功能很神奇,可以实现编程语言的转化.感觉在一些场景之下还是有点作用的,比如你原来跟我一样是做Java的,因为工作需要突然转Go.这个时候用你Java的经 ...
- oracle学习笔记1 安装 虚拟机 plsql 连接 oracle
第一步就是安装 为了节省资源,运行起来更快捷,首先是在电脑上安装好vm虚拟机, 新建虚拟机,安装xp,也就是把xp光盘文件导入, 接着在虚拟机中下载oracle,解压的话会用到WinRAR,也一并导入 ...
- 【备忘录】 主定理 Master Theorem (转载)
备忘录 https://zhuanlan.zhihu.com/p/113406812
- 使用ASP.NET CORE SignalR实现APP扫描登录
使用signalr实现APP扫码登录 1. 背景介绍 在移动化时代,web开发很多时候都会带着移动端开发,这个时候为了减少重复输入账号密码以及安全性,很多APP端都会提供一个扫码登录功能,web端生成 ...
- Redis-Cluster常用命令
CLUSTER INFO 打印集群的信息 CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息. //节点 CLUSTER MEET <ip> < ...
- 当我把ChatGPT拉进群聊里,我的朋友都玩疯了
前言 近期ChatGPT可以说是太火了,问答.写论文.写诗.写代码,只要输入精确的prompt,他的表现总是让人惊喜.本着打不过就加入的原则.要是把ChatGPT拉入群聊中,会是怎样一番场景?说做就做 ...
- java 面向对象 --static
java 面向对象 --static package charpter5.Demo09; //static public class Student { private static int age; ...
- Spring Boot 中的 ApplicationRunner 和 CommandLineRunner
前言 一般项目中的初始化操作,初次遇见,妙不可言.如果你还有哪些方式可用于初始化操作,欢迎在评论中分享出来~ ApplicationRunner 和 CommandLineRunner Spring ...