您的位置:首页 > 大数据 > 人工智能

Hard-题目47:336. Palindrome Pairs

2016-05-31 23:52 393 查看
题目原文:

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个元素的单词列表,单词长度不超过k,很容易想到暴力解法,复杂度为O(kn^2),提交显然tle。

看到discuss中一位大神的解法,大致理解如下:

把每个字符串翻转后构建Trie树,trie树的每个节点增加两个信息:

int index,如果该点是单词,则记录在原列表的下标,如果不是,该值为-1

List list, 这个列表有点难理解,先摘抄原文如下:

Here I take another strategy: add an integer list to each TrieNode; the list will record the indices of all words satisfying the following two conditions: each word has a suffix represented by the current Trie node; the rest of the word forms a palindrome.

我是这样理解这段话的:list记录的是索引值,其中索引值对应的单词均以这个Trie节点为后缀(因为这棵trie树是反向构造的,所以这点代表的前缀对应为单词的后缀),并且该字符串去掉这一点对应串的后缀是个回文串。

构建完这样的trie树后,遍历单词列表,带上下标i放到trie树中搜索,因为trie树是反着存的,所以如果存在这样的回文串,必定能正向查找到一个节点j(例如列表里有abc和cba两个词,则trie树里存了abc这个节点),再看trie树中的abc节点的list,其中记录了所有以cba为结尾,剩下部分是回文串的下标,很显然这些字符串前面加上abc必是回文串!!!!!!!!

这里有两个trick,第一个是trie树的root节点是空,但列表中可能有空串,这样的情况下只需要看words[i]是不是回文即可。第二个trick是i本身若是回文串,则(i,i)也是回文的,但观察标程的输出发现i不能等于j(这个题目好像没有说清,不知道是不是我没理解好题意)。

源码:(language:java)

public class Solution {
class TrieNode {
TrieNode[] next;
int index;
List<Integer> list;
TrieNode() {
next = new TrieNode[26];
index = -1;
list = new ArrayList<>();
}
}
public List<List<Integer>> palindromePairs(String[] words) {
List<List<Integer>> res = new ArrayList<>();
TrieNode root = new TrieNode();
for (int i = 0; i < words.length; i++)
addWord(root, words[i], i);
for (int i = 0; i < words.length; i++)
search(words, i, root, res);
return res;
}
private void addWord(TrieNode root, String word, int index) {
for (int i = word.length() - 1; i >= 0; i--) {
if (root.next[word.charAt(i) - 'a'] == null)
root.next[word.charAt(i) - 'a'] = new TrieNode();
if (isPalindrome(word, 0, i))
root.list.add(index);
root = root.next[word.charAt(i) - 'a'];
}
root.list.add(index);
root.index = index;
}
private void search(String[] words, int i, TrieNode root, List<List<Integer>> list) {
for (int j = 0; j < words[i].length(); j++) {
if (root.index >= 0 && root.index != i && isPalindrome(words[i], j, words[i].length() - 1))
list.add(Arrays.asList(i, root.index));
root = root.next[words[i].charAt(j) - 'a'];
if (root == null) return;
}

for (int j : root.list) {
if (i != j)
list.add(Arrays.asList(i, j));
}
}
private boolean isPalindrome(String word, int i, int j) {
while (i < j) {
if (word.charAt(i++) != word.charAt(j--))
return false;
}
return true;
}
}


成绩:

63ms

Cmershen的碎碎念:

好题,很考验数据结构和算法设计能力。trie树是acm中的一种比较基础的数据结构,这题借助反向构建trie树来寻找回文串,应该在求职机试中会是难题,而且把如果数据出严一点,个人感觉放在acm竞赛里面也绝对不是一道水题。

Leetcode是面向面试的,如果哪位大仙能在面试的短时间和高心理压力下想得到这个算法,真的是大神了……
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: