我使用Trie找到了回文对问题的代码。
public static class Trie {
int pos;
Trie[] nodes; // consider xyxabc. if current trie is 'a'. Then a.nodes has information. It means string after a is palindrome
List<Integer> palins;
public Trie() {
pos = -1;
nodes = new Trie[26];
palins = new ArrayList<>();
}
}
public static void add(Trie root, String word, int pos) {
for (int i = word.length() - 1; i >= 0; i--) {
char ch = word.charAt(i);
if (isPalindrome(word, 0, i)) { // check if substring(0, i) is palindrome.
root.palins.add(pos);
}
if (root.nodes[ch - 'a'] == null) {
root.nodes[ch - 'a'] = new Trie();
}
root = root.nodes[ch - 'a'];
}
root.pos = pos; // if it is xyxcba. Until now, the node should be at x.
root.palins.add(pos);
}
public static void search(Trie root, String[] words, int i, List<List<Integer>> ans) {
int len = words[i].length();
for (int j = 0; j < len && root != null; j++) {
if (root.pos >= 0 && i != root.pos && isPalindrome(words[i], j, len - 1)) {
ans.add(Arrays.asList(new Integer[] {i, root.pos}));
}
char ch = words[i].charAt(j);
root = root.nodes[ch - 'a'];
}
if (root != null && root.palins.size() > 0) { // assume 'xyxabc' is in trie, now try 'cba'
for (int j : root.palins) {
if (j != i) {
ans.add(Arrays.asList(new Integer[] {i, j}));
}
}
}
}
public static List<List<Integer>> palindromePairs(String[] words) {
List<List<Integer>> ans = new ArrayList<>();
Trie trie = new Trie();
for (int i = 0; i < words.length; i++) {
add(trie, words[i], i);
}
for (int i = 0; i < words.length; i++) {
search(trie, words, i, ans);
}
return ans;
}
public static boolean isPalindrome(String str, int i, int j) {
while (i < j) {
if (str.charAt(i++) != str.charAt(j--)) {
return false;
}
}
return true;
}
任何人都可以帮助我理解,我们在添加方法中尝试做什么。
if (isPalindrome(word, 0, i)) { // check if substring(0, i) is palindrome.
root.palins.add(pos);
}
在FOR循环之外,为什么我们需要添加:
root.palins.add(pos);
我在这里看到了这段代码: http://www.allenlipeng47.com/blog/index.php/2016/03/15/palindrome-pairs/
但是我仍然觉得很难理解这种方法。
由于
答案 0 :(得分:4)
我认为您链接到的博客文章并不能很好地解释解决方案的核心理念。这可能使得理解代码变得困难。
让我们从问题开始(因为你没有引用它):
给出一个独特单词列表。找到给定列表中的所有不同索引
(i, j)
对,以便两个单词的串联,即words[i] + words[j]
是回文。示例1:给定
words = ["bat", "tab", "cat"]
返回[[0, 1], [1, 0]]
回文是["battab", "tabbat"]
示例2:给定
words = ["abcd", "dcba", "lls", "s", "sssll"]
返回[[0, 1], [1, 0], [3, 2], [2, 4]]
回文是["dcbaabcd", "abcddcba", "slls", "llssssll"]
两个单词words[i]
和words[j]
何时满足words[i] + words[j]
作为回文的条件?
words[i]
和words[j]
的长度相等,则words[i]
必须等于words[j]
的反转(反之亦然)。words[i]
)更长,那么它必须以words[j]
的反向结束,其余words[i]
必须是回文。lls
和s
。 lls
以s
结尾,ll
在回文结束。因此,s
+ lls
是回文。注意到这一点后,我们基本上需要一种有效的方法来检查某些words[i]
是否以words[j]
的反向结束,而words[i]
的其余部分是回文。
这是使用Trie
结构实现的,该结构在反向词上构建基数树。博客文章为单词Trie
的构建"cbaaa", "bc", "abc"
提供了一个很好的示例:
此Trie
使搜索前缀非常有效。例如,搜索cba
(abc
的反向)会使节点以cbaaa
开头。
我认为理解代码的主要问题是由于命名不佳的字段(并且代码通常有点混乱)。目前尚不清楚pos
和palins
是什么,所以这可能会给您带来麻烦。
pos
节点的 Trie
只是由&#34; root&#34;中的节点序列形成的单词的索引。到给定节点。在上面的示例中,cbaaa
的索引为0
,bc
为索引1
,abc
为索引2
。相应的节点具有适当的pos
值。
palins
更有趣。在构建Trie
到某个节点时,我们有一些共同的前缀。例如,当Trie
构建到a
中的节点c-b-a-a-a
时,我们会使用公共前缀cba
。但我们还需要快速检查的是,其余部分是回文。这是palins
的用途。 palins
保存单词的索引,这些单词以我们目前在构造中使用的公共前缀开头,其余单词是palindrom。在我们的示例中,cbaaa
拥有cba
和其余aa
的明星是一个回文。因此,0
中cbaaa
的索引words
将添加到palins
。如果有类似cbatt
的内容,则其索引也会添加到palins
我们还需要考虑abc
- cba
这样的情况,其中没有余数。这是通过将单词的索引添加到最后一个符号的节点的palins
来完成的(这就是为什么您在root.palins.add(pos);
循环之外看到另一个for
的原因。)
现在应该或多或少地清楚搜索方法的工作原理:
*对于每个单词,搜索前缀,等于该单词反转。如果有这样的前缀,Trie
中会有一个对应的节点。
*如果找到此类节点,请选中palins
。这将有效地给出给定单词的回文对的工作指数。
例如,当我们搜索abc
时,我们会在a
中找到第一个c-b-a-a-a
节点。前缀cba
反过来等于abc
。此palins
节点的a
将包含0
(cbaaa
中的words
索引),因此我们将[2, 0]
作为public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
Context context;
private List<RecyclerClass>listdata ;
public RecyclerAdapter(Context context, List<StreetClass> list) {
this.listdata = list;
this.context = context;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.show_items, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
public void onBindViewHolder(final ViewHolder holder, int position) {
RecyclerClass Details = listdata.get(position);
Picasso.with(context).load(Details.getImgurl()).resize(120, 60).into(holder.ImageTextView);
holder.ImageTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Bundle bundle = new Bundle();
//add data to your bundle
bundle.putInt("id", position);
//create intent
Intent mainIntent = new Intent(context, ShowImage.class);
//add bundle to intent
mainIntent.putExtras(bundle);
//start activity
context.startActivity(mainIntent);
}
});
其中一个结果。