336-回文对

Description:

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]为回文。


问题分析

两种做法

  1. 假设当前字符串为words[i],对wordsi遍历,将其分成两部分,分别对两部分为回文的情况进行处理。例子,若words[i] = “aabc”,那么将其分成”aa”,”bc”,由于”aa”为回文,只需找到”bc”的逆字符串,将其插入”aabc”的前面就可以形成回文。
  2. 使用字典树。这种方法可以看一下这个链接,解释得非常详细:
    https://leetcode.com/problems/palindrome-pairs/discuss/79195/O(n*k2)-java-solution-with-Trie-structure

解法1:

class Solution {
    public List<List<Integer>> palindromePairs(String[] words) {
        List<List<Integer>> res = new ArrayList();
        if(words == null || words.length < 2)   return res;
        //存放字符串对应下标
        Map<String, Integer> map = new HashMap();

        int len = words.length;
        for(int i = 0;i < len;i++)  map.put(words[i], i);

        for(int i = 0;i < len;i++){
            for(int j = 0;j <= words[i].length();j++){
                //将words[i]分为两部分,分别对两部分为回文的情况进行处理
                String str1 = words[i].substring(0, j);
                String str2 = words[i].substring(j);
                if(isPalindrome(str1)){
                    String str2reverse = new StringBuilder(str2).reverse().toString();
                    if(map.containsKey(str2reverse) && map.get(str2reverse) != i){
                        List<Integer> list = new ArrayList();
                        list.add(map.get(str2reverse));
                        list.add(i);
                        res.add(list);
                    }
                }
                if(isPalindrome(str2) && str2.length() != 0){
                    String str1reverse = new StringBuilder(str1).reverse().toString();
                    if(map.containsKey(str1reverse) && map.get(str1reverse) != i){
                        List<Integer> list = new ArrayList();
                        list.add(i);
                        list.add(map.get(str1reverse));
                        res.add(list);
                    }
                }
            }
        }

        return res;
    }
    //判断str是否为回文
    public boolean isPalindrome(String str){
        int i = 0, j = str.length() - 1;

        while(i < j){
            if(str.charAt(i) != str.charAt(j))  return false;
            i++;
            j--;
        }

        return true;
    }
}

解法2(字典树)

class Solution {
    private class TrieNode{
        //存放字符串对应下标,若该节点在字典树中不是单词,则默认-1
        int index;
        //存放以当前字符串为后缀,剩余字符串为回文的字符串的下标
        List<Integer> list;
        TrieNode[] next;
        public TrieNode(){
            index = -1;
            list = new ArrayList();
            next = new TrieNode[26];
        }
    }
    public List<List<Integer>> palindromePairs(String[] words) {
        List<List<Integer>> res = new ArrayList();
        if(words == null || words.length == 0)  return res;

        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++) searchWord(root, i, words[i], res);

        return res;
    }
    private void addWord(TrieNode root, String word, int index){
        for(int i = word.length() - 1;i >= 0;i--){
            int j = word.charAt(i) - 'a';
            if(root.next[j] == null) root.next[j] = new TrieNode();
            //若word的子串[i, i]为回文,说明以word的子串[i + 1, word.length()]为后缀
            //且剩余字符串为回文
            if(isPalindrome(word, 0, i))    root.list.add(index);
            root = root.next[j];
        }
        root.index = index;
        root.list.add(index);
    }
    private void searchWord(TrieNode root, int i, String word, List<List<Integer>> res){
        for(int j = 0;j < word.length();j++){
            //若word[0, j - 1]与字典树该节点对应的字符串匹配
            //且word[j, word.length() - 1]为回文,说明(i, root.index)满足条件
            if(root.index >= 0 && root.index != i && isPalindrome(word, j, word.length() - 1)){
                res.add(Arrays.asList(i, root.index));
            }
            root = root.next[word.charAt(j)- 'a'];
            if(root == null)    return;
        }
        //注意这里
        for(int j : root.list){
            if(j == i)  continue;
            res.add(Arrays.asList(i, j));
        }
    }
    private boolean isPalindrome(String str, int start, int end){
        while(start < end){
            if(str.charAt(start++) != str.charAt(end--))    return false;
        }

        return true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值