我有一些莫尔斯代码丢失了字母之间的空格,我的挑战是找出消息所说的内容。到目前为止,由于可能存在大量的组合,我有点失落。
以下是我所拥有的消息的所有信息。
-..-...-...-...-..-.-.-.-.-..-.-.-.-.-.-.-.-.-.-..-...-.
有没有人有一个聪明的解决方案?
答案 0 :(得分:7)
这不是一个容易的问题,因为正如鲁赫所说,给定的信息有许多可行的句子。例如,“JACK AND JILL WENT UP THE HILL”具有与“JACK AND JILL WALK CHISELED”相同的编码。由于这些都是语法句子,并且每个中的单词都很常见,所以如何选择一个或另一个(或任何其他40141055989476564163599不同的英语单词序列与此消息具有相同的编码)并不明显,如果不钻研自然语言处理
无论如何,这里有一个动态编程解决方案来解决找到最短句子的问题(如果有一个平局则用最少的字符)。它还可以计算与给定消息具有相同编码的句子总数。它需要一个文件中的英文单词字典。
下一个增强功能应该更好地衡量一个句子的可能性:也许是单词频率,莫尔斯的假阳性率(例如,“I”是一个常用词,但它通常作为其他莫尔斯序列的一部分出现代码序列)。棘手的部分是制定一个好的分数函数,可以用可以用动态编程计算的方式表达。
MORSE = dict(zip('ABCDEFGHIJKLMNOPQRSTUVWXYZ', [
'.-', '-...', '-.-.', '-..', '.', '..-.', '--.', '....',
'..', '.---', '-.-', '.-..', '--', '-.', '---', '.--.',
'--.-', '.-.', '...', '-', '..-', '...-', '.--', '-..-',
'-.--', '--..'
]))
# Read a file containing A-Z only English words, one per line.
WORDS = set(word.strip().upper() for word in open('dict.en').readlines())
# A set of all possible prefixes of English words.
PREFIXES = set(word[:j+1] for word in WORDS for j in xrange(len(word)))
def translate(msg, c_sep=' ', w_sep=' / '):
"""Turn a message (all-caps space-separated words) into morse code."""
return w_sep.join(c_sep.join(MORSE[c] for c in word)
for word in msg.split(' '))
def encode(msg):
"""Turn a message into timing-less morse code."""
return translate(msg, '', '')
def c_trans(morse):
"""Construct a map of char transitions.
The return value is a dict, mapping indexes into the morse code stream
to a dict of possible characters at that location to where they would go
in the stream. Transitions that lead to dead-ends are omitted.
"""
result = [{} for i in xrange(len(morse))]
for i_ in xrange(len(morse)):
i = len(morse) - i_ - 1
for c, m in MORSE.iteritems():
if i + len(m) < len(morse) and not result[i + len(m)]:
continue
if morse[i:i+len(m)] != m: continue
result[i][c] = i + len(m)
return result
def find_words(ctr, i, prefix=''):
"""Find all legal words starting from position i.
We generate all possible words starting from position i in the
morse code stream, assuming we already have the given prefix.
ctr is a char transition dict, as produced by c_trans.
"""
if prefix in WORDS:
yield prefix, i
if i == len(ctr): return
for c, j in ctr[i].iteritems():
if prefix + c in PREFIXES:
for w, j2 in find_words(ctr, j, prefix + c):
yield w, j2
def w_trans(ctr):
"""Like c_trans, but produce a word transition map."""
result = [{} for i in xrange(len(ctr))]
for i_ in xrange(len(ctr)):
i = len(ctr) - i_ - 1
for w, j in find_words(ctr, i):
if j < len(result) and not result[j]:
continue
result[i][w] = j
return result
def shortest_sentence(wt):
"""Given a word transition map, find the shortest possible sentence.
We find the sentence that uses the entire morse code stream, and has
the fewest number of words. If there are multiple sentences that
satisfy this, we return the one that uses the smallest number of
characters.
"""
result = [-1 for _ in xrange(len(wt))] + [0]
words = [None] * len(wt)
for i_ in xrange(len(wt)):
i = len(wt) - i_ - 1
for w, j in wt[i].iteritems():
if result[j] == -1: continue
if result[i] == -1 or result[j] + 1 + len(w) / 30.0 < result[i]:
result[i] = result[j] + 1 + len(w) / 30.0
words[i] = w
i = 0
result = []
while i < len(wt):
result.append(words[i])
i = wt[i][words[i]]
return result
def sentence_count(wt):
result = [0] * len(wt) + [1]
for i_ in xrange(len(wt)):
i = len(wt) - i_ - 1
for j in wt[i].itervalues():
result[i] += result[j]
return result[0]
msg = 'JACK AND JILL WENT UP THE HILL'
print sentence_count(w_trans(c_trans(encode(msg))))
print shortest_sentence(w_trans(c_trans(encode(msg))))
答案 1 :(得分:0)
我不知道这是否是&#34;聪明&#34;,但我会尝试广度优先搜索(而不是BRPocock正则表达式中隐含的深度优先搜索) 。假设您的字符串如下所示:
.---.--.-.-.-.--.-...---...-...-..
J A C K A N D J I L L
您从状态('', 0)
开始(''
是您目前已解码的内容; 0
是您在摩尔斯电码字符串中的位置)。从位置0开始,可能的初始字符为. E
,.- A
,.-- W
,.--- J
和.---- 1
。因此,将状态('E', 1)
,('A', 2)
,('W', 3)
,('J', 4)
和('1', 5)
推送到您的队列中。在将状态('E', 1)
出列后,您会将状态('ET', 2)
,('EM', 3)
和('EO', 4)
排入队列。
现在,您的可能状态队列将会非常快速地增长 - {.
,-
}都是字母,{..
,.-
都是字母, -.
,--
}以及所有{...
,..-
,.-.
,.--
,-..
,{{1} },-.-
,--.
},因此在每次传递中,您的状态数将增加至少三倍 - 因此您需要有一些用户反馈机制。特别是,你需要某种方式来询问你的用户&#34;这个字符串是以---
开头是否合理?&#34;,如果用户说'#34; no&#34;,你会需要从队列中丢弃状态EOS3AIOSF
。理想的情况是向用户呈现GUI,该GUI经常显示所有当前状态并让他/她选择哪些值得继续。 (&#34;用户&#34;当然也是你。英语缺少代词:如果&#34;你&#34;指的是程序,那么代词是指用户程序员?! )
答案 2 :(得分:0)
维护3件事:到目前为止的单词列表S,到目前为止的当前单词W,以及当前符号C.
现在,给定一个新符号,让我们说' - ',我们用它扩展C(在这种情况下我们得到'.--')。 如果C是一个完整的字母(在这种情况下是字母“W”),我们可以选择将其添加到W,或者通过添加更多符号继续扩展该字母。 如果我们扩展W,我们可以选择将它添加到S(如果它是一个有效的单词),或者继续进一步扩展它。
这是一个搜索,但是大多数路径都会很快终止(只要你不是任何单词的有效前缀就可以停止,只要C不是你可以停止的任何字母的前缀)。
为了提高效率,您可以使用动态编程来避免冗余工作并使用尝试来有效地测试前缀。
代码可能是什么样的?省略函数'is_word'来测试字符串是否是英文单词,省'is_word_prefix'来测试字符串是否是任何有效单词的开头,如下所示:
morse = {
'.-': 'A',
'-...': 'B',
etc.
}
def is_morse_prefix(C):
return any(k.startswith(C) for k in morse)
def break_words(input, S, W, C):
while True:
if not input:
if W == C == '':
yield S
return
i, input = input[0], input[1:]
C += i
if not is_morse_prefix(C):
return
ch = morse.get(C, None)
if ch is None or not is_word_prefix(W + ch):
continue
for result in break_words(input, S, W + ch, ''):
yield result
if is_word(W + ch):
for result in break_words(input, S + ' ' + W + ch, '', ''):
yield result
for S in break_words('....--', [], '', ''):
print S