Seek the Name, Seek the Fame
先看一下KMP核心的next数组的操作:
nex[0] = -1; for (i = 1; i <= len; i++) { while (j >= 0 && st[j + 1] != st[i]) //不匹配回溯一个大规律 j = nex[j]; nex[i] = ++j; //经过上面的循环,要么j回到了0,要么已经重新回到了st[j+1]==st[i]可以继续匹配啦 }
如串a b a b a c 下标1 2 3 4 5 6 j 匹配 回溯 nex[1]=0 0 ([1]a!=[2]b) -1 2=0 0 ([1]a=[3]a) No 3=1 1 ([2]b=[4]b) No 4=2 2 ([3]a=[5]a) No 5=3 3 ([4]b!=[6]c) 2 2 ([2]b!=[6]c) -1 6=0 可以得到: 串 a b a b a c 下标 1 2 3 4 5 6 next数组 0 0 1 2 3 0 如当下标为5不匹配时,我们将直接回溯到下标[3-1]的[2]b上 下标为6不匹配时,我们将回溯到[1]a上从新开始
KMP就可以通过快速的段级的回溯减少大量匹配操作。
看一道例题——2021年广东工业大学第十五届文远知行杯程序设计竞赛-B题找山坡
链接:https://ac.nowcoder.com/acm/contest/13504/B
计算:
max{ R - L | 1 <= L <= R <= n, a[L] == a[R], 对于所有i (L <= i <= R), 满足a[i] >= a[L] }.
找到两个坐标,这两个坐标的值相等,并且他们之间的值都大于等于这两个坐标上的值.
这两个坐标相减最大能是多少.
样例输入:
5
1 2 3 2 1
样例输出:
4 ( [5]1 - [1]1 = 4 )
ans = 0,j=0; for (i = 1; i <= n; i++) { while (j && a[nex[j]] > a[i])//遇到a[i]变小,前推nex[j],扩大区间
j--; if (j && a[nex[j]] == a[i]) //匹配值等于a[i]时,取最大区间 ans = max(ans, i - nex[j]); else nex[++j] = i; }
如:
5
1 2 3 2 1
我们第一次匹配到的应该是 [2]2 = [4]2 ans=2
然后会有[5]1 < [4]2 nex[j]前推 [1]1 = [5]1 ans=4
看大佬写的题解,他们好像是一类问题,可以用单调栈/单调队列乱杀。待我学习补充..