You are given a 0-indexed array of unique strings words
.
A palindrome pair is a pair of integers (i, j)
such that:
words[i] + words[j]
(the concatenation of the two strings) is a palindrome.
Return an array of all the palindrome pairs of words
.
Example 1:
Copy Input: words = ["abcd","dcba","lls","s","sssll"]
Output: [[0,1],[1,0],[3,2],[2,4]]
Explanation: The palindromes are ["abcddcba","dcbaabcd","slls","llssssll"]
Example 2:
Copy Input: words = ["bat","tab","cat"]
Output: [[0,1],[1,0]]
Explanation: The palindromes are ["battab","tabbat"]
Example 3:
Copy Input: words = ["a",""]
Output: [[0,1],[1,0]]
Explanation: The palindromes are ["a","a"]
Constraints:
1 <= words.length <= 5000
0 <= words[i].length <= 300
words[i]
consists of lowercase English letters.
这题呢,超级难,bruteforce呢,是T:O(n^2 * k)。
然后呢,看了答案,通过把前缀和后缀存入hashMap中优化,能优化到T:O(k^2 * n),但n超级大的时候,会比brute force好。这里有3种情况需要加到result里:
1.存在reverse,譬如,list里有CAT和TAC。那么这对可以加
2.word1比较短,word2比较长,word2后缀是word1的reverse而且word2中间是palindrome。譬如,CAT,LOLTAC
3.word1比较长,word2比较短,word1前缀是word2的reverse而且word1中间是palindrome,譬如,CATLOL ,TAC
我们每遇到一个word,就算一次prefix和suffix(剩余部分是valid palindrome),然后reverse这个prefix和suffix看是不是存在在worlist里。如果是,那么这两个可以组成一对。
还有一种解法是用Trie,因为我们这里算了一堆prefix,suffix。具体做法要看solution,但其实时间复杂度没变。听说是如果我们要support变增加,变查找的功能时候,Trie比较好。
Copy // 抄了一遍
public List<List< Integer >> palindromePairs( String [] words) {
if (words == null || words . length == 0 ) {
return null ;
}
Map < String , Integer > wordMap = new HashMap <>();
int len = words . length ;
for ( int i = 0 ; i < len; i ++ ) {
wordMap . put (words[i] , i);
}
List < List < Integer >> result = new ArrayList <>();
for ( String word : wordMap . keySet ()) {
int curInd = wordMap . get (word);
String reverseWord = new StringBuilder(word) . reverse () . toString ();
// case 1, reverse of this word exist
if ( wordMap . containsKey (reverseWord) && wordMap . get (reverseWord) != curInd) {
result . add ( Arrays . asList (curInd , wordMap . get (reverseWord)));
}
// case 2, suffix, current word is 2nd word
for ( String suffix : getAllValidSuffix(word) ) {
String reverseSuffix = new StringBuilder(suffix) . reverse () . toString ();
if ( wordMap . containsKey (reverseSuffix)) {
result . add ( Arrays . asList ( wordMap . get (reverseSuffix) , curInd));
}
}
// case 3, prefix, current word is 1st word
for ( String prefix : getAllValidPrefix(word) ) {
String reversePrefix = new StringBuilder(prefix) . reverse () . toString ();
if ( wordMap . containsKey (reversePrefix)) {
result . add ( Arrays . asList (curInd , wordMap . get (reversePrefix)));
}
}
}
return result;
}
private List< String > getAllValidSuffix( String word) {
List < String > suffixes = new ArrayList <>();
for ( int i = 0 ; i < word . length (); i ++ ) {
// 前面是valid palindrome
if ( isPalindrome(word , 0 , i) ) {
// 把后半部分放入suffix list里
suffixes . add ( word . substring (i + 1 , word . length ())); //houmia
}
}
return suffixes;
}
private List< String > getAllValidPrefix( String word) {
List < String > prefixes = new ArrayList <>();
for ( int i = 0 ; i < word . length (); i ++ ) {
// 后面是valid palindrome
if ( isPalindrome(word , i , word . length() - 1 ) ) {
// 把前半部分放入prefix list里
prefixes . add ( word . substring ( 0 , i));
}
}
return prefixes;
}
private boolean isPalindrome( String str , int start , int end) {
for ( int i = start , j = end; i < j; i ++ , j -- ) {
if ( str . charAt (i) != str . charAt (j)) {
return false ;
}
}
return true ;
}
// 暴力算法
public List<List< Integer >> palindromePairs( String [] words) {
if (words == null || words . length == 0 ) {
return null ;
}
List < List < Integer >> result = new ArrayList <>();
int len = words . length ;
for ( int i = 0 ; i < len; i ++ ) {
for ( int j = 0 ; j < len; j ++ ) {
if (i == j) {
continue ;
}
String combinedStr = words[i] + words[j];
if ( isPalindrome(combinedStr) ) {
List < Integer > oneAns = Arrays . asList (i , j);
result . add (oneAns);
}
}
}
return result;
}
private boolean isPalindrome( String str) {
for ( int i = 0 , j = str . length () - 1 ; i < j; i ++ , j -- ) {
if ( str . charAt (i) != str . charAt (j)) {
return false ;
}
}
return true ;
}