解析摩尔斯电码

时间:2014-05-14 20:58:31

标签: algorithm parsing morse-code

我正在努力解决this problem。 目标是确定莫尔条纹的解释方式,给定一个单词字典。 我所做的是我首先将我的词典中的单词“翻译”成莫尔斯语。然后,我使用了一个朴素的算法,搜索它可以递归解释的所有方法。

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <iterator>
using namespace std;

string morse_string;
int morse_string_size;
map<char, string> morse_table;
unsigned int sol;

void matches(int i, int factor, vector<string> &dictionary) {
    int suffix_length = morse_string_size-i;
    if (suffix_length <= 0) {
        sol += factor;
        return;
    }
    map<int, int> c;
    for (vector<string>::iterator it = dictionary.begin() ; it != dictionary.end() ; it++) {
        if (((*it).size() <= suffix_length) && (morse_string.substr(i, (*it).size()) == *it)) {
            if (c.find((*it).size()) == c.end())
                c[(*it).size()] = 0;
            else
                c[(*it).size()]++;
        }
    }

    for (map<int, int>::iterator it = c.begin() ; it != c.end() ; it++) {
        matches(i+it->first, factor*(it->second), dictionary);
    }
}

string encode_morse(string s) {
    string ret = "";
    for (unsigned int i = 0 ; i < s.length() ; ++i) {
        ret += morse_table[s[i]];
    }
    return ret;
}

int main() {
    morse_table['A'] = ".-"; morse_table['B'] = "-..."; morse_table['C'] = "-.-."; morse_table['D'] = "-.."; morse_table['E'] = "."; morse_table['F'] = "..-."; morse_table['G'] = "--."; morse_table['H'] = "...."; morse_table['I'] = ".."; morse_table['J'] = ".---"; morse_table['K'] = "-.-"; morse_table['L'] = ".-.."; morse_table['M'] = "--"; morse_table['N'] = "-."; morse_table['O'] = "---"; morse_table['P'] = ".--."; morse_table['Q'] = "--.-"; morse_table['R'] = ".-."; morse_table['S'] = "..."; morse_table['T'] = "-"; morse_table['U'] = "..-"; morse_table['V'] = "...-"; morse_table['W'] = ".--"; morse_table['X'] = "-..-"; morse_table['Y'] = "-.--"; morse_table['Z'] = "--..";
    int T, N;
    string tmp;
    vector<string> dictionary;
    cin >> T;

    while (T--) {
        morse_string = "";
        cin >> morse_string;
        morse_string_size = morse_string.size();
        cin >> N;
        for (int j = 0 ; j < N ; j++) {
            cin >> tmp;
            dictionary.push_back(encode_morse(tmp));
        }

        sol = 0;
        matches(0, 1, dictionary);
        cout << sol;

        if (T)
            cout << endl << endl;
    }

    return 0;
}

现在问题是我只允许3秒的执行时间,并且我的算法在这个时间限制下无法工作。

这是做这件事的好方法,如果是这样,我错过了什么?否则,你能否给出一些关于什么是好策略的提示?

编辑: 字典中最多可以有10 000个单词,莫尔斯字符串中最多可以有1000个单词。

1 个答案:

答案 0 :(得分:0)

将动态编程与rolling hash相结合的解决方案应该适用于此问题。

让我们从一个简单的动态编程解决方案开始。我们分配一个向量,用于存储morse_string前缀的已知计数。然后我们遍历morse_string并在每个位置迭代所有单词,我们回头看看它们是否适合morse_string。如果它们适合,那么我们使用动态编程向量来确定我们可以构建morse_string前缀到i-dictionaryWord.size()

的方式的数量。
vector<long>dp;
dp.push_back(1);
for (int i=0;i<morse_string.size();i++) {
   long count = 0;
   for (int j=1;j<dictionary.size();j++) {
       if (dictionary[j].size() > i) continue;
       if (dictionary[j] == morse_string.substring(i-dictionary[j].size(),i)) {
           count += dp[i-dictionary[j].size()];
       }
   }
   dp.push_back(count);
}
result = dp[morse_code.size()]

这个解决方案的问题是它太慢了。假设Nmorse_string的长度,Mdictionary的大小,K是字典中最大单词的大小。它将执行O(N*M*K)次操作。如果我们假设K=1000这大约是10^10次操作,这在大多数机器上都太慢了。

K费用来自dictionary[j] == morse_string.substring(i-dictionary[j].size(),i)

如果我们可以将这个字符串匹配加速到常量或对数复杂度,我们就可以了。这就是滚动哈希的用武之地。如果你构建一个morse_string的滚动哈希数组,那么你可以计算morse_stringO(1)的任何子字符串的哈希值。那么你可以做hash(dictionary[j]) == hash(morse_string.substring(i-dictionary[j].size(),i))

这很好但是在存在不完美的散列的情况下,你可以从字典中使用相同的散列来获得多个单词。这意味着在获得哈希匹配后,您仍然需要匹配字符串以及哈希值。在编程竞赛中,人们通常会假设完美的散列并跳过字符串匹配。这通常是一个安全的赌注,特别是在一本小字典上。如果它不能产生完美的散列(您可以检查代码),您可以随时调整散列函数,并且可能调整的散列函数将产生完美的散列。