336. 回文对
首先想出蛮力算法
-
所谓蛮力算法,就是枚举每一个字符串,然后判断他们加起来是不是一个回文。
-
这个方法的代码如下,我看题解里有人说在别的语言中使用蛮力算法是可以通过的,但是C++中使用蛮力算法就会超时,但是通过蛮力算法来启发思路还是蛮不错的。
-
时间复杂度O(n^2 * m), m为字符串平均长度
class Solution {
public:
//蛮力算法
vector<vector<int>> palindromePairs(vector<string>& words) {
vector<vector<int>> sto;
for (int i(0); i < words.size(); i++)
for (int j(0); j < words.size(); j++) {
if (i == j) continue;
if (isPalindrome(words[i], words[j]))
sto.push_back({i, j});
}
return sto;
}
bool isPalindrome(string a, string b) {
string all = a + b;
for (int i(0); i < all.size(); i++) {
if (*(all.begin() + i) != *(all.end() - i - 1))
return false;
}
return true;
}
};
使用HaspMap来进行优化
- 对于两个字符串a和b而言,有三种可能。
- len(a) == len(b):这种情况下a是b的翻转
- len(a) > len(b):这种情况下,a是可以拆分成两部分的,一部分自己就是一个回文,另一部分可能是其他字符串的回文,我们需要做的就是找到这个其他的字符串。
- len(a) < len(b):同上。
- 思路:我们枚举字符串的每一个前缀和后缀,判断其是否为回文串。如果是回文串,我们就查询其剩余部分的翻转是否在给定的字符串序列中出现即可。
- 所以,我们就需要一个存储翻转字符串的数据结构,这里使用HashMap,还有一个字典树的做法,我没有搞懂。
- 代码如下,和官方的是差不多的,我根据自己的理解添加了些许注释,希望对你有帮助。
- 时间复杂度:O(n * m^2)
class Solution {
private:
vector<string> wordsRev;
unordered_map<string_view, int> indices;
public:
//在indices中寻找前缀(在indices中本来就是倒序的,如果找到和前缀一样的了,就说明找到倒序的了)
int findWord(const string_view& s, int left, int right) {
auto iter = indices.find(s.substr(left, right - left + 1));
return iter == indices.end()? -1: iter->second;
}
//判断当前string_view是否是回文
bool isPalindrome(const string_view& s, int left, int right) {
int len = right - left + 1;
for (int i(0); i < len / 2; i++)
if (s[left + i] != s[right - i])
return false;
return true;
}
vector<vector<int>> palindromePairs(vector<string>& words) {
int n = words.size();
//将每一个word进行翻转,并存放在wordsRev
for (const string& word: words) {
wordsRev.push_back(word);
reverse(wordsRev.back().begin(), wordsRev.back().end());
}
//将翻转后的字符串放到indices中
for (int i(0); i < n; i++)
indices.emplace(wordsRev[i], i);
//用于存放返回结果
vector<vector<int>> ret;
for(int i(0); i < n; i++) {
int m = words[i].size();
if (!m) continue; //如果当前word的长度为0,则继续
//使用string_view可以避免频繁的字符串拷贝
string_view wordView(words[i]);
for (int j(0); j <= m; j++) {
//如果后缀是回文,就去indices里面寻找前面的剩余部分
if (isPalindrome(wordView, j, m - 1)) {
int left_id = findWord(wordView, 0, j - 1);
//剩余部分的字符串在indices中存在同时也不是自己
if (left_id != -1 && left_id != i)
ret.push_back({i, left_id});
}
//如果前缀是回文,那就去找后缀
if (j && isPalindrome(wordView, 0, j - 1)) {
int right_id = findWord(wordView, j, m - 1);
if (right_id != -1 && right_id != i)
ret.push_back({right_id, i});
}
}
}
return ret;
}
};