POJ 3080 Blue Jeans 字典树

题目链接

题意:给N个文本串 找到在一个在N个文本串中都出现的最长的字典序最小的字串

本来找的是KMP 的题 想来半天都不知道怎么用KMP搞
之后发现可以 将每个串的后缀都加入一颗字典树中
字典树中每个节点的value表示一个状态 即 这个串在哪几个序列中出现过
最后在树上深搜 按A C G T 的顺序搜索
最后在逆这树向上打印文本

时间复杂度: 一个串有len个后缀 将一个长度为n的串加入字典树要用O(n) 所以插入一个长为len的串的时间为 O(len ^ 2) 有N个串 O(N * Len ^ 2)

说一下静态字典树的长度预测 串数上限为N 串长上限为M 假设每次插入的都是新节点 则需要N * M个节点

代码:

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <ctime>
#define sf scanf
#define pf printf
using namespace std;

const int sigma_size = 4;
const int maxn = 40000;

int ch[maxn][sigma_size];
int node_cnt;
int value[maxn];
int pre[maxn];
char pf_ans[] = {'A','C','G','T'};
int IDX(char c){
    if(c == 'A') return 0;
    else if(c == 'C') return 1;
    else if(c == 'G') return 2;
    else return 3;
}



void init_trie(){
    node_cnt = 1;
    memset(ch[0],0,sizeof(ch[0]));
    pre[0] = -1;
}

bool ok(char* s,int len){
    char temp[] = "CATCATCAT";
    for(int i = 0;i <= len;++i){
        if(temp[i] != s[i]) return false;
    }
    return true;
}

void Insert(char *s,int v){
//    puts(s);
    int len = strlen(s);
    int cur = 0,idx;
    for(int i = 0;i < len;++i){
        idx = IDX(s[i]);
        if(ch[cur][idx] == 0){
            ch[cur][idx] = node_cnt;
            memset(ch[node_cnt],0,sizeof(ch[node_cnt]));
            value[node_cnt] = 0;
            pre[node_cnt++] = cur;
        }
        cur = ch[cur][idx];
        value[cur] = value[cur] | v;
//        if(ok(s,i)) pf("%d\n",value[cur]);
    }
}

int ans_deep,ans_lable,ans_state;
//char check[70];
void DFS(int cur,int deep){
//    pf("%d\n",cur);
    if(value[cur] == ans_state && ans_deep < deep){
        ans_deep = deep;
        ans_lable = cur;
//        check[deep] = '\0';
//        puts(check);
    }
    for(int i = 0;i < sigma_size;++i){
        if(ch[cur][i]){
//            check[deep] = pf_ans[i];
            DFS(ch[cur][i],deep + 1);
        }
    }
}

void PRINT_ANS(int cur,int PRE){
    if(cur == -1) return;
    else{
        PRINT_ANS(pre[cur],cur);
        for(int i = 0;i < sigma_size;++i){
            if(ch[cur][i] == PRE) {pf("%c",pf_ans[i]);break;}
        }
    }
}
char str[100];
int main(){
//    freopen("read.txt","r",stdin);
    int T,n;
    sf("%d",&T);
    while( T-- ){
        init_trie();
        sf("%d",&n);
        ans_state = (1 << n) - 1;
        for(int i = 0;i < n;++i){
            sf("%s",str);
            char* insert_str = str;
            while(*insert_str){
                Insert(insert_str,1 << i);
                insert_str++;
            }
        }
        ans_deep = 0;
        DFS(0,0);
        if(ans_deep < 3){
            pf("no significant commonalities");
        }
        else PRINT_ANS(ans_lable,-1);
        pf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值