思路:我们如何使用 递归去写呢?
递归三部曲 :
1 . 确定递归函数参数和它的返回值;
2.确定递归结束条件 ;
3. 确定单层递归逻辑;
这一道题是根据中序序列及后序序列去确定先序序列, 我们的递归函数的参数设置为
(
h
l
,
h
r
,
z
l
,
z
r
)
(hl , hr , zl , zr )
(hl,hr,zl,zr)分别表示当前树的 : 后序遍历的 左边界 , 后序遍历序列的右边界+1 , 中序遍历序列的左边界, 中序遍历的右边界 + 1 , 递归结束的条件是当前树的中序遍历序列的左边界和中序遍历的右边界 + 1 相等 (表示这个点是一个叶子结点 ) 我们就直接return ; 单层递归逻辑就是遍历当前树的中序序列根据传入的后序序列的右边界找到这个树的根节点的在中序遍历序列的对应的下标(方便确定当前树的左子树和右子树) , 因为是先序遍历 , 我们先输出这个树的根节点 ; 之后递归遍历这个树的左子树和右子树, 从而实现对整个树的遍历。
#include <iostream>
#include <cstring>
using namespace std ;
string a ,b ;
void dfs(int hl , int hr , int zl , int zr)
{
if(zl == zr ) return ;
int flag = -1 ;
for(int i = zl ; i < zr ; i ++ )
{
if(a[i] == b[hr - 1] )
{
flag = i ;
cout << a[flag] ;
break ;
}
}
dfs(hl , hl + flag - zl , zl , flag ) ;
dfs(hl + flag - zl , hr - 1 , flag + 1 , zr ) ;
}
int main()
{
cin >> a >> b ;
dfs(0 , b.size() , 0 , a.size() ) ; // 传入的是左边界和右边界加1
return 0 ;
}
思路: 这题跟上题的递归思路是一样的,我们用类似的递归方式去解决这道题,
注意点:这题的数据范围是 1 e 5 1e5 1e5 , 我么根据这个递归方式, 要想实现这个东西 , 就需要进行一些优化, 注意在递归函数参数的确定中, 我们可以看到的是 :
void dfs(vector<int> &pre ,int l1 , int r1 , vector<int> &suf , int l2 , int r2
这个里面的容器是用引用去做的, 这样能够节省很多的创建形参的时间。
AC代码
class Solution {
public:
vector<int > ans ;
void dfs(vector<int> &pre ,int l1 , int r1 , vector<int> &suf , int l2 , int r2 )
{
if(l1 > r1 ) return ;
if(l1 == r1 ) { // 如果遍历到根节点, 我们就将这个点直接入栈。
ans.push_back( pre[l1] ) ;
return ;
}
int root = pre[l1] ;
int pos ;
int root2 = pre[ l1 + 1 ] ;
for(int i = l2 ; i <= r2 ; i ++ )
{
if(suf[i] == root2 )
{
pos = i ;
break ;
}
}
dfs(pre , l1 + 1 , l1 + 1 + pos - l2 , suf , l2 , pos ) ;
ans.push_back(root) ;
dfs(pre , l1 + 2 + pos - l2 , r1 , suf , pos + 1 , r2 - 1 ) ;
}
vector<int> solve(int n, vector<int>& pre, vector<int>& suf) {
dfs(pre , 0 , n - 1 , suf , 0 , n - 1 ) ;
return ans ;
}
};