Given a list of unique words, find all pairs of distinct indices (i, j)
in the given list, so that the concatenation of the two words, i.e. words[i] + words[j]
is a palindrome.
Example 1:
Given words
= ["bat", "tab", "cat"]
Return [[0, 1], [1, 0]]
The palindromes are ["battab", "tabbat"]
Example 2:
Given words
= ["abcd", "dcba", "lls", "s", "sssll"]
Return [[0, 1], [1, 0], [3, 2], [2, 4]]
The palindromes are ["dcbaabcd", "abcddcba", "slls", "llssssll"]
Credits:
Special thanks to @dietpepsi for adding this problem and creating all test cases.
The idea is for each of the word, find the strings that can be added before or after to form a palindrome, and generate the results.
For example "abcd"
before abcd we could add dcba to form dcbaabcd,
and add dcb to form dcbabcd.
after abcd we could add dcba to form abcddcba
and add cba to form abcdcba.
And we check whether dcba,dcb,dcba,cba is in the list, if there is a occurence we add (i,j) or (j,i) to the result.
But there would be duplicates if abcd and dcba all the in the list, because for after abcd we will find dcba, and for before dcba we will find abcd.
what we could do is in whether the getBefore or getAfter, we do not return the reverse of the string s to avoid the duplicates.
Code:
public class Solution {
public List<List<Integer>> palindromePairs(String[] words) {
List<List<Integer>> ret = new ArrayList<>();
HashMap<String,HashSet<Integer>> hm = new HashMap<>();
for(int i = 0; i < words.length; i++){
hm.computeIfAbsent(words[i], k->new HashSet<Integer>()).add(i);
}
for(int i = 0; i < words.length; i++){
String s = words[i];
List<String> before = getBefore(s);
List<String> after = getAfter(s);
for(String bf : before){
for(int j : hm.getOrDefault(bf,new HashSet<Integer>())){
List<Integer> temp = new ArrayList<>();
if(i == j) continue;
temp.add(j);
temp.add(i);
ret.add(temp);
}
}
for(String af : after){
for(int j : hm.getOrDefault(af,new HashSet<Integer>())){
List<Integer> temp = new ArrayList<>();
if(i == j) continue;
temp.add(i);
temp.add(j);
ret.add(temp);
}
}
}
return ret;
}
public List<String> getAfter(String s){
List<String> ret = new ArrayList<>();
String rev = new StringBuilder(s).reverse().toString();
for(int i = 0; i <= s.length(); i++){
if(rev.substring(0,i).equals(s.substring(s.length() - i,s.length()))){
ret.add(rev.substring(i,s.length()));
}
}
return ret;
}
public List<String> getBefore(String s){
List<String> ret = new ArrayList<>();
String rev = new StringBuilder(s).reverse().toString();
for(int i = 1; i <= s.length(); i++){ // i start from 1 to avoid duplicates
if(s.substring(0,i).equals(rev.substring(s.length() - i,s.length()))){
ret.add(rev.substring(0,s.length() - i));
}
}
return ret;
}
}