题目: 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”]
题目翻译:给一个不重复的单词列表,从给的列表中找出所有不重复下标(i,j)的组合,使得words[i] + words[j]是一个回文字符串。
解析:这个题主要的难点在于时间的约束,经过测试,当复杂度是n^2时,是超时的。
复杂度为n^2的解法:
public List<List<Integer>> palindromePairs(String[] words) {
//复杂度为n^2时比较简单,只要两层遍历,然后把两次遍历元素链接,判断链接的字符串是否是回文的就可以了
List<List<Integer>> llRes =new ArrayList<>();
for(int i=0;i<words.length;i++){
for(int j=0;j<words.length;j++){
StringBuffer sb=new StringBuffer(words[i]).append(words[j]);
String str1=sb.toString();
String str2=sb.reverse().toString();
if(i!=j&&str1.equals(str2)){
List<Integer> listTmp=new ArrayList<>();
listTmp.add(i);
listTmp.add(j);
llRes.add(listTmp);
}
}
}
return llRes;
}
复杂度为n+m的解法:
public List<List<Integer>> palindromePairs(String[] words) {
List<List<Integer>> llRes =new ArrayList<>();
HashMap<String,Integer> hashMap=new HashMap<>();
//因为words是不重复,所以用hashMap存储以word为key,以下标为value
for(int i=0;i<words.length;i++){
hashMap.put(words[i],i);
}
//对于hashMap里面的每个元素有以下三种情况会有形成回文字符串的可能
for (String key : hashMap.keySet()) {
//第一种可能,如果当前map的key是个回文字符串,那么只要hashMap中有空的字符串"",
//那么这两个元素分别在左右,可以形成两个下标组合,当然因为i!=j,所以当前key不能和""相同
if(hashMap.containsKey("")&&isPalindrome(key)&&hashMap.get("")!=hashMap.get(key)){
List<Integer> tmp=new ArrayList<>();
tmp.add(hashMap.get(key));
tmp.add(hashMap.get(""));
List<Integer> tmp2=new ArrayList<>();
tmp2.add(hashMap.get(""));
tmp2.add(hashMap.get(key));
llRes.add(tmp);
llRes.add(tmp2);
}
//第二种可能,如果当前key的反转字符串在hashMap中,那么当前value和取反字符串的value,
//可以组合成一个下标组合
String strReverse=new StringBuffer(key).reverse().toString();
if(hashMap.containsKey(strReverse)&&hashMap.get(strReverse)!=hashMap.get(key)){
List<Integer> tmp=new ArrayList<>();
tmp.add(hashMap.get(key));
tmp.add(hashMap.get(strReverse));
llRes.add(tmp);
}
//第三种可能,比较复杂一点。这个要把当前key分成左右两个部分,
//左边部分left从1个元素到key.size-1个元素,
//右边部分right从key.size-1到1个元素
for(int i=1;i<key.length();i++){
String left = key.substring(0,i);
String right = key.substring(i,key.length());
//如果left是一个回文字符串,那么如果hashMap中存在right的反转字符串。
//那么当前value和right的反转字符串的value可以组成一个下标组合
if(isPalindrome(left)){
String rightReverse=new StringBuffer(right).reverse().toString();
if(hashMap.containsKey(rightReverse)&&hashMap.get(rightReverse)!=hashMap.get(key)){
List<Integer> tmp=new ArrayList<>();
tmp.add(hashMap.get(rightReverse));
tmp.add(hashMap.get(key));
llRes.add(tmp);
}
}
//如果right是一个回文字符串,那么如果hashMap中存在left的反转字符串。
//那么当前value和left的反转字符串的value可以组成一个下标组合
if(isPalindrome(right)){
String leftReverse=new StringBuffer(left).reverse().toString();
if(hashMap.containsKey(leftReverse)&&hashMap.get(leftReverse)!=hashMap.get(key)){
List<Integer> tmp=new ArrayList<>();
tmp.add(hashMap.get(key));
tmp.add(hashMap.get(leftReverse));
llRes.add(tmp);
}
}
}
}
return llRes;
}
//判断一个字符串是否是回文字符串
public boolean isPalindrome(String str){
for(int i=0;i<str.length()/2;i++){
if(str.charAt(i)!=str.charAt(str.length()-1-i)){
return false;
}
}
return true;
}