题解 | #牛群编号的回文顺序II# Manacher算法
牛群编号的回文顺序II
https://www.nowcoder.com/practice/e887280579bb4d91934378ea359f632e
知识点
Manacher算法
思路
很经典的求最长回文子串的问题,一般来说有三种办法
- 动态规划 时间复杂度
- 中心扩展 时间复杂度
- Manacher算法 时间复杂度
这道题的范围 显然不可以使用
的算法,但是Manacher算法的难度远超面试难度。
以下代码为链表形式的Manacher算法。
时间复杂度
AC Code(C++)
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @return ListNode类
*/
int expand (const vector<ListNode*>& s, int left, int right) {
while (left >= 0 && right < s.size() && s[left]->val == s[right]->val) {
--left;
++right;
}
return (right - left - 2) / 2;
}
ListNode* maxPalindrome(ListNode* head) {
vector<ListNode*> s;
auto p = head;
while (p) {
s.emplace_back(p);
p = p->next;
}
int n = s.size();
int start = 0, end = -1;
vector<ListNode*> t = {new ListNode(-1)};
for (auto x : s) {
t.emplace_back(x);
t.emplace_back(new ListNode(-1));
}
t.emplace_back(new ListNode(-1));
s = t;
vector<int> arm_len;
int right = -1, j = -1;
for (int i = 0; i < s.size(); ++i) {
int cur_arm_len;
if (right >= i) {
int i_sym = j * 2 - i;
int min_arm_len = min(arm_len[i_sym], right - i);
cur_arm_len = expand(s, i - min_arm_len, i + min_arm_len);
} else {
cur_arm_len = expand(s, i, i);
}
arm_len.push_back(cur_arm_len);
if (i + cur_arm_len > right) {
j = i;
right = i + cur_arm_len;
}
if (cur_arm_len * 2 + 1 > end - start) {
start = i - cur_arm_len;
end = i + cur_arm_len;
}
}
vector<ListNode*> ans;
for (int i = start; i <= end; ++i) {
if (s[i]->val != -1) {
ans.emplace_back(s[i]);
}
}
if (ans.size() == n) return nullptr;
ans.back()->next = nullptr;
return ans.front();
}
};
查看8道真题和解析