• poj1200


    原题:

     题目意思大致是这样 

    输入的NC 如4 说明输入的这个addbabac 有abcd四个不同字符

    输入的N 如 3 是指子串长度

    输入的s 如daababac是主串

    我们要找主串中不同的连续子串数目 子串长度必须为N

    如daababac 有

     这五个不同连续子串

    这样一看 好像这个NC没啥用 我们先用最简单的方法写一遍

    #include<cstdio>
    #include<iostream>
    #include<set>
    #include<string>
    
    using namespace std;
    int main()
    {
        int N,NC;
        scanf("%d%d",&N,&NC);
        string q;
        cin>>q;
        set<string> c;
        for(int i =0; i < q.size()-N+1;i++)
        {
            c.insert(q.substr(i,N));
        }
        cout<<c.size()<<endl;
        return 0;
    }

    我们直接暴力遍历一遍 把所有遍历的放了去重容器set中 再直接数set多少个元素就行

    果不其然超时了。这种看似简单的题基本都会卡输入输出

    所以想想怎么优化:

    具体思路是

    首先cin cout肯定不能有 

    string也避免用 

    就用c写不去用stl

    然后再想想优化算法

    我们之前是直接暴力比较

    set是红黑树 插入的时间复杂度是O(logN)但是里边还有一个string的substr 这个substr截取子串的话如果用char数组,char*去想想实现原理

    平均应该也有个n/2次 那时间复杂度是o(N)

     上边还有一个循环

    这个时间复杂度粗略估算是三个乘起来 怎么也得比o(n²)o(n*m)高

    所以算法必须优化。之前这个算法好处就是 set这个红黑树的logn时间复杂度还挺好 所以要善于用set

    怎么优化呢 用哈希

    这样这个NC就用上了

    举个例子

    对于addbabac 这个串 我们用c的语言特点

    a虽然是char 但是int值也是97

    a-z这些字符他们的int值本身也是哈希值 一一映射

    这就方便我们直接用int数组记录哈希

    还有就是 这个NC提示我们要用NC进制去标识 这个s转化的唯一NC进制数

    之后我们把字符 字符串的比较转化为了数字的比较 

    举个例子 10进制 每位就是0-9 唯一标识了一个数 假如abcd是 1234

    就不会有adbb也是1234 和他重复 

    ac代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define ll long long int
    const int maxn = 16000000 + 3;
    char s[maxn];
    int not_0[maxn];
    int num[301];
    int N,NC;
    void hash(char *s)
    {
        int len = strlen(s);
        int temp = 0;
        num[s[0]] = temp++;  
        for(int i=1;i<len;i++)
        { 
            if(num[s[i]] == 0)
                num[s[i]] = temp ++;
        } //num[s[i]] char -> int
    }
    int get_cnt(int l,int r)
    {
        int sum = 0;
        for(int i=l;i<=r;i++)
        {
            sum = sum * NC + num[s[i]];
        }
        return sum;
    }
    int main()
    {
        while(~scanf("%d%d%s",&N,&NC,s))
        {
            int ans = 0;
            int len = strlen(s);
            hash(s);
            for(int i=0;i<=len-N;i++)
            {
                int cnt = get_cnt(i, i+N-1);
                if(!not_0[cnt])
                {
                    ans ++;
                    not_0[cnt] = 666;
                }
            }
            printf("%d\n",ans);
        }
        return 0;
    }
  • 相关阅读:
    负载均衡
    二叉树反转
    hashMap 和红黑树
    linux c++ 服务器编程,收藏一个测试例子
    某某音乐盒面试
    Linux中的文件i节点
    linux 文件格式压缩
    类string的构造函数、拷贝构造函数和析构函数
    计算二叉树的深度
    string转换为decimal
  • 原文地址:https://www.cnblogs.com/ranzhong/p/15817968.html
Copyright © 2020-2023  润新知