我正在尝试解决 GeeksforGeeks 问题 Sum Tree:
给定一棵二叉树。如果对于树中除叶子之外的每个节点 X,其值等于其左子树值与其右子树值之和,则返回 true。否则返回 false。
空树也是 Sum Tree,因为空树的和可以被认为是 0。叶子节点也被认为是 Sum Tree。
示例1:
输入:
3 / \ 1 2
输出: 1
说明: 左子树和右子树的和是 1 + 2 = 3,即根节点的值。 因此,给定的二叉树是一棵和树。
示例2:
输入:
10 / \ 20 30 / \ 10 10
输出:0
说明: 给定的树不是求和树。 对于根节点,元素之和 左子树为 40,元素之和 右子树为 30。根元素 = 10 不等于 30+40。
我下面的代码通过了所有主要测试用例,例如:
我的代码怎么可能在 return
函数的递归调用中执行
solve
语句而正常工作?看起来递归函数有一个默认返回值
solve
我可以信赖。代码
#include <bits/stdc++.h>
using namespace std;
struct Node
{
int data;
struct Node *left;
struct Node *right;
};
// Utility function to create a new Tree Node
Node* newNode(int val)
{
Node* temp = new Node;
temp->data = val;
temp->left = NULL;
temp->right = NULL;
return temp;
}
// Function to Build Tree
Node* buildTree(string str)
{
// Corner Case
if(str.length() == 0 || str[0] == 'N')
return NULL;
// Creating vector of strings from input
// string after spliting by space
vector<string> ip;
istringstream iss(str);
for(string str; iss >> str; )
ip.push_back(str);
// Create the root of the tree
Node* root = newNode(stoi(ip[0]));
// Push the root to the queue
queue<Node*> queue;
queue.push(root);
// Starting from the second element
int i = 1;
while(!queue.empty() && i < ip.size()) {
// Get and remove the front of the queue
Node* currNode = queue.front();
queue.pop();
// Get the current node's value from the string
string currVal = ip[i];
// If the left child is not null
if(currVal != "N") {
// Create the left child for the current node
currNode->left = newNode(stoi(currVal));
// Push it to the queue
queue.push(currNode->left);
}
// For the right child
i++;
if(i >= ip.size())
break;
currVal = ip[i];
// If the right child is not null
if(currVal != "N") {
// Create the right child for the current node
currNode->right = newNode(stoi(currVal));
// Push it to the queue
queue.push(currNode->right);
}
i++;
}
return root;
}
// } Driver Code Ends
// Solution class comes here
// ... see my code in next code block ...
//
//{ Driver Code Starts.
int main()
{
int t;
scanf("%d ",&t);
while(t--)
{
string s;
getline(cin,s);
Node* root = buildTree(s);
Solution ob;
cout <<ob.isSumTree(root) << endl;
}
return 1;
}
// } Driver Code Ends
我的代码:
class Solution
{
public:
// int returnSum=0;
// Should return true if tree is Sum Tree, else false
int solve(Node* root, int& sumofSubtree){
if(root==NULL){
return 0;
}
int l = solve(root->left, sumofSubtree);
int r = solve(root->right, sumofSubtree);
// int sum = l+r;
sumofSubtree = l+r+root->data;
if(sumofSubtree-root->data == root->data){
return sumofSubtree;
}
}
bool isSumTree(Node* root)
{ //Main Function
int sumofSubtree = 0;
solve(root, sumofSubtree);
cout<<"sumofSubtree"<<" : "<<sumofSubtree<<endl;
//
if(sumofSubtree-root->data==root->data || sumofSubtree == root->data){
return true;
}
else{
return false;
}
}
};
未定义的行为。尽管它可能适用于多次运行和输入,但这并不可靠。
您的代码当然不会通过每个输入。例如,我在 GeeksforGeeks 用户界面中使用了这个自定义输入测试用例:
3 1 2 4
...测试失败了。
isSumTree
函数给出了函数返回 true 的两种可能性:
sumofSubtree - root->data == root->data
或
sumofSubtree == root->data
root-data
只有 一个
正确值,而不是两个。其他一些备注:
sumofSubtree
是通过引用传递的,但调用者(
isSumTree
除外)永远不会使用在进行递归调用后可能已存储在那里的值。它立即覆盖它。所以本质上,这个引用参数仅用于检查根节点。这并没有真正提高代码的可读性。
100
/ \
20 20
/ \ / \
5 5 5 5
/ \ / \ / \ / \
.. .. .. .. .. .. ..
当根的子节点之一
是一片叶子(那么它不算双倍)时,我们可以有类似的推理,...等等。
这里的代码看起来并不比必要的更深入。当然,如果这棵树恰好整体上是正确的,那么就需要遍历所有节点:
class Solution
{
private:
bool isLeaf(Node *root) {
return root && !root->left && !root->right;
}
int getSum(Node *root) {
return !root ? 0 : isLeaf(root) ? root->data : 2 * root->data;
}
public:
bool isSumTree(Node* root)
{
return !root
|| isLeaf(root)
|| root->data == getSum(root->left) + getSum(root->right)
&& isSumTree(root->left) && isSumTree(root->right);
}
};