2

字符串-----KMP竟然是18禁

今天学了一下午字符串,讲到结束也没讲KMP。有人问老师为什么不讲,老师来一句:字符串noip不考,而且还是18禁,自然不讲。【手动滑稽】

所以我也不讲。【微笑】

1.表达式树

表示3+5*8

最后计算的符号是根节点,是一课二叉树,左右子树可以是数或式。

例题:表达式计算

代码如下

/*
10+(2+3)*4
30
*/

#include <iostream>
#include <stack>
#include <cstring>
using namespace std;

const int MAXN = 10000 + 10;
char str[MAXN];

int solve(int l, int r) // 璁$畻杈撳叆鐨勮〃杈惧紡[l,r]鍐呯殑鍊?
{
    // 鎵炬渶鍚庝竴涓绠楃殑浣嶇疆
    int pos=-1;
    int flag=0;
    int level=2; // 0:+- 1:*/
    for(int i=l;i<=r;i++)
    {
        if(str[i]=='(')flag++;
        if(str[i]==')')flag--;
        if(flag == 0 && (str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/'))
        {
            int l=-1;
            switch(str[i])
            {
                case '+':case '-':l=0;break;
                case '*':case '/':l=1;break;
            }
            if(level >= l)
            {
                level=l;
                pos=i;
            }
        }
    }
    if(pos==-1)
    {
        if(str[l]=='('&&str[r]==')') return solve(l+1,r-1);
        int x=0;
        for(int i=l;i<=r;i++)
            x=x*10+str[i]-'0';
        return x;
    }
    int a = solve(l, pos-1);
    int b = solve(pos+1, r);
    int ans;
    switch(str[pos])
    {
        case '+':ans=a+b;break;
        case '-':ans=a-b;break;
        case '*':ans=a*b;break;
        case '/':ans=a/b;break; // 3*2/3
    }
    return ans;
}
int main()
{
    cin >> (str+1);
    cout << solve(1, strlen(str+1)) << endl;

    return 0;
}

这道题还有一个栈的做法

代码如下

/*
1+(2+3)*4
21
*/
// 鍋囪杈撳叆鐨勬暟瀛楀湪[0,9]

#include <iostream>
#include <stack>
using namespace std;

const int MAXN = 10000 + 10;
char str[MAXN];
stack<int> nums;
stack<char> symbol;

void pop()
{
    int a = nums.top();nums.pop();
    int b = nums.top();nums.pop();
    char s = symbol.top();symbol.pop();
    int ans;
    switch(s)
    {
        case '+':ans=a+b;break;
        case '-':ans=b-a;break;
        case '*':ans=a*b;break;
        case '/':ans=b/a;break; // 3*2/3
    }
    nums.push(ans);
}
int main()
{
    cin >> (str+1);
    for(int i=1;str[i]!=0;i++)
    {
        char c=str[i];
        if('0'<=c&&c<='9')
        {
            nums.push(c-'0');
        } else {
            if(c==')')
            {
                while(symbol.top() != '(') pop();
                symbol.pop();
            } else if (c=='+' || c=='-')
            {
                while(!symbol.empty()
                    &&symbol.top()!='+'
                    &&symbol.top()!='-'
                    &&symbol.top()!='(') pop();
                symbol.push(c);
            } else symbol.push(c);
        }
    }
    while(!symbol.empty())pop();
    cout<<nums.top()<<endl;

    return 0;
}

2.hash(搞一个233进制数)&&trie树

例题:字符串统计

const int P = 673, MOD = 1000007;

int hash(char* str)
// 瑕佹眰鐩稿悓瀛楃涓茶繑鍥炵殑瀛楃涓插繀椤荤浉鍚?
// 涓嶅悓鐨勫瓧绗︿覆杩斿洖鍊煎敖閲忎笉鍚?
{
    int ans=0;
    for(int i=0;str[i];i++)
        ans=(ans*P+str[i])%MOD;
    return ans;
}
vector<string> L[MOD];
int main()
{
    int n;
    cin >> n;
    char str[100 + 10];
    while(n--)
    {
        cin>>str;
        int h=hash(str);
        bool same=false;
        for(int i=0;i<(int)L[h].size()&&!same;i++)
            if(str==L[h][i])
                same=true;
        puts(same ? "YES" : "NO");
        if(!same) L[h].push_back(str);
    }
}
/*hash*/
const int MAXN = 100000 + 10;

struct Node
{
    int son[26];
    int mark;
};
Node tree[MAXN*10];
int root=0, op=0;

bool insert(char* str) // 鎻掑叆瀛楃涓诧紝杩斿洖璇ュ瓧绗︿覆鏄惁宸茬粡鍑虹幇杩?
{
    int pos=root;
    for(int i=0;str[i];i++)
    {
        int c=str[i]-'a';
        if(tree[pos].son[c] == 0) tree[pos].son[c] = ++op;
        pos = tree[pos].son[c];
    }
    int mark=tree[pos].mark;
    tree[pos].mark=1;
    return mark!=0;
}
int main()
{
    int n;
    cin >> n;
    char str[100 + 10];
    while(n--)
    {
        cin>>str;
        puts(insert(str) ? "YES" : "NO");
    }
}
/*trie树*/

例题:情书

const int MAXN = 100000 + 10;

struct Node
{
    int son[26];
    int mark;
    int time; // 琛ㄧず鏈€鏂板尮閰嶇殑鏄摢鍙ヨ瘽
};
Node tree[MAXN*10];
int root=0, op=0;
char str[1000000 + 10];
int cnt, ans;
// cnt琛ㄧず褰撳墠姝e湪澶勭悊鐨勫崟璇嶆槸绗嚑鍙ヨ瘽

void insert(char* str) // 鎻掑叆瀛楃涓?
{
    int pos=root;
    for(int i=0;str[i];i++)
    {
        int c=str[i]-'a';
        if(tree[pos].son[c] == 0) tree[pos].son[c] = ++op;
        pos = tree[pos].son[c];
    }
    tree[pos].mark=1;
}
void search(char* str)
{
    int pos=root;
    for(int i=0;str[i];i++)
    {
        int c=str[i]-'a';
        if(tree[pos].son[c] == 0) return;
        pos = tree[pos].son[c];
    }
    if(tree[pos].mark==1 && tree[pos].time!=cnt)
        ans++;
    tree[pos].time=cnt;
}
int main()
{
    int n;
    cin >> n;
    while(n--)
    {
        cin>>str;
        insert(str);
    }
    cnt=1;
    while(cin>>str)
    {
        int len=strlen(str);
        bool juzi=false;
        if(str[len-1]=='.')
        {
            juzi=true;
            str[len-1]='\0';
        }
        search(str);
        if(juzi)
        {
            cout<<ans<<endl;
            ans=0;
            cnt++;
        }
    }
}

例题:LCP(最长公共前缀hash做法)

const int P = 637, MOD = 1000000007;
char str[MAXN];
long long H[MAXN];
long long POW[MAXN];

int main()
{
    cin>>str+1;
    n=strlen(str+1);
    for(int i=1;i<=n;i++)
        H[i]=(H[i-1]*P+str[i])%MOD;
    POW[0]=1;
    for(int i=1;i<=n;i++)
        POW[i]=(POW[i-1]*P)%MOD;
    int A, B;
    while(cin>>A>>B)
    {
        int l=0, r=min(n-A+1, n-B+1), mid;
        while(l<r)
        {
            mid=(l+r)/2+1; // l=0, r=1 [0, 1]/[-1, 0]
            // h1涓簊tr[A~A+mid-1]鐨刪ash鍊?
            long long h1=((H[A+mid-1]-H[A-1]*POW[mid])%MOD+MOD)%MOD;
            long long h2=((H[B+mid-1]-H[B-1]*POW[mid])%MOD+MOD)%MOD;
            if(h1==h2)l=mid;
            else r=mid-1;
        }
    }
}

// -9 % 4 = (-1 + 4) % 4 = 3

 

posted @ 2018-02-08 18:53  DDYYZZ  阅读(1293)  评论(0编辑  收藏  举报