学习日记(1.13)

今天主要还是关于hash和kmp的例题练习

目录

kmp例题

Radio Transmission 无线传输

题目描述

输入格式

输出格式

说明/提示

思路

代码 

hash例题

字符串哈希

题目描述

输入格式

输出格式

说明/提示

思路

代码实现


kmp例题

Radio Transmission 无线传输

题目描述

给你一个字符串 s_1s1​,它是由某个字符串 s_2s2​ 不断自我连接形成的。但是字符串 s_2s2​ 是不确定的,现在只想知道它的最短长度是多少。

输入格式

第一行一个整数 LL,表示给出字符串的长度。

第二行给出字符串 s_1s1​ 的一个子串,全由小写字母组成。

输出格式

仅一行,表示 s_2s2​ 的最短长度。

说明/提示

样例输入输出 1 解释

对于样例,我们可以利用 \texttt{abc}abc 不断自我连接得到 \texttt{abcabcabc}abcabcabc,读入的 \texttt{cabcabca}cabcabca,是它的子串。

规模与约定

对于全部的测试点,保证 1 < L \le 10^61<L≤106。

思路

首先根据提示就可以知道给出的样例由一段子串不断自我连接出来的一个主串中的子串,直接上图:

由上图可知,我首先找出了给出字符串的最大前缀(红色线条)和对应的最大后缀(蓝色线条),然后会发现,将前缀部分和后缀部分重叠之后能够得到,一个由最小字符串组成的完整主串。

但是我这个举的是一个比较特殊的例子,如果是题目中给出的那样的例子,也是相同的道理

为什么会这样嘞,根据上面一个草图来看,可以知道,将前缀后缀分成了俩部分,一部分是重叠了的部分,一部分是未重叠的部分,这么分的原因是,将串延长一点可能会更加清楚

由上图可知,重复部分的字符是相对应的,所以最小字符串长度就是未重叠的长度。

代码 

#include<stdio.h>
#include<string.h>
char str[1000010];
int next[1000010];

void get_next(int L)
{
    int i=0,j=-1;
    next[0] = -1;
    while(i<L)
    {
        if(j==-1 || str[i]==str[j])
        {
            ++i;
            ++j;
            next[i] = j;
        }
        else
            j = next[j];
    }
}

int main()
{
    int L;
    scanf("%d",&L);
    scanf("%s",str);
    get_next(L);
    printf("%d ",L-next[L]);
    return 0;
}

hash例题

字符串哈希

题目描述

如题,给定 NN 个字符串(第 ii 个字符串长度为 M_iMi​,字符串内包含数字、大小写字母,大小写敏感),请求出 NN 个字符串中共有多少个不同的字符串。

友情提醒:如果真的想好好练习哈希的话,请自觉。

输入格式

第一行包含一个整数 NN,为字符串的个数。

接下来 NN 行每行包含一个字符串,为所提供的字符串。

输出格式

输出包含一行,包含一个整数,为不同的字符串个数。

说明/提示

对于 30\%30% 的数据:N\leq 10N≤10,M_i≈6Mi​≈6,Mmax\leq 15Mmax≤15。

对于 70\%70% 的数据:N\leq 1000N≤1000,M_i≈100Mi​≈100,Mmax\leq 150Mmax≤150。

对于 100\%100% 的数据:N\leq 10000N≤10000,M_i≈1000Mi​≈1000,Mmax\leq 1500Mmax≤1500。

样例说明:

样例中第一个字符串(abc)和第三个字符串(abc)是一样的,所以所提供字符串的集合为{aaaa,abc,abcc,12345},故共计4个不同的字符串。

Tip: 感兴趣的话,你们可以先看一看以下三题:

BZOJ3097:http://www.lydsy.com/JudgeOnline/problem.php?id=3097

BZOJ3098:http://www.lydsy.com/JudgeOnline/problem.php?id=3098

BZOJ3099:http://www.lydsy.com/JudgeOnline/problem.php?id=3099

如果你仔细研究过了(或者至少仔细看过AC人数的话),我想你一定会明白字符串哈希的正确姿势的^_^

思路

首先关于hash算法,我的理解是,就是将复杂简单化,通过取余的方式可以实现,也可以通过特殊的进制来达到目的,但是不管是什么情况,避免哈希冲突才是重点。

然后就是关于这个题目,可以先把字符串利用特殊的进制来达到区分不同的目的,然后将字符串转化为不同的数字之后,然后按序排好,然后就是找相同的数字,排除掉相同的字符串达到题目要求。

代码实现

#include<stdio.h>
#include<string.h>
#define num 10010
long long base(char str[])
{
    long long sum=0;
    for(int i=0; str[i]; i++)
        sum=sum*11+str[i];
    return sum;
}

int main()
{
    long long base(char str[]);
    long long n,hash[num];
    scanf("%d",&n);
    for(int i=0; i<n; i++)
    {
        char str[1510];
        scanf("%s",str);
        hash[i] = base(str);
    }
    for(int i=1; i<n; i++)
        for(int k=0; k<n-1; k++)
        {
            long long x;
            if(hash[k]>hash[k+1])
            {
                x=hash[k];
                hash[k]=hash[k+1];
                hash[k+1]=x;
            }
        }
    int count = 0;
    for(int i=0; i<n; i++)
    {
        if(hash[i]!=hash[i+1])
        {
            count++;
        }
    }
    printf("%d",count);
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值