[题解]UVA10391 复合词 Compound Words

思路

如果有 num 个单词,需要从中找出复合单词。可以采取的一种策略使用一个二重循环将第 i 个单词和第 j 个单词拼接成一个新单词,然后再字典中查找,如果查找到,则新单词是一个复合单词。但是此题中,最多有 120000 个单词,所以这种方法肯定会超时。

注意到,字典中的单词是按字典序排列的,这极大地简化了复合单词的查找。以下代码的策略是:对第 i 个单词一样(可用 strncmp 函数实现),则以二分查找法在字典中查找第 j 个单词的后半部分。如果查找到,则找到一个复合单词。

以上策略需要注意:

  1. 因为字典中的单词是按字典序排列的,则如果第 j 个单词前半部分跟第 i 个单词一样,则第 j 个单词就在第 i 个单词的后边(可能有多个,但不会太多)如样例输入中:aaliennewnewborn。对前半部分第 i 个单词不一样的单词,不需考虑。
  2. 因为字典中的单词是有序的,所以在查找第 j 个单词后半部分是,可以用二分法来查找。
  3. 题目中要求按字典序输出所有的复合单词,因此找到一个复合单词后,还需要把它插入到合适的地方,这时因为字典序靠后的单词可能先被找到。例如:address 是由 address 复合的,address 先于 addend 找到。
  4. 同一个复合单词,可能可以由多组单词复合而成。例如:begel 可以由 begel 复合而成,也可以由 begel 复合而成。这两个问题可以统一处理:用 out 数组存储所有找到的复合单词且按字典序排列。每次找到一个复合单词 w 后,在 out 数组中从后往前找第一个小于或等于 w 的单词 w1,如果 w1 等于 w,就不插入,否则把 w1 后的每个单词后移,然后把 w 插入到 w1 后面。

Code

#include <bits/stdc++.h>  
  
using namespace std;  
  
const int N = 1200010;  
char di[N][20],t[20];// di 用来存储字典中的单词   
char out[N][20];// out 用来存储复合单词   
int num,cnum;// num 字典中单词的个数  cnum 复合单词的个数   
  
bool search(char w[]){//在字典中用二分法查找 w 所指向的单词   
    int l = 0,r = num - 1,mid,j;  
    while (l <= r){  
        mid = l + (r - l >> 1);  
        j = strcmp(w,di[mid]);  
        if (j){  
            if (j < 0) r = mid - 1;  
            else l = mid + 1;  
        }  
        else break;// w 与 di[mid] 相等   
    }  
    if (l <= r) return true;  
    return false;  
}  
  
int main(){  
    int i,j,k,n;  
    while (cin >> t) strcpy(di[num++],t);//读入字典中的单词   
    for (int i = 0;i < num;i++){  
        for (int j = i + 1;j < num && !strncmp(di[i],di[j],strlen(di[i]));j++){  
            // di[j] 单词中前 strlen(di[i]) 个字母跟单词 di[i] 一样  
            if (search(di[j] + strlen(di[i]))){//在字典中找 di[j] 后半部分   
                for (k = cnum - 1;k >= 0 && strcmp(di[j],out[k]) < 0;k--);//找到一个复合单词 di[j],找一个合适的位置存放   
                if (k < 0 || strcmp(di[j],out[k])){  
                    for (n = cnum;n > k;n--) strcpy(out[n + 1],out[n]);  
                    strcpy(out[k + 1],di[j]);  
                    cnum++;  
                }  
            }  
        }  
    }  
    for (int i = 0;i < cnum;i++) cout << out[i] << endl;//输出每个复合单词   
    return 0;  
}  

作者:WaterSun

出处:https://www.cnblogs.com/WaterSun/p/18270907

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   WBIKPS  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示