[Java/Python 3]  One pass w/ brief explanation and analysis.
Intuition:\n1. In order to build a palindrome from given input, we can start from the center to construct one;\n2. There are 2 possibilites for the center of th
**Intuition:**\n1. In order to build a palindrome from given input, we can start from the center to construct one;\n2. There are `2` possibilites for the center of the palindrome:\na empty string;\na palindromic word, which implies `word[0] == word[1]`;\n3. According to the problem, each word is allowed to use at most once; Also, we only need the length of the longest palindrome. \n\nTherefore, we can use `HashMap/dict` to save non-paired words and try to pair the words during traversal; Once find a counter-part for current word, remove it from the `HashMap/dict`, increase the `pairs` counter and update the count of the symmitric words accordingly.\n\n---\n\nCount pairs and symmetric words \n\n1. Use a `HashMap`, `nonPaired`, to count words not in pairs yet; use `pairs` to count the number of pairs of mirror words we found, use `sym` to count the symmetric words **not** in `pairs`;\n2. Traverse input; For each word, first check if its mirror word already in `nonPaired`; if yes, found a pair, deduct its mirror count in `nonPaired`; otherwise, increase the count of the word in `nonPaired`;\n3. Adjust the `sym` accordingly in 2.\n4. If at least `1` symmetric word not in `pairs`, we can put it in the middle of the palindrome to construct, and put those counted in `pairs` on the two sides.\n5. Each pairs has a size of `4`, and a symmetric word, if exists, has a size of `2`; therefore, `4 * pairs + (sym > 0 ? 2 : 0)` is the answer.\n\n```java\n    public int longestPalindrome(String[] words) {\n        Map<String, Integer> nonPaired = new HashMap<>();\n        int pairs = 0, sym = 0;\n        for (String w : words) {\n            String reverse = new StringBuilder(w).reverse().toString();\n            if (nonPaired.getOrDefault(reverse, 0) > 0) { // Find a counterpart for w among non-paired words.\n                ++pairs;                                  // Increase the counter by 1.  \n                nonPaired.merge(reverse, -1, Integer::sum); // Decrease reverse by 1 since it has been counted in pairs.\n                sym -= w.charAt(0) == w.charAt(1) ? 1 : 0; // Decrease sym by 1 since it has been counted in pairs. \n            }else {\n                nonPaired.merge(w, 1, Integer::sum); // Increase the occurrence of w. \n                sym += w.charAt(0) == w.charAt(1) ? 1 : 0; // Increase sym by 1. \n            }\n        }\n        return 4 * pairs + (sym > 0 ? 2 : 0);        \n    }\n```\n**Q & A:**\nQ1: What does the following statement mean?\n```java\n            nonPaired.merge(w, 1, Integer::sum); \n```\nA1: It is same as the following:\n```java\n            nonPaired.put(w, 1 + nonPaired.getOrDefault(w, 0)); \n```\n\n----\n\n```python\n    def longestPalindrome(self, words: List[str]) -> int:\n        pairs, sym, nonPaired = 0, 0, Counter()\n        for w in words:\n            if nonPaired[w[:: -1]] > 0:\n                pairs += 1\n                nonPaired[w[:: -1]] -= 1\n                sym -= 1 if w[0] == w[1] else 0\n            else:\n                nonPaired[w] += 1    \n                sym += 1 if w[0] == w[1] else 0\n        return pairs * 4 + (2 if sym > 0 else 0)\n```\n**Analysis:**\n\nTime & space: `O(n)`, where `n = words.length`.\n\n----\n\nPlease feel free to let me know if you have any questions, and **upvote** it if you find it helpful.
['Java', 'Python3']