滑动

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

看大佬写的题解,他们好像是一类问题,可以用单调栈/单调队列乱杀。待我学习补充..

原文地址:https://www.cnblogs.com/thx2199/p/14588988.html