算法:找出所有满足其出现频率大于某个给定阈值的子串

问题:
给定一组字符串的集合(共53个长度相同的字符串),试设计一个算法,找出所有满足其出现频率大于某个给定阈值的子串,其中阈值为输入参数。例如:“taat”这个子串,集合中的53个字符串中有24个字符串包含“taat”这个子串,则其频率计算为24/53. 如果阈值设置为0.5,则该子串由于其频率小于0.5,所以不必输出。反之,如果阈值设置为0.4,则该子串由于其频率24/53大于0.4,故应该被输出。

初看这道题目,我的想法是首先生成这个包含53个字符串的集合,为了保证任意性和普遍性,我选择了随机生成字符串的方法,然后把这组随机生成的字符串插入到已经定义好的字符串集合中去。

char get_rand_char() {//借助随机库函数随机生成一个字符串
    char str[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    //srand((unsigned int)time((time_t *)NULL));  如果这条语句放在这里,则在get_rand_str()中每次产生的char都是一样的
    return str[rand() % 52];
}
/*把随机生成的字符串插入到已经定义好的set<string> s中去*/
char get_rand_char();
string str = "\0";
srand((unsigned int)time((time_t *)NULL));//time seed created
for (int j = 0; j < SIZE; j++) {//SIZE==53
    for (int i = 0; i < length; i++) {//length is the length of the strings
        str.push_back(get_rand_char());
    }
    s.insert(str);
    str = "\0";
}

但是在之后的程序测试中发现,随机生成的这组字符串是具有了任意性,可是……,也太“任意”了,这些字符串中的相同子串实在是太少了,给调试带来了很大的麻烦。
所以,我干脆自定义一个庞大的字符串数组,然后把它们一一插入到字符串集合中去! 哎,不得不说,这种机械劳动很烦人呐。

string T[53] = { "tactagcaatacgcttgcgttcggtggttaagtatgtataatgcgcgggcttgtcgt",
    "tgctatcctgacagttgtcacgctgattggtgtcgttacaatctaacgcatcgccaa",
    "gtactagagaactagtgcattagcttatttttttgttatcatgctaaccacccggcg",
    "aattgtgatgtgtatcgaagtgtgttgcggagtagatgttagaatactaacaaactc",
    "tcgataattaactattgacgaaaagctgaaaaccactagaatgcgcctccgtggtag",
    "aggggcaaggaggatggaaagaggttgccgtataaagaaactagagtccgtttaggt",
    "cagggggtggaggatttaagccatctcctgatgacgcatagtcagcccatcatgaat",
    "tttctacaaaacacttgatactgtatgagcatacagtataattgcttcaacagaaca",
    "cgacttaatatactgcgacaggacgtccgttctgtgtaaatcgcaatgaaatggttt",
    "ttttaaatttcctcttgtcaggccggaataactccctataatgcgccaccactgaca",
    "gcaaaaataaatgcttgactctgtagcgggaaggcgtattatgcacaccccgcgccg",
    "cctgaaattcagggttgactctgaaagaggaaagcgtaatatacgccacctcgcgac",
    "gatcaaaaaaatacttgtgcaaaaaattgggatccctataatgcgcctccgttgaga",
    "ctgcaatttttctattgcggcctgcggagaactccctataatgcgcctccatcgaca",
    "tttatatttttcgcttgtcaggccggaataactccctataatgcgccaccactgaca",
    "aagcaaagaaatgcttgactctgtagcgggaaggcgtattatgcacaccgccgcgcc",
    "atgcatttttccgcttgtcttcctgagccgactccctataatgcgcctccatcgaca",
    "aaacaatttcagaatagacaaaaactctgagtgtaataatgtagcctcgtgtcttgc",
    "tctcaacgtaacactttacagcggcgcgtcatttgatatgatgcgccccgcttcccg",
    "gcaaataatcaatgtggacttttctgccgtgattatagacacttttgttacgcgttt",
    "gacaccatcgaatggcgcaaaacctttcgcggtatggcatgatagcgcccggaagag",
    "aaaaacgtcatcgcttgcattagaaaggtttctggccgaccttataaccattaatta",
    "tctgaaatgagctgttgacaattaatcatcgaactagttaactagtacgcaagttca",
    "accggaagaaaaccgtgacattttaacacgtttgttacaaggtaaaggcgacgccgc",
    "aaattaaaattttattgacttaggtcactaaatactttaaccaatataggcatagcg",
    "ttgtcataatcgacttgtaaaccaaattgaaaagatttaggtttacaagtctacacc",
    "catcctcgcaccagtcgacgacggtttacgctttacgtatagtggcgacaatttttt",
    "tccagtataatttgttggcataattaagtacgacgagtaaaattacatacctgcccg",
    "acagttatccactattcctgtggataaccatgtgtattagagttagaaaacacgagg",
    "tgtgcagtttatggttccaaaatcgccttttgctgtatatactcacagcataactgt",
    "ctgttgttcagtttttgagttgtgtataacccctcattctgatcccagcttatacgg",
    "attacaaaaagtgctttctgaactgaacaaaaaagagtaaagttagtcgcgtagggt",
    "atgcgcaacgcggggtgacaagggcgcgcaaaccctctatactgcgcgccgaagctg",
    "taaaaaactaacagttgtcagcctgtcccgcttataagatcatacgccgttatacgt",
    "atgcaattttttagttgcatgaactcgcatgtctccatagaatgcgcgctacttgat",
    "ccttgaaaaagaggttgacgctgcaaggctctatacgcataatgcgccccgcaacgc",
    "tcgttgtatatttcttgacaccttttcggcatcgccctaaaattcggcgtcctcata",
    "ccgtttattttttctacccatatccttgaagcggtgttataatgccgcgccctcgat",
    "ttcgcatatttttcttgcaaagttgggttgagctggctagattagccagccaatctt",
    "tgtaaactaatgcctttacgtgggcggtgattttgtctacaatcttacccccacgta",
    "gatcgcacgatctgtatacttatttgagtaaattaacccacgatcccagccattctt",
    "aacgcatacggtattttaccttcccagtcaagaaaacttatcttattcccacttttc",
    "ttagcggatcctacctgacgctttttatcgcaactctctactgtttctccatacccg",
    "gccttctccaaaacgtgttttttgttgttaattcggtgtagacttgtaaacctaaat",
    "cagaaacgttttattcgaacatcgatctcgtcttgtgttagaattctaacatacggt",
    "cactaatttattccatgtcacacttttcgcatctttgttatgctatggttatttcat",
    "atataaaaaagttcttgctttctaacgtgaaagtggtttaggttaaaagacatcagt",
    "caaggtagaatgctttgccttgtcggcctgattaatggcacgatagtcgcatcggat",
    "ggccaaaaaatatcttgtactatttacaaaacctatggtaactctttaggcattcct",
    "taggcaccccaggctttacactttatgcttccggctcgtatgttgtgtggaattgtg",
    "ccatcaaaaaaatattctcaacataaaaaactttgtgtaatacttgtaacgctacat",
    "tggggacgtcgttactgatccgcacgtttatgatatgctatcgtactctttagcgag",
    "tcagaaatattatggtgatgaactgtttttttatccagtataatttgttggcataat",
};
for (int i = 0; i < SIZE; i++) {
    s.insert(T[i]);

接着我声明了一个阈值变量,这个阈值由用户在程序台自己输入,范围当然是0-1之间的数了。

cout << "请您输入阈值(0-1):" << endl;
while (1) {
    cin >> threshold;
    if (threshold > 0 && threshold < 1)
        break;
    else
        cout << "输入错误!请您输入阈值(0-1):" << endl;
}
double number = SIZE*threshold;//达到阈值的字符串临界值数量,包含该子串的字符串数量小于这个值则不输出,大于等于就输出
cout << "子字符串至少需要出现" << number << "次才输出。" << endl;

接下来就是我们的重头戏了,把每一个字符串中的子串找出来,然后在每一个字符串里寻找有没有这个子串(我们借助了set::find()函数):如果有,count++,直到count达到number的值就把这个子串插入到另一个已经定义好的字符串集合中去而不是立即输出这个子串,这样可以避免相同子串重复输出的问题。
具体代码如下:

/*--------------------------找出字符串中的所有子串---------------------------*/
set<string>::iterator it = s.begin();
set<string> s_sub;//满足符合条件的子串集合
string sub_str = "\0";//存储字符串中的子串
for (int i = 0; i < SIZE; i++) {//对字符串集合中的SIZE个字符串循环
    for (int j = 0; j < SUBNUM; ) {//SUBNUM为给定长度length的字符串中所包含的所有子串数目,其值可以用数学方法算出来等于(length^2-4)/2
        string::const_iterator p = (*it).begin();
        for (int n = 1; n <= length-1; n++) {
            for (int k = 0; k <= length - n; k++) {
                for (int c = 0; c < n; c++) {
                    sub_str.push_back(p[k + c]);
                }
                j++;
                int count = 0;
                for (set<string>::iterator q = s.begin(); q != s.end(); q++) {
                    if ((*q).find(sub_str) != string::npos) {
                        count++;
                    }
                }
                string temp = "\0";
                temp = sub_str;
                sub_str = "\0";
                if (count >= number) {
                    s_sub.insert(temp);
                }
            }

            p = (*it).begin();
        }
    }
    ++it;
}

大功还没有告成,我们还需要输出一下所有满足条件的子串集合:

int num = 0;
for (set<string>::iterator i = s_sub.begin(); i != s_sub.end(); i++) {
    cout << *i << "\t";
    num++;
}
cout << "共有" << num << "个子串" << endl;
cout << endl << endl;
it = s.begin();
for (it; it != s.end(); it++) {
    cout << *it << '\n';
}

为了观察这个算法的运行时间,我在算法执行前定义了两个clock_t变量,分别表示算法执行前和执行完毕的时间,最后取其差值输出。

clock_t start, finish;
start = clock();
/*算法执行*/
......
/*执行结束*/
finish = clock();
cout << "运行时间为:" << (finish - start) / CLOCKS_PER_SEC << "s" << endl;

然后我们来看一下运行结果。为了在博客中看着方便,我们将阈值取得大一点,比如0.9:

运行结果:
这里写图片描述
运行时间:
这里写图片描述

小伙伴们,然而还有一个头疼的问题是我们之前定义的那个字符串数组,定义的时候宝宝的手指敲得都要累死了,为了提高生产率,我们再优化一下,采用读文件的方法来把字符串插入到字符串集合中去。代码如下:

const char* filename = "G:\\set.txt";
ifstream inFile(filename);
if (!inFile) {
    cout << "\nFailed to open file" << filename;
    return 1;
}
string st = "\0";
char buf[100];
while (!inFile.eof()) {
    inFile.getline(buf, 100);
    st = buf;
    if (strlen(buf) == 0)
        break;
    s.insert(st);
}
inFile.close();

再来看一下结果?嗯…….
这里写图片描述

至此,大功告成!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值