UVA11019KMP(二维矩阵匹配出现次数)

本文探讨了在二维矩阵中寻找特定子矩阵出现次数的问题,通过将二维问题转化为一维问题并运用KMP算法进行高效匹配,实现算法优化。在实际应用中,即使面对较高的时间复杂度,通过合理调整数据输入和随机测试,算法仍然能够有效运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:
    给你两个矩阵,一个大的一个小的,然后问你这个小矩阵在大的矩阵里出现了多少次?
思路:
      说好了AC自动机的,我自己尝试写了个暴力的KMP竟然过了,AC自动机自己的模板还没写完,就暂时没用,说下KMP的解法吧,首先我们考虑如果是一维的情况,是不是就直接KMP裸题了,那么我们就想办法把二维降成一维,我用的是比较笨的方法就是把每一数列看成一个字母(每次比较的时候要比较一数列),求出next数组,然后在把大的那个串暴力拆成一些小串,宽度是他自己的宽度,长度是和小串长度一样,然后线性的去KMP就行了,一开始只是抱着试试的态度,毕竟时间复杂度最坏的情况太高,但是试的原因是这样的,在处理串匹配的时候时间往往并没有那么多,是可以根据概率算出来,就算是最笨的匹配方式,匹配失败就从头从新匹配,在随机数据的情况下也是很少的,并不能简单的(m+n*m)/2这样算,当时我的想法是如果这样超时了,我会去尝试把比较那个地方优化下,就是把两个串比较的那个地方,感觉string去处理可能会快一点(没有尝试),如果还超时那就只能把自己上午没写完的那个AC自动机模板写完(写了两天了,写的比较痛苦),然后在做了。不过没想到1A了。



#include<stdio.h>
#include<string.h>

char stra[1002][1002];
char strb[102][102];
int next[102];

bool jude(int a ,int b ,int n)
{
    for(int i = 1 ;i<= n ;i ++)
    if(strb[i][a] != strb[i][b])
    return 0;
    return 1;
}


bool jude2(int a ,int b ,int I ,int k)
{
    for(int i = 1 ;i <= k ;i ++)
    if(stra[i+I-1][a] != strb[i][b])
    return 0;
    return 1;
}

void GetNext(int n ,int m)
{
    int j = 0 ,k = -1;
    next[0] = -1;
    while(j < m)
    {
        if(k == -1 || jude(j ,k ,n))
        next[++j] = ++k;
        else k = next[k];
    }
}

int KMP(int n ,int m ,int k ,int I)
{
    int i ,j ,Ans = 0;
    for(i = j = 0 ;i < n ;)
    {
        if(jude2(i ,j ,I ,k))
        {
            if(j == m - 1) Ans ++;
            i ++ ,j ++;
        }
        else
        {
            j = next[j];
            if(j == -1)
            {
                i ++ ,j = 0;
            }
        }
    }
    return Ans;
}


int main ()
{
    int t ,n1 ,m1 ,n2 ,m2 ,i;
    scanf("%d" ,&t);
    while(t--)
    {
        scanf("%d %d" ,&n1 ,&m1);
        for(i = 1 ;i <= n1 ;i ++)
        scanf("%s" ,stra[i]);
        scanf("%d %d" ,&n2 ,&m2);
        for(i = 1 ;i <= n2 ;i ++)
        scanf("%s" ,&strb[i]);
        if(n2 > n1 || m2 > m1)
        {
            printf("0\n");
            continue;
        }
        GetNext(n2 ,m2);
        int Ans = 0;
        for(i = 1 ;i <= n1 - n2 + 1 ;i ++)
        {
            Ans += KMP(m1 ,m2 ,n2 ,i);
        }
        printf("%d\n" ,Ans);
    }
    return 0;
}































KMP(Knuth-Pratt)算法是一种用于字符串模式匹配的高效算法,它通过构建部分匹配表(也称作失配函数)来避免不必要的字符比较,从而减少了比较次数。下面是C语言实现KMP算法的一个简单版本: ```c #include <stdio.h> #include <string.h> // 创建部分匹配表 void compute_lps(char pattern[], int lps[], int len) { int index = 0; for (int i = 1; i < len; ++i) { if (pattern[i] == pattern[index]) { lps[i] = index + 1; index++; } else { if (index != 0) { index = lps[index - 1]; } else { lps[i] = 0; } } } } // 使用KMP算法寻找模式在主串中的位置 int kmp_search(char main_str[], char pattern[]) { int len1 = strlen(main_str); int len2 = strlen(pattern); int lps[len2]; // 部分匹配表 compute_lps(pattern, lps, len2); int index = 0, count = 0; while (index < len1) { if (main_str[index] == pattern[index]) { index++; count++; } else { if (index != 0 && lps[index - 1] != 0) { index = lps[index - 1]; } else { main_str[index++] = '\0'; // 如果找不到匹配,结束搜索并回溯 } } } return count; // 返回匹配次数,如果没有找到匹配则返回0 } int main() { char main_str[] = "ababcabaa"; char pattern[] = "abca"; printf("Pattern '%s' occurs %d times in the string.\n", pattern, kmp_search(main_str, pattern)); return 0; } ``` 在这个代码中,`compute_lps`函数计算了部分匹配表,而`kmp_search`函数利用这个表在主串中查找模式。注意,如果找到匹配,`count`变量会记录匹配次数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值