惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
CERT Recently Published Vulnerability Notes
U
Unit 42
T
The Blog of Author Tim Ferriss
H
Hackread – Cybersecurity News, Data Breaches, AI and More
B
Blog RSS Feed
Microsoft Azure Blog
Microsoft Azure Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Securelist
L
Lohrmann on Cybersecurity
Blog — PlanetScale
Blog — PlanetScale
Recorded Future
Recorded Future
D
DataBreaches.Net
Spread Privacy
Spread Privacy
T
Threat Research - Cisco Blogs
I
Intezer
P
Palo Alto Networks Blog
Simon Willison's Weblog
Simon Willison's Weblog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
I
InfoQ
宝玉的分享
宝玉的分享
Security Latest
Security Latest
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
Threatpost
Cisco Talos Blog
Cisco Talos Blog
P
Proofpoint News Feed
博客园 - 司徒正美
H
Hacker News: Front Page
Y
Y Combinator Blog
爱范儿
爱范儿
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
NISL@THU
NISL@THU
月光博客
月光博客
有赞技术团队
有赞技术团队
Cloudbric
Cloudbric
酷 壳 – CoolShell
酷 壳 – CoolShell
G
Google Developers Blog
A
Arctic Wolf
博客园 - 【当耐特】
W
WeLiveSecurity
V
Visual Studio Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
V
V2EX
C
Cyber Attacks, Cyber Crime and Cyber Security
S
SegmentFault 最新的问题
The GitHub Blog
The GitHub Blog
The Cloudflare Blog
Stack Overflow Blog
Stack Overflow Blog

Louis C Deng's Blog

CS231n Lecture Note: Generative Models CS231n Lecture Note: Self-Supervised Learning CS231n Lecture Note: Large Scale Distributed Training 自動微分 | DIY 實現自己的 PyTorch From RNNs to Transformers CS231n Lecture Note VII: Recurrent Neural Networks Uncovering Batch & Layer Normalization CS231n Lecture Note VI: CNN Architectures and Training CS231n Lecture Note V: Convolution Neural Networks Basics Demystifying Softmax Loss: A Step-by-Step Derivation for Linear Classifiers Backpropagation: A Vector Calculus Perspective CS231n Lecture Note IV: Neural Networks and Backpropagation CS231n Lecture Note III: Optimization CS231n Lecture Note II: Linear Classifiers CS231n Lecture Note I: Image Classification CSAPP Cache Lab II: Optimizing Matrix Transposition CSAPP Cache Lab I: Let's simulate a cache memory! CS188 Search Lecture Notes III CS188 Search Lecture Notes II How to Use TouchID for Sudo Commands on macOS CS188 Search Lecture Notes I RECAP2025: 留白 CSAPP Bomb Lab 解析 x64 暫存器速查表 CSAPP Data Lab 解析 矩陣的 Modified Gram Schmidt 方法 聊一聊位掩碼(Bit Mask) 整數溢位與未定義行為 快速排序 幾種劃分方法討論 等待 記夢(DeepSeek 輔助創作) 午夜飛行 橋樑 黎明 或 2012 RECAP2024: 水檻臥聽雨 太陽、潮落 RECAP2023: 泡沫 題解 P1622 釋放囚犯 題解 P5888 傳球遊戲 殘陽似火 再會 飢餓藝術家 卡夫卡 Python 中的 zip() 和 enumerate() 泡沫 “救救孩子……”——談魯迅和《狂人日記》 想念 淺灘 蟬 · 夏 微風 觀星 浮塵 復活 【摘錄 | 轉載】普魯斯特 《追憶似水年華》第一卷 《在斯萬家那邊》(一) Time - Pink Floyd - The Dark Side of the Moon 【轉載】靜夜思變調 高樓 幻夢 冰 RECAP2022: 流星雨 清夜 割點 Tarjan 演算法 P3147 USACO16OPEN 262144 P 題解 P3354 Riv 河流 題解 夜雨 層霧 從愚人節玩笑到真的玩笑(bushi): 淺談 lsnotes I made my own Hexo theme 題解 紀念品分組 題解 導彈攔截 如何高效使用搜尋引擎 用 GitHub Actions 格式化 C/C++ 程式碼 四季的天空 洛谷 7 月月賽 Div.2 總結 題解 最近公共祖先 (LCA) 用簡單的物理方法證明牛頓萊布尼茨公式 簡評榮耀手環6 海上生明月,天涯共此時。 我為什麼重新拿出了 iPod Swift 中的 SharedPreferance —— UserDefaults 凝視那一輪明月 用 GitHub Actions 部署 Hexo 部落格 遲來的日誌 - WWDC 2020 獎學金 vcpkg - 方便的 C/C++ 庫管理器 vimrc 配置指南 NextCloud - DIY NAS 解決方案 sudo shutdown -r now sudo shutdown -r now
馬拉車演算法
Louis C Deng · 2022-11-21 · via Louis C Deng's Blog

