Palindromic对数组中的单词

时间:2018-02-17 07:11:59

标签: java algorithm palindrome

我使用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/

但是我仍然觉得很难理解这种方法。

由于

1 个答案:

答案 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]必须是回文。
    例如,取llssllss结尾,ll在回文结束。因此,s + lls是回文。

注意到这一点后,我们基本上需要一种有效的方法来检查某些words[i]是否以words[j]的反向结束,而words[i]的其余部分是回文。

这是使用Trie结构实现的,该结构在反向词上构建基数树。博客文章为单词Trie的构建"cbaaa", "bc", "abc"提供了一个很好的示例:

Trie for words <code>"cbaaa", "bc", "abc"</code>

Trie使搜索前缀非常有效。例如,搜索cbaabc的反向)会使节点以cbaaa开头。

我认为理解代码的主要问题是由于命名不佳的字段(并且代码通常有点混乱)。目前尚不清楚pospalins是什么,所以这可能会给您带来麻烦。

给定pos节点的

Trie只是由&#34; root&#34;中的节点序列形成的单词的索引。到给定节点。在上面的示例中,cbaaa的索引为0bc为索引1abc为索引2。相应的节点具有适当的pos值。

palins更有趣。在构建Trie到某个节点时,我们有一些共同的前缀。例如,当Trie构建到a中的节点c-b-a-a-a时,我们会使用公共前缀cba。但我们还需要快速检查的是,其余部分是回文。这是palins的用途。 palins保存单词的索引,这些单词以我们目前在构造中使用的公共前缀开头,其余单词是palindrom。在我们的示例中,cbaaa拥有cba和其余aa的明星是一个回文。因此,0cbaaa的索引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将包含0cbaaa中的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); } }); 其中一个结果。