这道题有几个点,第一个就是如何比较结点,方法就是序列化输出字符串,
然后是如何查找是否存在,方法hashmap;
如何不重复插入,方法set。
实际解决的还是有几个问题;
class Solution {
public:
unordered_map<string,TreeNode*> hashmap;
set<TreeNode*> res;
string preorder(TreeNode *root)
{
if(root==NULL)
return "null ";
string ss=to_string(root->val)+" "+preorder(root->left)+preorder(root->right);
if(hashmap.find(ss)!=hashmap.end())
//错误做法1:res.insert(root);以为找到了就把结点放进去,但是啊,每个结点是不一样的,而且这样的set的意义何在?所以要用hashmap去找这个字符串的结点
res.insert(hashmap[ss]);
else
//错误做法2:hashmap[preorder(root)]=root;在函数中调用自己,内存泄露,真的是蠢啊
hashmap[ss]=root;
return ss;
}
vector<TreeNode*> findDuplicateSubtrees(TreeNode* root) {
if(!root) return {};
preorder(root);
return vector<TreeNode*>(res.begin(),res.end());
}
};
但是我第一次做的时候,有点蠢,后面几个案例用时超时,怎么回事呢?一个结点我递归了两次!我是递归序列化,然后再递归查找,这不是蠢到家了吗?序列化和查找是可以在一个递归里实现的。
class Solution {
public:
unordered_map<string,int> hashmap;
vector<TreeNode*> res;
string serialize(TreeNode *root)
{
if(root==NULL)
return "null ";
return to_string(root->val)+" "+serialize(root->left)+serialize(root->right);
}
vector<TreeNode*> findDuplicateSubtrees(TreeNode* root) {
if(!root) return {};
if(hashmap.find(serialize(root))!=hashmap.end())
{if(!hashmap.find(serialize(root))->second)
{res.push_back(root);hashmap[serialize(root)]++;}}
else
hashmap[serialize(root)]=0;
findDuplicateSubtrees(root->left);
findDuplicateSubtrees(root->right);
return res;
}
};
只用hash表实现的话也可以
unordered_map<string,int> hashmap;
vector<TreeNode*> res;
string preorder(TreeNode *root)
{
if(root==NULL)
return "null ";
string ss=to_string(root->val)+" "+preorder(root->left)+preorder(root->right);
if(hashmap.find(ss)!=hashmap.end())
{hashmap[ss]++;
if(hashmap[ss]==1)
res.push_back(root);
}
else
hashmap[ss]=0;
return ss;
}
中间的的步骤也可以用下面的代码。因为hashmap[key]的方式去访问的话,此时hashmap如果没有,那么就会自动创建。且把其value设定为该类型的默认值,int的话就是0。
这个方法在这里刚好能遇到,但是如何在其他地方查找就要注意,不然会自动插入
if(hashmap[ss]==1)
res.push_back(root);
hashmap[ss]++;
最后标准答案里面那种uid解法,能大概明白,但是不会用C++写