uva 10391 - Compound Words

点击打开链接


题目意思: 给定很多个单词,现在要求我们找到这些单词里面,是否有单词由另外两个单词组成,输出所有的这种组合单词


解题思路: 1 map映射

我么知道map内部的实现原理是红黑树,还有如果用map那么两个键值要为string , 我么知道 string 是一个类 处理起来是要消耗大量时间的,那么我们先要插入map中然后在两个for 枚举每一种组合判断是否存在,这样的时间肯定是不满足题目所给的,那么map映射就被抛弃了。

2 hash 映射

我们知道哈希表的查找具有高效性,如果我么在读入的时候就把这些单词转换成哈希值存入哈希表中,当读完以后我们再通过枚举每一个单词的所有拆分成的两部分是否都在这个哈希表中,如果是直接输出,然后往下一个单词判断,那么这样就大大降低了时间复杂度,对于题目时间肯定是够的。

注意: 由于刚开始时候我建完表后想到的就是直接两个for枚举每一种组合,然后再去查找,可是这一题的数据很强,单词 数最多有120000个 那么如果是直接这样循环枚举肯定超时,所以开始我就陷入了TLE中,后来没辙看了队友的思路发现是他通过拆单词而不是组合单词,这个想法直接o(n)就可以了,比我的想法高效多了,嗨,只感叹自己脑子真的是 不够灵通啊,只想组合就没有想过拆。

还有我的拆单词方法比较低效率,比起对于足足多了0.02s


代码:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <stack>
#include <queue>
#include <set>
using namespace std;
#define MAXN 1000003
typedef char Word[100];
 
Word w[MAXN];
Word ch;
int  head[MAXN] , next[MAXN];
int  n;

//哈希表的初始化
void init_table(){
    n = 1; 
    memset(head , 0 , sizeof(head));
    memset(next , 0 , sizeof(next));
}

//哈希函数
int Hash(char *ch){
    int seed = 131;
    int hash = 0;
    while(*ch) hash = seed*hash + (*ch++);
    return (hash & 0x7FFFFFFF) % MAXN;
}

//插入
void insert_table(int s){
    int h = Hash(w[s]);
    next[s] = head[h];
    head[h] = s;
}

//查询
int search_table(char *ch){
    int h = Hash(ch);
    int u = head[h];//从表头开始查找
    while(u){
        if(strcmp(ch , w[u]) == 0) return 1;
        u = next[u];
    }
    return 0;
}

int main(){
    //freopen("input.txt" , "r" , stdin);
    init_table() ;
    int i , j;
    while(gets(w[n])){
        insert_table(n);
        n++;
    }
    //枚举拆分(我的做法效率比较差,我的AC时间0.052)
    for(i = 1 ; i < n ; i++){
        if(strlen(w[i]) > 1){
            for(j = 0 ; j < strlen(w[i]) ; j++){
                char w1[50] = {0} , w2[50] = {0};
                for(int k = 0 ; k <= j ; k++) w1[k] = w[i][k];
                for(int k = j+1 ; k < strlen(w[i]) ; k++) w2[k-j-1] = w[i][k];
                if(search_table(w1) && search_table(w2)) { printf("%s\n" , w[i]) ; break;}
            }
        }
    } 
    //队友的拆分的处理(AC运行时间0.032)
    /*
    for(int i=1; i< n; ++i){
        if(strlen(w[i])){
           for(int j = 0 ; j < strlen(w[i])-1; ++j){  
               strcpy(str, w[i]);  
               str[j+1] = '\0';  
               if(search_table(str) && search_table(w[i]+j+1)){  
                  puts(w[i]); break;  
               }  
           } 
        }
    }
    */
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值