前言
这是六月集训的第十八日,今日的训练内容是 树
解题报告
今日学到很多深度优先搜索的知识。
1.力扣1361
原题链接
题目概述
先记录一下,对于入度出度还有很多不懂的东西。
2.力扣1367
原题链接
题目概述
给你一棵以 root 为根的二叉树和一个 head 为第一个节点的链表。
如果在二叉树中,存在一条一直向下的路径,且每个点的数值恰好一一对应以 head 为首的链表中每个节点的值,那么请你返回 True ,否则返回 False 。
一直向下的路径的意思是:从树中某个节点开始,一直连续向下的路径。
解题思路
好好记录一下这道题,这道题是属于有思路但是不知道怎么实现的题目,在看了一下别人的解法之后对DFS的写法有了一些新的想法,在源码剖析仔细的来记录一下这道题的解法。
源码剖析
bool DFS(struct ListNode* head,struct TreeNode* root){
if(head==NULL) return true; //链表要是移动到结束了肯定有子串满足
if(root==NULL) return false; //说明这条线路没有满足条件的子串
if(head->val!=root->val) return false; //都是递归出口
return (DFS(head->next,root->left))||(DFS(head->next,root->right)); //(1)
}
bool isSubPath(struct ListNode* head, struct TreeNode* root){
if(root==NULL) return false;
return (DFS(head,root))||(isSubPath(head,root->left))||(isSubPath(head,root->right));//(2)
}
- 这种写法的意思就是,递归遍历到底,只要有一条路径是满足题目要求的解就可以返回 true。
- 这个递归的意思是,对每一个结点的左子树和右子树都进行深度优先搜索寻找是否有满足条件的路径,只要有满足的路径就返回 true。假如当前的树结点返回了 false ,这个时候链表的头指针就没有移动的必要了,因此直接取链表的头结点再对左树进行判断,右树同理。
3.力扣1457
原题链接
题目概述
给你一棵二叉树,每个节点的值为 1 到 9 。我们称二叉树中的一条路径是 「伪回文」的,当它满足:路径经过的所有节点值的排列中,存在一个回文序列。
请你返回从根到叶子节点的所有路径中 伪回文 路径的数目。
解题思路
这题的难点其实在于判断经过的路径上面的数字是否为回文序列上,也就是要判断好出现了奇数次的数字个数是否为 0 个或 1个。
这里我使用了一个哈希表配合深度优先搜索,一边路径行进的过程中一边就对哈希表进行填充,然后在到达了此路径的底部(也就是叶结点的位置)才开始看哈希表中的数据,去看是否有出现过奇数次的数字,如果有超过两个就直接回溯,否则计数器加一。
这里有几个指的一说的点:
- DFS采用的是 void 的函数类型,因此不会返回值(这是为了更加方便遍历的过程),那么如果需要返回所需要的值的话,就要传入一个指针,然后直接对指针所指的数据进行操作。但尤其要注意,在调用DFS的时候,写进去的参数一定要写上的是数据的地址或者是指向数据的指针。在之前做题时在这里被卡住过几个小时。非常重要。
- 上面没有仔细提到回溯这个过程。我们来看,每一次遍历的过程,实际上我们进行的操作就是让对哈希表的对应项加一,那么如果要回溯的话也就只要把这一步操作抵消了就好了,也就是让哈希表这一项的值减一。假如当前的遍历已经进行到了叶结点的位置,其实只要不符合条件的话仍然只是对哈希表进行了操作,如果满足条件的话又不需要回溯,因此回溯的操作是一样的。
- 对于 void 类型的递归函数来说,当结束了某一条路径的递归,回溯一般会在路径结束的地方使用 return;
源码剖析
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
void DFS(struct TreeNode* root,int* ans,int *hash){
if(root==NULL) return;
if(root->left==NULL&&root->right==NULL){
hash[root->val]++;
int i,cal = 0;
for(i=1;i<10;++i){
if(hash[i]&1){
cal++;
}
}
if(cal<=1){
(*ans)++;
}
hash[root->val]--; //这里很关键,因为哈希表不会自己随着函数回溯,要手动处理
return; //回溯过程也代表这条路径结束了
}
hash[root->val]++; //每个结点都是需要进行操作的
if(root->left==NULL&&root->right){
DFS(root->right,ans,hash);
}else{
if(root->right==NULL&&root->left){
DFS(root->left,ans,hash);
}else{
DFS(root->right,ans,hash);
DFS(root->left,ans,hash);
}
}
hash[root->val]--;
}
int pseudoPalindromicPaths (struct TreeNode* root){
int hash[10] = {0};
int ans = 0;
DFS(root,&ans,hash);
return ans;
}
4.力扣1373
原题链接
题目概述
给你一棵以 root 为根的 二叉树 ,请你返回 任意 二叉搜索子树的最大键值和。
二叉搜索树的定义如下:
- 任意节点的左子树中的键值都 小于 此节点的键值。
- 任意节点的右子树中的键值都 大于 此节点的键值。
- 任意节点的左子树和右子树都是二叉搜索树。
解题思路
先暂做记录
3415



被折叠的 条评论
为什么被折叠?



