<p>Given an array of strings <code>strs</code>, group the <span data-keyword="anagram">anagrams</span> together. You can return the answer in <strong>any order</strong>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<div class="example-block">
<p><strong>Input:</strong> <span class="example-io">strs = [&quot;eat&quot;,&quot;tea&quot;,&quot;tan&quot;,&quot;ate&quot;,&quot;nat&quot;,&quot;bat&quot;]</span></p>

<p><strong>Output:</strong> <span class="example-io">[[&quot;bat&quot;],[&quot;nat&quot;,&quot;tan&quot;],[&quot;ate&quot;,&quot;eat&quot;,&quot;tea&quot;]]</span></p>

<p><strong>Explanation:</strong></p>

<ul>
	<li>There is no string in strs that can be rearranged to form <code>&quot;bat&quot;</code>.</li>
	<li>The strings <code>&quot;nat&quot;</code> and <code>&quot;tan&quot;</code> are anagrams as they can be rearranged to form each other.</li>
	<li>The strings <code>&quot;ate&quot;</code>, <code>&quot;eat&quot;</code>, and <code>&quot;tea&quot;</code> are anagrams as they can be rearranged to form each other.</li>
</ul>
</div>

<p><strong class="example">Example 2:</strong></p>

<div class="example-block">
<p><strong>Input:</strong> <span class="example-io">strs = [&quot;&quot;]</span></p>

<p><strong>Output:</strong> <span class="example-io">[[&quot;&quot;]]</span></p>
</div>

<p><strong class="example">Example 3:</strong></p>

<div class="example-block">
<p><strong>Input:</strong> <span class="example-io">strs = [&quot;a&quot;]</span></p>

<p><strong>Output:</strong> <span class="example-io">[[&quot;a&quot;]]</span></p>
</div>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= strs.length &lt;= 10<sup>4</sup></code></li>
	<li><code>0 &lt;= strs[i].length &lt;= 100</code></li>
	<li><code>strs[i]</code> consists of lowercase English letters.</li>
</ul>

/*
    anagram? same length, same freq of characters
    input range: lowercase alphabet (26 characters)

    vector<int> counts(26, 0)

    strs = ["eat","tea","tan","ate","nat","bat"]
*/

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        // Lambda for custom hash function based on character frequency
        auto hash_fn = [](const string& str) -> size_t {
            vector<int> freq(26, 0); // ASCII character set
            for (char c : str) {
                freq[c - 'a']++;
            }

            size_t hash_value = 0;
            for (int f : freq) {
                hash_value ^= hash<int>{}(f) + 0x9e3779b9 + (hash_value << 6) +
                              (hash_value >> 2);
            }

            return hash_value;
        };

        // Lambda for custom equality function based on character frequency
        auto equal_fn = [](const string& str1, const string& str2) -> bool {
            if (str1.length() != str2.length())
                return false;

            vector<int> freq1(26, 0);
            vector<int> freq2(26, 0);
            for (char c : str1) {
                freq1[c - 'a']++;
            }
            for (char c : str2) {
                freq2[c - 'a']++;
            }

            return freq1 == freq2;
        };

        // unordered_map that uses the lambda hash and equality function
        unordered_map<std::string, vector<string>, decltype(hash_fn),
                      decltype(equal_fn)>
            freq(0, hash_fn, equal_fn);

        for (const string& str : strs) {
            freq[str].emplace_back(str);
        }

        vector<vector<string>> result;
        for (const auto& [key, val] : freq) {
            result.emplace_back(val);
        }

        return result;
    }
};
27671