Leetcode 336. Palindrome Pairs

本文介绍了一种算法,用于从给定的唯一单词列表中找出所有可能的配对,使得两个单词的拼接形成回文。通过使用哈希表和巧妙地处理空字符串及自身回文的情况,有效地解决了重复问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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:

Input: ["abcd","dcba","lls","s","sssll"]
Output: [[0,1],[1,0],[3,2],[2,4]] 
Explanation: The palindromes are ["dcbaabcd","abcddcba","slls","llssssll"]

Example 2:

Input: ["bat","tab","cat"]
Output: [[0,1],[1,0]] 
Explanation: The palindromes are ["battab","tabbat"]

------------------------------------------------------------------------------------------------

能想到把前后缀拿去查Hash表,这题就成功了一半,另外一半是对于空串和本身回文的处理。直接来会有重复,如以下代码,暂时没有太简洁的去重方式list(set(lst))要求lst里面不能包含list,所以只能转成tuple来玩:

class Solution:
    def palindromePairs(self, words):
        palin_idx = []
        pos = {}
        for idx, word in enumerate(words):
            pos[word[::-1]] = idx
        dup = []

        for idx, word in enumerate(words):
            wl = len(word)
            for i in range(0, wl + 1):
                left = word[:i]
                right = word[i:] if i < wl else ''
                if (left == left[::-1] and right in pos and idx != pos[right]):
                    dup.append([pos[right], idx])
                if (right == right[::-1] and left in pos and idx != pos[left]):
                    dup.append([idx, pos[left]])
        res = []
        dupset = set()
        for item in dup:
            if (tuple(item) not in dupset):
                dupset.add(tuple(item))
                res.append(item)
        return res
s = Solution()
print(s.palindromePairs(["abcd","dcba","lls","s","sssll"]))

另外一种玩法是,把空和本身回文的单独拿出来考虑,注意注释那行的问题:

class Solution:
    def palindromePairs(self, words):
        pos = {}
        palin = []
        for idx, word in enumerate(words):
            pos[word[::-1]] = idx
            if (word == word[::-1]):
                palin.append(idx)

        res = []
        for idx, word in enumerate(words):
            wl = len(word)
            if (wl == 0):
                for i in palin:
                    if (i != idx):
                        res.append([idx, i])
            else:
                for i in range(wl):
                    left,right = word[:i],word[i:] #left可能为空,right不可能为空
                    if (left == left[::-1] and right in pos and idx != pos[right]):
                        res.append([pos[right], idx])
                    if (right == right[::-1] and left in pos and idx != pos[left]):
                        res.append([idx, pos[left]])
        return res                    

s = Solution()
print(s.palindromePairs(["a",""]))

 

### 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、付费专栏及课程。

余额充值