LeetCode 336——回文对

一、题目介绍

给定一组唯一的单词, 找出所有不同 的索引对(i, j),使得列表中的两个单词, words[i] + words[j] ,可拼接成回文串。

示例 1:

输入: ["abcd","dcba","lls","s","sssll"]
输出: [[0,1],[1,0],[3,2],[2,4]] 
解释: 可拼接成的回文串为 ["dcbaabcd","abcddcba","slls","llssssll"]
示例 2:

输入: ["bat","tab","cat"]
输出: [[0,1],[1,0]] 
解释: 可拼接成的回文串为 ["battab","tabbat"]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/palindrome-pairs
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、 解题思路

在数组中判断某一字符串能否与其他字符串组成回文对,主要分为以下几种情况:

假设当前字符串为s1

(1)如果s1本身为回文串,可以和空字符串组成回文对。

(2)如果s1反转之后,可以在数组中找到相同的字符串,则可以组成回文对,注意反转之后不能是自己(避免本身为回文串的情况)。

(3)如果s1可以找到一个分界点,分界点前的字符串为回文串,分界点后的字符串反转之后可以在数组中找到,则可以组成回文对。

(4)如果s1可以找到一个分界点,分界点后的字符串为回文串,分界点前的字符串反转之后可以在数组中找到,则可以组成回文对。

除了需要考虑以上内容之外,需要找到一种数据结构,能够快速查找某一字符串是否存在。

本文尝试了两种数据结构,第一种:HashMap(参考大佬);第二种:Trie树

三、解题代码

(1)HashMap

class Solution {
public:
    bool ispalindrome(string s)
    {
        if(s.empty()) return true;
        for(int i=0;i<s.size()-1-i;i++) 
            if(s[i]!=s[s.size()-1-i]) 
                return false;
        return true;
    }
    vector<vector<int>> palindromePairs(vector<string>& words) {
        vector<vector<int>>res;
        unordered_set<int>s;
        unordered_map<string,int>mp;
        for(int i=0;i<words.size();i++)
        {
            mp[words[i]]=i;
            s.insert(words[i].size());
        }
        for(int i=0;i<words.size();i++)
        {
            //将字符串反转在mp中查找是否存在,同时确保不能找到自己
            string w=words[i];
            reverse(w.begin(),w.end());
            if(mp.find(w)!=mp.end()&&mp[w]!=i)
            {
                vector<int>cur;
                cur.push_back(i);
                cur.push_back(mp[w]);
                res.push_back(cur);
            }
            
            //判断字符串的前缀或者后缀是不是回文串,回文串本身作为自己的前缀和后缀可以与空字符组组成回文对
            for(int j=words[i].size()-1;j>=0;j--)
            {
                //首先判断 要查找的字符串长度在set中是否存在,不存在可直接pass,剪枝
                if(s.find(j)==s.end()) 
                    continue;
                string w1=words[i].substr(0,j);
                if(ispalindrome(words[i].substr(j))) //判断后缀
                {
                    reverse(w1.begin(),w1.end());
                    if(mp.find(w1)!=mp.end())
                    {
                        vector<int>cur;
                        cur.push_back(i);
                        cur.push_back(mp[w1]);
                        res.push_back(cur);
                    }
                }
                string w2=words[i].substr(words[i].size()-j);
                if(ispalindrome(words[i].substr(0,words[i].size()-j))) //判断前缀
                {
                    reverse(w2.begin(),w2.end());
                    if(mp.find(w2)!=mp.end()){
                        vector<int>cur;
                        cur.push_back(mp[w2]);
                        cur.push_back(i);
                        res.push_back(cur);
                    }
                }
            }
        }
        return res;
    }
};

(2)Trie

struct Node
{
    bool isword;
    int pos;
    unordered_map<char, Node*> mp;
    Node()
    {
        isword = false;
    }
};

class Trie
{
private: 
    Node* root;
public:
    Trie()
    {
        root = new Node();
    }
    void insert(string word, int n)
    {
        Node* p = root;
        for(int i = 0; i < word.size(); ++i)
        {
            if(p->mp[word[i]] == NULL)
                p->mp[word[i]] = new Node();
            p = p->mp[word[i]];
        }
        p->isword = true;
        p->pos = n;
    }
    
    int search(string word)
    {
        Node* p = root;
        for(int i = 0; i < word.size(); ++i)
        {
            if(p->mp[word[i]] == NULL)
                return -1;
            p = p->mp[word[i]];
        }
        if(p->isword)
            return p->pos;
        return -1;
    }
    
};
class Solution {
public:
    bool isPalindrome(string word)
    {
        int n = word.size();
        for(int i = 0; i < n/2; ++i)
        {
            if(word[i] != word[n-1-i])
                return false;
        }
        return true;
    }
    vector<vector<int>> palindromePairs(vector<string>& words) {
        Trie t;
        unordered_map<string, int> mp;
        unordered_set<int> s;
        //将所有单词添加到前缀树中
        for(int i = 0; i < words.size(); ++i)
        {
            t.insert(words[i], i);
            s.insert(words[i].size());
        }
        
        vector<vector<int>> res;
        int rtn = -1;
        for(int i = 0; i < words.size(); ++i)
        {
            //将当前字符串反转后在前缀树中查找  (1)
            string str = words[i];
            reverse(str.begin(), str.end());
            rtn = t.search(str);
            if(rtn != -1 && rtn != i)  //规避本身为回文串,反转之后找到自身的情况
            {
                vector<int> vec;
                vec.push_back(i);
                vec.push_back(rtn);
                res.push_back(vec);
            }
                
            //确定当前字符串的前缀或者是否为回文串, 将前缀和后缀的范围扩展到可以包括字符串本身
            for(int j = words[i].size()-1; j >= 0; --j)
            {
                //剪枝 j代表将要查找的字符串长度
                if(s.find(j) == s.end()) 
                    continue;
                
                string str2 = words[i].substr(0, j);
                if(isPalindrome(words[i].substr(j)))  //判断后缀子串
                {
                    reverse(str2.begin(), str2.end());
                    rtn = t.search(str2);
                    if(rtn != -1)
                    {
                        vector<int> vec;
                        vec.push_back(i);
                        vec.push_back(rtn);
                        res.push_back(vec);
                    }
                } 
                
                string str1 = words[i].substr(words[i].size()-j);
                if(isPalindrome(words[i].substr(0, words[i].size()-j)))  //判断前缀子串
                {
                    reverse(str1.begin(), str1.end());
                    int rtn = t.search(str1);
                    if(rtn != -1)
                    {
                        vector<int> vec;
                        vec.push_back(rtn);
                        vec.push_back(i);
                        res.push_back(vec);
                    }
                }
            }
                
                       
        } 
        return res;
    }
};

四、解题结果

(1)HashMap

(2)Trie树

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值