最近在學習馬拉車演算法,簡單記錄一下心得。(如有疏漏,請指出

先看 模板題 ,要求最長迴文串的長度。

首先思考樸素演算法,顯然是 O(n3)O(n^3) ,無法透過。而馬拉車演算法能將時間複雜度最佳化到 O(n)O(n)

性質

  • 對於一個迴文字串,必然有一個對稱中心,在對稱中心兩側的部分均全等。
  • 一個迴文字串對稱之後得到的一定也是迴文字串
    即 aba x aba
    • 但是對於奇數、偶數長度的迴文字串,這個對稱中心可能是字元,也可能在兩個字元中間。
      如:ab | ba, a b a

所以考慮,在兩個字元中間都插入隔板 #,即 abba 變成 #a#b#b#a#。原長度為 n 的字串,增加 n+1 隔板,長度變成 2n+1 必然是奇數,方便統計。

思路

馬拉車演算法,即記錄一直最長迴文子串區間,對樸素演算法進行最佳化。

因為是樸素演算法兩側向外拓展,隔板對判斷迴文無影響。p[i] 陣列儲存以 str[i] 為對稱中心的迴文字串半徑長度。半徑長度中計算了隔板個數,所以得到的就是迴文字串長度。

1
2
3
4
5
6
7
8
9
10
11
for(int i = 0, l = 0, r = -1;i<s2.size(); i++){
int k = (i>r)? 1 : min(p[l+r-i], r-i+1);
while(0 <= i-k && i+k<s2.size() && s2[i-k]==s2[i+k]){
k++;
}
p[i] = --k;
if(i+k>r){
l = i-k;
r = i+k;
}
}

先記錄 i,列舉每個對稱中心,記錄 lr 即目前最長迴文字串的左右端點。k 則是目前半徑長度。

演算法主體就是樸素演算法,向左右兩端拓展。

考慮最佳化。如果i處在一個迴文子串中,因為對稱性,可以得到與i對稱的點j的最長迴文串長度。因為i不斷增加,對稱的點的座標一定小於i即已經更新過。

由於上文推斷的性質,迴文子串可以對稱得到。注意單個字元也可以考慮成一個迴文子串。所以 k 可以從 之前的 p[j] 開始計算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(設 x 表示 [l,r] 對稱中心,j 就是 i 關於 x 的對稱點)

1. 案例1
l r
#a#b#b#a#
^ ^ ^
j x i

2. 案例2
l r
#a#b#a#b#a#b#a#
^ ^ ^
j x i

手推方便理解

然後考慮如何計算 j,因為中點座標公式,得到 l+r2=i+j2=mid\frac{l+r}{2} = \frac{i+j}{2} = mid ,得到 j=l+r−ij = l+r-i

但是因為確定區間,且偶數情況存在。所以還應判斷 j 是否在區間內。

而如果不在區間內,很顯然應該從1開始列舉。

所以得到:

1
int k = (i>r)? 1 : min(p[l+r-i], r-i+1);

每次更新 l r 區間長度即可。

AC Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <cstdio>
#include <iostream>
#include <string>

using namespace std;

int p[110000001];

int main() {

string s1;
cin >> s1;
string s2;
s2.resize(s1.size()*2+4);
s2[0] = '~';
s2[1] = '#';
for(int i = 0, j=2; i<s1.size(); i++, j+=2){
s2[j] = s1[i];
s2[j+1] = '#';
}
int ans = 0;
for(int i = 0, l = 0, r = -1;i<s2.size(); i++){
int k = (i>r)? 1 : min(p[l+r-i], r-i+1);
while(0 <= i-k && i+k<s2.size() && s2[i-k]==s2[i+k]){
k++;
}
k--;
p[i] = k;
if(i+k>r){
l = i-k;
r = i+k;
}
ans = max(ans,p[i]);
}
cout << ans << endl;
return 0;
}

小結

馬拉車演算法實用且容易理解,但熟練掌握還需要練習。

作業 | 最長雙迴文串