难度简单219收藏分享切换为英文接收动态反馈
给出一棵二叉树,其上每个结点的值都是 0
或 1
。每一条从根到叶的路径都代表一个从最高有效位开始的二进制数。
- 例如,如果路径为
0 -> 1 -> 1 -> 0 -> 1
,那么它表示二进制数01101
,也就是13
。
对树上的每一片叶子,我们都要找出从根到该叶子的路径所表示的数字。
返回这些数字之和。题目数据保证答案是一个 32 位 整数。
示例 1:
输入:root = [1,0,1,0,1,0,1] 输出:22 解释:(100) + (101) + (110) + (111) = 4 + 5 + 6 + 7 = 22
示例 2:
输入:root = [0] 输出:0
提示:
- 树中的节点数在
[1, 1000]
范围内 Node.val
仅为0
或1
大体意思都能懂,只是在二叉树的递归回溯法中与普通的递归回溯法还是有区别的,其实只要理解了递归回溯的思想,这些算不上区别,在思路上,因为传统的回溯法一般都会和标记数组一起使用,来达到深度优先搜索完成后的向来的方向回退一步再进行选择的目的,但是二叉树不同,因为普通的二叉树,一旦进入就很难回头了,所以要保证分叉进入不同的路之后,当一条路走到尽头时,要有办法在回到第一个分叉的地方,所以,左右子树的递归要和回溯结合在一起,也就是左右子树递归多少次,就要回溯多少次,可能会有人不理解回溯那么多次不会把两个相同父节点的叶子结点给忽略了吗?这其实就要从进入和离开子树的递归说起了,我们看到的递归仅仅有一两句话,但是实际上他是由很多个递归嵌套起来的,举个例子
dfs(左子树)
{
dfs(左子树的左子树){。。。。。。回溯。。。return ;}
dfs(左子树的右子树){。。。。。。回溯。。。return ;}
回溯。。。
return ;
}
dfs(右子树)
{
。。。。。
}
所以说在第一个叶子结点执行完后,接着是回溯递归该叶子结点父节点的右子树,然后再通过两次回溯到达叶子结点的上一层,再进行递归,所以说也就有了二叉树全部的不同路径的走法
那接下来就是代码了(可能有点眼花,建议复制到编译器里看)
class Solution {
public:
vector<int >p;
vector<vector<int>> ans;
void dfs(TreeNode* root,vector<vector<int> >&ans,vector<int> &p)
{
if(!root->left&&!root->right)
{
p.push_back(root->val);
ans.push_back(p);
return ;
}
else
{
p.push_back(root->val);
if(root->left)
{dfs(root->left,ans,p);p.pop_back();}
if(root->right)
{dfs(root->right,ans,p);p.pop_back();}
}
}
int sumRootToLeaf(TreeNode* root) {
int result=0;
dfs(root,ans,p);
for(auto &i:ans)
{
int sum=0;
int k=i.size()-1;
for(auto &j:i)
{
sum+=pow(2,k--)*j;
}
result+=sum;
}
return result;
}
};
2.其实这个题还有更简单的方法,就是省去二进制求和的代码,用位运算加以取代,再以递归取代回溯法,也就是官方的方法,让我学到了位运算的用处,他可以直接将二进制进行运算,从而节省了计算机计算的时间,大大提高了代码效率,建议能用位运算,别用运算法,
这里以叶子节点为递归结束的条件,每当碰到一个叶子节点,就返回当前的结果,在最后的大左右子树进行总求和进行计算,真的很牛啊,学到老活到老。
算法之路————递归与回溯应用只二叉树