You are given an array of strings of the same length words.

In one move, you can swap any two even indexed characters or any two odd indexed characters of a string words[i].

Two strings words[i] and words[j] are special-equivalent if after any number of moves, words[i] == words[j].


	For example, words[i] = "zzxy" and words[j] = "xyzz" are special-equivalent because we may make the moves "zzxy" -&gt; "xzzy" -&gt; "xyzz".


A group of special-equivalent strings from words is a non-empty subset of words such that:


	Every pair of strings in the group are special equivalent, and
	The group is the largest size possible (i.e., there is not a string words[i] not in the group such that words[i] is special-equivalent to every string in the group).


Return the number of groups of special-equivalent strings from words.

&nbsp;
Example 1:

Input: words = ["abcd","cdab","cbad","xyzz","zzxy","zzyx"]
Output: 3
Explanation: 
One group is ["abcd", "cdab", "cbad"], since they are all pairwise special equivalent, and none of the other strings is all pairwise special equivalent to these.
The other two groups are ["xyzz", "zzxy"] and ["zzyx"].
Note that in particular, "zzxy" is not special equivalent to "zzyx".


Example 2:

Input: words = ["abc","acb","bac","bca","cab","cba"]
Output: 3


&nbsp;
Constraints:


	1 &lt;= words.length &lt;= 1000
	1 &lt;= words[i].length &lt;= 20
	words[i] consist of lowercase English letters.
	All the strings are of the same length.


class Solution:
    def numSpecialEquivGroups(self, words) -> int:
        return len(set([(''.join(sorted(i[::2])),''.join(sorted(i[1::2]))) for i in words]))
class Solution {
    public int numSpecialEquivGroups(String[] words) {
        if(words.length == 0 || words.length == 1) return words.length;

        // To store group sizes
        HashMap<String, Integer> hashmap = new HashMap<>();

        // To mark the strings already part of some groups
        boolean[] isGrouped = new boolean[words.length];

        for(int index = 0; index < words.length; index++) {
            if(isGrouped[index]) continue; // Already grouped
            String word = words[index];
            for(int j = index + 1; j < words.length; j++) {
                if(isGrouped[j]) continue; // Already grouped
                String string = words[j];

                // The idea is to store count of characters on even and odd indices
                // It is done by incrementing counts of characters in both even and odd maps respectively
                // Then compare the two strings by reducing the same count in both even and odd maps
                // If both the maps are empty at last, the two strings for a group
                HashMap<Character, Integer> evens = new HashMap<>();
                HashMap<Character, Integer> odds = new HashMap<>();
                boolean isSpecialEquivalent = true;

                for(int i = 0; i < word.length(); i++) {
                    if(i % 2 == 0) {
                        evens.put(word.charAt(i), evens.getOrDefault(word.charAt(i), 0) + 1);
                    } else {
                        odds.put(word.charAt(i), odds.getOrDefault(word.charAt(i), 0) + 1);
                    }
                }

                for(int i = 0; i < string.length(); i++) {
                    char character = string.charAt(i);
                    if(i % 2 == 0) {
                        if(!evens.containsKey(character)) {
                            isSpecialEquivalent = false;
                            break;
                        }

                        evens.put(character, evens.get(character) - 1);
                        if(evens.get(character) == 0) evens.remove(character);
                    } else {
                        if(!odds.containsKey(character)) {
                            isSpecialEquivalent = false;
                            break;
                        }

                        odds.put(character, odds.get(character) - 1);
                        if(odds.get(character) == 0) odds.remove(character);
                    }
                }

                if(isSpecialEquivalent) {
                    hashmap.put(word, hashmap.getOrDefault(word, 0) + 1);
                    isGrouped[j] = true;
                }
            }

            // If no group is formed, the word alone forms a group of size 1
            if(!hashmap.containsKey(word)) hashmap.put(word, 1);
        }

        return hashmap.size();
    }
}
class Solution {
public:
    int numSpecialEquivGroups(vector<string>& words) {
        int n = words.size();
        vector<pair<string, string>>v;
        for(auto it:words) {
            string even = "";
            string odd = "";
            for(int i = 0;i<it.size();i+=2) even+=it[i];
            for(int i = 1;i<it.size();i+=2) odd+=it[i];
            sort(even.begin(), even.end());
            sort(odd.begin(), odd.end());
            even+=odd;
            v.push_back({it, even});

        }

        map<string, int>m;
        for(auto it:v) {
            m[it.second]++;
        }

        return m.size();
    }
};
var numSpecialEquivGroups = function(words) {
    const set = new Set()
    const a = 'a'.charCodeAt(0)
    const alphaCounter = new Array(26).fill(0)
    for (const word of words) {
        const [even, odd] = [[...alphaCounter], [...alphaCounter]]
        word.split('').forEach((l,i) => {
            l = l.charCodeAt(0) - a
            if (i%2) odd[l]++
            else even[l]++
        })
        const hashkey = even.join('') + odd.join('')
        set.add(hashkey)
    }
    return set.size
};
Groups of Special-Equivalent Strings