My first reaction was to use Manacher - which is O(n*k*k) - n is the no. of words, and k is the average length of words.
Code of Manacher based solution is kinda long:
class Solution { vector<vector<int>> ret; // To find lenghth of the leading Palin only vector<string> manacher(const string &s) { size_t slen = s.length(); if (slen < 2) return { s }; // inserting tokens to original string string ns = "#"; for (auto c : s) { ns += c; ns += "#"; } // size_t len = ns.length(); vector<size_t> rec(len, 0); int maxi = 1, maxr = 0; vector<int> rs_leading; int ci = 1, r = 0; for (size_t i = 1; i < len; i++) { int myr = 0; // brand new index if (i <= (ci + r)) // can be reused due to symmetry { myr = std::min(rec[2 * ci - i], (ci + r) - i); } // expand to new inx towards end of string bool bMis = false; int max_ex = std::min(len - 1 - i, i); while (myr < max_ex) { myr++; if (ns[i + myr] != ns[i - myr]) { bMis = true; break; } } if (bMis) myr--; // book-keeping rec[i] = myr; if ((i + myr) > (maxi + maxr)) ci = i, r = myr; if (myr > maxr) // record max { maxi = i, maxr = myr; if (i == myr) { rs_leading.push_back(maxr); } } } // Retrieve the Palin vector<string> ret; for (auto l : rs_leading) { string raw = ns.substr(0, l * 2 + 1); string tmp; for (auto c : raw) { if (c != '#') tmp += c; } ret.push_back(tmp); } return ret; } void handleLeadingPalin(string w, int inxw, unordered_map<string, int> &dict, bool bReversed) { vector<string> hPalins = manacher(w); for (auto hPalin : hPalins) { int plen = hPalin.size(); if (plen) { string tgt = w.substr(plen); if (!bReversed) reverse(tgt.begin(), tgt.end()); if (dict.find(tgt) != dict.end()) { int inxt = dict[tgt]; if (inxw != inxt) { if (!bReversed) ret.push_back({ inxt, inxw }); else ret.push_back({ inxw, inxt}); } } } } } public: vector<vector<int>> palindromePairs(vector<string>& words) { // Fill out String <-> Index dictionary unordered_map<string, int> dict; for (int i = 0; i < words.size(); i ++) dict[words[i]] = i; // Go for (auto &k : dict) { int inx = k.second; // case 1: reverse the whole string string tgt1 = k.first; reverse(tgt1.begin(), tgt1.end()); if (dict.find(tgt1) != dict.end()) { int inx1 = dict[tgt1]; if (inx1 != inx) ret.push_back({inx, inx1}); } // case 2a: leading manacher of key handleLeadingPalin(k.first, inx, dict, false); // case 2b: leading manacher of reverse(key) string tmp = k.first; reverse(tmp.begin(), tmp.end()); handleLeadingPalin(tmp, inx, dict, true); } return ret; } };
And please check this concise Python solution - so neat!