LeetCode 652: Find Duplicate Subtrees
You forgot a std::
There's a string without std:: in front of it. I guess you secretly used using namespace std and/or #include &lt;bits/stdc++.h&gt; before submitting the result. The rest looks fine though.
Consider using const TreeNode * everywhere
I know the public API of the LeetCode problem explicitly takes non-const pointers to TreeNode, so you shouldn't change this. But consider that your functions, quite rightly so, don't modify the TreeNodes themselves. So you could write const TreeNode * everywhere you now have TreeNode *, and it would still compile correctly. So in real production code, that is what you should do.
Don't use this-&gt; unnecessarily
In C++, there is rarely a need to write this-&gt;. So in findDuplicateSubtrees(), you can just write serialize(root, nodes_map).
Use range-for and structured bindings where appropriate
You can replace the for-loop in findDuplicateSubtrees() using range-for and structured bindings:
for (auto &amp;[serialization, nodes]: nodes_map) {
    if (nodes.size() &gt; 1) {
        duplicates.push_back(nodes[0]);
    }
}

Consider using a binary serialization format
There are many ways you could serialize trees. Making human-readable strings has some advantages: it is easy to reason about, and it is nice when having to put them in textual formats like XML or JSON files. But it can be inefficient to convert values to strings. In your case, you are only using the serialization internally, so a binary format might be more efficient.
In the case of trees of integers, an obvious representation is just a vector of ints. However, a node might have only one child, and you somehow have to encode that as well. You could use a std::optional&lt;int&gt;, and use std::nullopt to represent an unpopulated leaf node. The serialization format would then be:
std::vector&lt;std::optional&lt;int&gt;&gt; serialization;

The serialization function would then look like:
std::vector&lt;std::optional&lt;int&gt;&gt; serialize(TreeNode *node, std::unordered_map&lt;std::string, std::vector&lt;TreeNode *&gt;&gt; &amp;nodes_map) {
    if (!node) {
        return {std::nullopt};
    }

    auto left = serialize(node-&gt;left, nodes_map);
    auto right = serialize(nodes-&gt;right, nodes_map);
    left.append(node-&gt;val);
    left.insert(left.end(), right.begin(), right.end()); // append right
    return left;
}

For the LeetCode problem, it's not worth doing this though; the algorithmic complexity is the same, and the string representation is smaller for trees with small values. Also, you can not use a std::unordered_map anymore for nodes_map, unless you write a custom hash function. You could use a std::map though, since optionals and vectors have well-defined ordering.