336. Palindrome Pairs

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"]

Credits:
Special thanks to @dietpepsi for adding this problem and creating all test cases.

Solution

HashMap, time O(n * k ^ 2), space O(n)

其实一开始就可以确认的是,O(n ^ 2)的解法一定是不能AC的,所以很自然会想到用O(n)去遍历words,对于每个word,我们用O(k)时间对其做切割,那么再用O(k)的时间去构造它的palindrome pair,然后查看它是否存在即可。但是如何构造palindrome pair呢?对于"ab"这种,是否需要构造"bbb....bbba"这种pair呢?看起来的无穷无尽让我想不通。

后来发现这样做就可以解决我的困扰:

  • 对于每个word来说,不仅为它添加suffix,也为它添加prefix,这样在处理word "ab"的时候只需考虑palindrome "aba", "bab"即可,等到处理word "bbba"的时候,自然会考虑到"bbbabbb", "abbbbbba", "abbbba", "abbba" 这种palindrome。

palindrome最大的特性就是对称,按长度的奇偶可以分为str,char,reverse(str)还有 str,reverse(str)型。
我们有一个str,在i这个位置进行切分,得到的前半部分是一个palindrome. 比如"lls", 变成"ll", "s".
已知"ll"是palindrome,我们只需要知道reverse("s") 放到前边就可以了。
reverse("s")"ll""s", 即reverse(str) PalindromeSubString str的类型。

还有一种就是后半部分是palindrome, 我们找到前半部分的reverse,拼到后面。["abcdc", "ba"]。
"cdc"是palindrome, reverse(ab) 就是 "ba", 我们有这样的string出现过。

代码细节就是有一个isPalindrome的helper function。 一个hashmap存入所有 paris加速查询。
容易出bug的两个地方, 以["abcd", "dcba", "lls", "s", "sssll"]为例。

  1. 如果一个str本身就是panlindrome,reverse就是本身,一定在hashmap里,去重的方法就是判断map.get(reverse(str)) != i.
    [[1,0],[0,1],[3,2],[3,3],[2,4]]
  2. 我们在切割str的时候,j ==0时str变成""和"str", j == str.length()的时候str变成"str"和""。
    "abcd", "dcba"这两个互为reverse的string, 在"abcd"尾部加上"dcba"也就是在"dcba"头部加上"abcd".
    所以后部分不能为空,否则就和头部为空的情况重复了。
    [[1,0],[0,1],[0,1],[1,0],[3,2],[2,4]]
class Solution {
    public List> palindromePairs(String[] words) {
        Map map = new HashMap<>();
        for (int i = 0; i < words.length; ++i) {
            map.put(words[i], i);
        }
        
        List> res = new ArrayList<>();
        for (int i = 0; i < words.length; ++i) {
            String word = words[i];
            int len = word.length();
            
            for (int j = 0; j <= len; ++j) {
                String s1 = word.substring(0, j);
                String s2 = word.substring(j);
                
                if (isPalindrome(s1)) {
                    String s2rvs = new StringBuilder(s2).reverse().toString();
                    if (map.containsKey(s2rvs) && map.get(s2rvs) != i) {
                        List pair = new ArrayList<>();
                        pair.add(map.get(s2rvs));
                        pair.add(i);
                        res.add(pair);
                    }
                }
                
                if (!s2.isEmpty() && isPalindrome(s2)) {    // avoid duplicates
                    String s1rvs = new StringBuilder(s1).reverse().toString();
                    if (map.containsKey(s1rvs) && map.get(s1rvs) != i) {
                        List pair = new ArrayList<>();
                        pair.add(i);
                        pair.add(map.get(s1rvs));
                        res.add(pair);
                    }
                }
            }
        }
        
        return res;
    }
    
    private boolean isPalindrome(String s) {
        int left = 0;
        int right = s.length() - 1;
        
        while (left < right && s.charAt(left) == s.charAt(right)) {
            ++left;
            --right;
        }
        
        return left >= right;
    }
}

你可能感兴趣的:(336. Palindrome Pairs)