表达式树(公共表达式消除 uva 12219)

来源:互联网 发布:js通过标签名获取元素 编辑:程序博客网 时间:2024/05/02 00:53

一共写了3遍,2遍超时,第三遍看了别人的代码才写出来的。。。


第一遍,直接保存整颗子树,也就是整个子表达式。

为了得到子表达式的值,我频繁调用substr函数。

为了找到分隔左右子表达式的逗号,我直接遍历子表达式。

最后用map去映射。

结果超时。。

后来看了下紫书,说不能保存整颗子树。。

说比较两棵树的时间复杂度是O(n),循环枚举两颗子树,总时间复杂度高达O(n^3)。

我本以为map比较高效的,但后来我仔细算了下发现不会高效很多。

我们都知道map的时间复杂度是O(logn),但是那只是查询的复杂度。如果你查询的是字符串,那就多O(n),每个子树查询一遍,就又多O(n),总共O(n^2logn)。

伤不起。。。


第二遍,建树使扫描整个子表达式找到中间的那个逗号

按书上说的改了下子树的保存方式后,时间复杂度变为O(nlogn),依旧超时。

后来上网看别人的代码,才知道我建树的方法太粗暴了。频繁调运substr+遍历找逗号,都不知道循环多少遍了。

只有扫描一遍的才不会超时。


参考 http://www.bubuko.com/infodetail-646757.html


AC代码

#include<stdio.h>#include<iostream>#include<map>#include<string.h>#include<string>using namespace std;string s;int k,cnt;map<int,int>done;struct tree{    string s;    int ls,rs;    bool operator < (const tree& rhs) const//要用map一定要重载运算符。    {        if(s!=rhs.s) return s<rhs.s;        else if(ls!=rhs.ls) return ls<rhs.ls;        else return rs<rhs.rs;    }};map<tree,int>MAP;//保存IDmap<int,tree>NODE;//保存节点信息int solve()//只扫描一遍,好棒。{    string cur;    while(s[k]>='a'&&s[k]<='z') cur.push_back(s[k++]);    int id=++cnt;//跟cnt有关的代码都好精彩,前两遍我也想到了,但写的好烂。                 //这里是先给你预留一个编号的意思。    tree& t=NODE[id];//引用,好灵活。    t.s=cur;    t.ls=0;    t.rs=0;    if(s[k]=='(')    {        //写得简单易懂,跳过非字母的字符。        k++;        t.ls=solve();k++;        t.rs=solve();k++;    }    if(MAP[t]) {cnt--;return MAP[t];}//如果MAP[t]!=0,那么cnt必为id+1,cnt--即可取消预留的编号。    else return MAP[t]=id;}//原来还可以这样输出。。。不过前两遍的代码我是一遍dfs解决建树与输出的。//该省的不省。。不该省的乱省。。只能说自己对时间复杂度不够敏感吧。void print(int u){    if(done[u]) printf("%d",u);    else    {        done[u]=1;        cout<<NODE[u].s;        if(NODE[u].ls)        {            cout<<"(";            print(NODE[u].ls);            cout<<",";            print(NODE[u].rs);            cout<<")";        }    }}int main(){    int q;    cin>>q;    while(q--)    {        MAP.clear();        done.clear();        NODE.clear();        cnt=k=0;        cin>>s;        print(solve());//solve返回根编号,print从根标号开始递归输出。        puts("");    }    return 0;}


第一遍代码

#include<stdio.h>#include<iostream>#include<string>#include<map>using namespace std;struct tree{    string now;    int l,r;    tree(string a,int b,int c):now(a),l(b),r(c){}};map<string,int>MAP;string s;int cnt;void dfs(int l,int r){    string a=s.substr(l,r-l+1);    if(MAP[a]) {printf("%d",MAP[a]);return;}    int now=++cnt;    if(s[r]!=')') {cout<<a;MAP[a]=cnt;return;}    while(s[l]!='(') printf("%c",s[l++]);    int k=l;    int p=0;    while(1)    {        if(s[k]=='(') p++;        if(s[k]==')') p--;        if(p==1&&s[k]==',') break;        k++;    }    printf("(");    dfs(l+1,k-1);    printf(",");    dfs(k+1,r-1);    printf(")");    MAP[a]=now;}int main(){    int c;    scanf("%d",&c);    while(c--)    {        MAP.clear();        cnt=0;        cin>>s;        dfs(0,s.size()-1);        puts("");    }    return 0;}

第二遍代码

#include<stdio.h>#include<iostream>#include<string>#include<sstream>#include<map>using namespace std;struct tree{    string now;    int l,r;    tree(string a,int b,int c):now(a),l(b),r(c){}    bool operator < (const tree & rhs) const    {        if(now!=rhs.now) return now<rhs.now;        else if(l!=rhs.r) return l<rhs.l;        else return r<rhs.r;    }};typedef pair<int,int> pii;typedef pair<int,string> pis;map<tree,int>MAP;string s;int cnt;pair<pis,int> dfs(int l,int r){    if(s[r]==')')    {        int ll=l;        while(s[ll]!='(') ll++;        int k=ll;        int p=0;        while(1)        {            if(s[k]=='(') p++;            if(s[k]==')') p--;            if(p==1&&s[k]==',') break;            k++;        }        int now=++cnt;        string cur=s.substr(l,ll-l);        stringstream sss;        string ss;        pair<pis,int> ls=dfs(ll+1,k-1);        pair<pis,int> rs=dfs(k+1,r-1);        //cout<<"      "<<ls.first.second<<" "<<rs.first.second;        tree t=tree(cur,ls.second,rs.second);        int id=MAP[t];        if(ls.first.first&&rs.first.first&&id)        {            cnt--;            sss<<id;            sss>>ss;            return make_pair(make_pair(1,ss),id);        }        else        {            sss<<cur;            MAP[t]=now;            sss<<"(";            sss<<ls.first.second;            sss<<",";            sss<<rs.first.second;            sss<<")";            sss>>ss;            return make_pair(make_pair(0,ss),now);        }    }    else    {        string ss=s.substr(l,r-l+1);        tree t(ss,0,0);        int id=MAP[t];        stringstream sss;        if(id) sss<<id;        else {MAP[t]=++cnt;sss<<ss;}        sss>>ss;        if(id) return make_pair(make_pair(1,ss),id);        else return make_pair(make_pair(0,ss),cnt);    }}int main(){    int c;    scanf("%d",&c);    while(c--)    {        MAP.clear();        cnt=0;        cin>>s;        cout<<dfs(0,s.size()-1).first.second;        puts("");    }    return 0;}


1 0