leetcode 336. Palindrome Pairs

本文探讨了如何解决回文串配对问题,通过遍历和优化的方式寻找字符串数组中可以形成回文串的配对,并介绍了使用哈希表进行优化的方法。

一开始的思路就是遍历所有的pair,判断这个pair拼接起来是不是回文串,首先,还是拿例子说明

["abcd", "dcba", "lls", "s", "sssll"] 答案:[[0, 1], [1, 0], [3, 2], [2, 4]]。当我遍历到i=2,j=4的时候,即words[i] = "lls",words[j] = "sssll",由于words[i] = "lls"的长度是小于words[j] = "sssll",所以要将”sssll“拆分成两部分,有一部分必须是”lls“的反转串,剩下的那一部分必须是回文串,这样的话words[j] = "sssll"才能拼到words[i] = "lls"的右边,这种情况是len(words[i]) <= len(words[j]);另外一种情况是len(words[i]) > len(words[j]),比如当遍历到i=4,j=2的时候,即words[i] = "sssll",words[j] = "lls",此时words[i] = "sssll"的长度是大于words[j] = "lls",处理的方法与前一种情况类似。实现代码如下:

class Solution {
public:
    vector<vector<int>> palindromePairs(vector<string>& words) {
        vector<vector<int>> resultVec;
        for (int i = 0; i < words.size(); i++) {
            for (int j = 0; j < words.size(); j++) {
                if (i == j) {
                    continue;
                }
                bool palidromeFlag = true, reverseFlag = true;
                if (words[i].size() <= words[j].size()) {
                    palidromeFlag = isPalidrome(words[j].substr(0, int(words[j].size()) - int(words[i].size())));
                    reverseFlag = isReverse(words[i], words[j].substr(int(words[j].size()) - int(words[i].size()), int(words[i].size())));
                } else {
                    palidromeFlag = isPalidrome(words[i].substr(int(words[j].size()), int(words[i].size()) - int(words[j].size())));
                    reverseFlag = isReverse(words[i].substr(0, int(words[j].size())), words[j]);
                }
                if (palidromeFlag && reverseFlag) {
                    vector<int> singleResult = {i, j};
                    resultVec.push_back(singleResult);
                }
            }
        }
        return resultVec;
    }
private:
    bool isPalidrome(string str) {
        int midInd = int(str.size() - 1) / 2;
        int leftInd = int(str.size()) % 2 == 0?midInd:midInd-1;
        int rightInd = midInd + 1;
        while (leftInd >= 0 && rightInd < str.size()) {
            if (str[leftInd] != str[rightInd]) {
                return false;
            }
            leftInd--;
            rightInd++;
        }
        return true;
    }
    bool isReverse(string leftStr, string rightStr) {
        int strSize = int(leftStr.size());
        for (int i = 0; i < strSize; i++) {
            if (leftStr[i] != rightStr[strSize - 1 - i]) {
                return false;
            }
        }
        return true;
    }
};

但是提交上去遇到这个case的时候TLE了。改进思路,每次遍历的时候都要算一次isReverse,如果用一个哈希表存放candidates的反转字符串,比对的时候直接访问哈希表就可以了,用空间换时间。而且这样的话就不需要O(N^2)的遍历,只需要O(N)遍历的基础上遍历所有可能反转字符串。要注意空字符串的问题

class Solution {
public:
    vector<vector<int>> palindromePairs(vector<string>& words) {
        unordered_map<string, int> hashTable;
        for (int i = 0; i < words.size(); i++) {
            string reverseStr = words[i];
            reverse(reverseStr.begin(), reverseStr.end());
            hashTable[reverseStr] = i;
        }
        vector<vector<int>> resultVec;
        for (int i = 0; i < words.size(); i++) {
            if (words[i].size() == 0) {
                for (int j = 0; j < words.size(); j++) {
                    if (j != i && isPalidrome(words[j])) {
                        resultVec.push_back({i, j});
                    }
                }
            }
            for (int j = 0; j < words[i].size(); j++) {
                string leftStr = words[i].substr(0, j), rightStr = words[i].substr(j, words[i].size() - j);
                //分为在左拼接,在右拼接,这样就不用O(N^2)遍历
                //在右拼接,还要考虑到candidate本身就是回文串的情况,加多一个判断条件
                if (isPalidrome(rightStr) && hashTable.find(leftStr) != hashTable.end() && hashTable[leftStr] != i) {
                    resultVec.push_back({i, hashTable[leftStr]});
                }
                //在左拼接
                if (isPalidrome(leftStr) && hashTable.find(rightStr) != hashTable.end() && hashTable[rightStr] != i) {
                    resultVec.push_back({hashTable[rightStr], i});
                }
            }
        }
        return resultVec;
    }
private:
    bool isPalidrome(string str) {
        int midInd = int(str.size() - 1) / 2;
        int leftInd = int(str.size()) % 2 == 0?midInd:midInd-1;
        int rightInd = midInd + 1;
        while (leftInd >= 0 && rightInd < str.size()) {
            if (str[leftInd] != str[rightInd]) {
                return false;
            }
            leftInd--;
            rightInd++;
        }
        return true;
    }
};
据说还有就TRIE的做法。

### LeetCode 336 Palindrome Pairs 解析 对于给定单词列表 `words`,目标是从该列表中找出所有的索引对 `(i, j)`,使得由这两个单词组成的字符串是回文串。此问题可以通过构建字典树(Trie)来高效解决[^1]。 #### 方法一:暴力法 最直观的方法是对每一对可能的组合进行两两比较,检查它们连接后的字符串是否为回文串。这种方法的时间复杂度较高,达到 O(n^2 * k),其中 n 是数组长度而 k 表示平均单词长度。虽然简单易懂但是效率低下,在数据量较大时表现不佳。 #### 方法二:哈希表优化方案 为了提高性能,可以利用哈希表存储反转后的单词及其对应的下标位置。遍历每一个单词 w_i 并尝试将其拆分为前后缀 s 和 p (即 w_i = sp 或者 w_i=p+s) ,如果前缀s本身构成一个回文串,则只需要查询是否存在另一个单词等于p的逆序;同理当后缀p是一个有效的回文串时也做同样的处理。这样做的好处是可以显著减少不必要的匹配次数并加快检索速度。 ```cpp class Solution { public: unordered_map<string,int> mp; bool isPalindrome(string& str){ int l=0,r=str.length()-1; while(l<r && str[l]==str[r]) ++l,--r; return l>=r; } vector<vector<int>> palindromePairs(vector<string>& words) { vector<vector<int>> res; // 建立映射关系 for(int i=0;i<words.size();++i) mp[string(words[i].rbegin(),words[i].rend())]=i; for(int i=0;i<words.size();++i){ string word=words[i]; if(mp.count(word)&&mp[word]!=i) res.push_back({min(i,mp[word]),max(i,mp[word])}); for(int j=1;j<=word.size();++j){ auto prefix=word.substr(0,j); auto suffix=word.substr(j); if(isPalindrome(prefix) && mp.count(suffix)) res.push_back({mp[suffix],i}); if(isPalindrome(suffix) && mp.count(prefix)) res.push_back({i,mp[prefix]}); } } // 删除重复项 sort(res.begin(),res.end()); res.erase(unique(res.begin(),res.end()),res.end()); return res; } }; ``` 上述代码实现了基于哈希表的方式寻找所有符合条件的索引对,并通过去重操作确保最终结果不含有冗余条目。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值