使用字典将一串单词重建为英语句子

时间:2016-10-18 15:57:04

标签: algorithm

我完全难过了。问题是:鉴于你有一个字符串,如#34; thisisasentence"函数isWord()如果是英文单词则返回true,我会卡在"这是一个发送的"

我如何以递归方式返回并跟踪每次我的位置?

2 个答案:

答案 0 :(得分:1)

您需要backtracking,这可以通过递归轻松实现。重点观察是,当您准备好返回解决方案时,您无需跟踪过去的位置。

当满足以下条件之一时,您有一个有效的“拆分”:

  • 字符串w为空(基本情况)或
  • 您可以将非空w分为子字符串ps,以便p+s=wp为单词,{{1} }可以分成一个句子(递归调用)。

实现可以在找到成功拆分时返回单词列表,或者在找不到时找到s。基本案例将始终返回一个空列表;递归情况,在找到导致null的非空返回的ps拆分后,构造一个列表,其中s前缀为从递归返回的列表调用

递归的情况下会有一个循环,尝试p的所有可能的前缀。为了加快速度,循环可以在到达与字典中最长的单词长度相等的前缀时终止。例如,如果最长的单词有12个字符,则您知道尝试13个字符或更长的前缀不会导致匹配,因此您可以缩短枚举次数。

答案 1 :(得分:0)

只是添加上面的答案。

根据我的经验,很多人在看到递归算法的“线性化”版本时会更好地理解递归,这意味着«作为堆栈上的循环实现»。线性化适用于任何递归任务。

假设isWord()有两个参数(第一个:要测试的字符串;第二个:它的长度)并返回一个布尔兼容的值,后退的C实现如下:

void doSmth(char *phrase, int *words, int total) {
    int i;

    for (i = 0; i < total; ++i)
        printf("%.*s ", words[i + 1] - words[i], phrase + words[i]);
    printf("\n");
}

void parse(char *phrase) {
    int current, length, *words;

    if (phrase) {
        words = (int*)calloc((length = strlen(phrase)) + 2, sizeof(int));
        current = 1;
        while (current) {
            for (++words[current]; words[current] <= length; ++words[current])
                if (isWord(phrase + words[current - 1],
                           words[current] - words[current - 1])) {
                    words[current + 1] = words[current];
                    current++;
                }
            if (words[--current] == length)
                doSmth(phrase, words, current); /** parse successful! **/
        }
        free(words);
    }
}

可以看出,对于每个单词,使用一对堆栈值,第一个是当前单词的第一个字符的偏移量,而第二个是当前字符恰好在当前字符之后的潜在偏移量word`s last one(因此是下一个单词的第一个字符)。当前单词的第二个值(其对位于我们的«stack»顶部的那个)将遍历短语中剩下的所有字符。

当一个单词被接受时,新的第二个值(等于当前,仅查看其后的位置)被推入堆栈,使前者成为新对中的第一个。如果当前单词(刚刚找到的单词)完成短语,则执行一些有用的操作;见doSmth()

如果我们的短语的剩余部分中没有可接受的单词,则当前单词被认为是不合适的,并且其第二个值从堆栈中被丢弃,有效地重复搜索前一个起始位置处的单词,而结束位置现在比之前接受的那个词更远。