Редакция для Морзе в двоичной записи
Submitting an official solution before solving the problem yourself is a bannable offence.
1. Идея
Нужно декодировать сообщение, записанное в необычном виде:
0— это точка азбуки Морзе;1— это тире;- отдельные коды разделены пробелами;
- символ
/означает границу между словами.
Значит, задача сводится к двум шагам:
- построить таблицу соответствия: двоичный код
->буква или цифра; - прочитать входную строку по токенам и для каждого токена:
- если это
/, добавить пробел; - иначе найти символ в таблице и добавить его в ответ.
- если это
2. Наблюдения
Наблюдение 1. Удобно заранее создать словарь декодирования
В условии используются только латинские заглавные буквы A–Z и цифры 0–9.
Для всех них известны стандартные коды Морзе.
Например:
A—.-B—-...1—.----
Но во входе вместо . и - используются 0 и 1.
Значит:
.-превращается в01-...превращается в1000.----превращается в01111
Если заранее перевести все обычные коды Морзе в двоичные и сохранить в словарь, декодирование станет очень простым.
Наблюдение 2. Вход удобно разбить на токены
Так как все элементы разделены пробелами, строку можно разбить на части:
- двоичные коды символов;
- символ
/.
После этого остаётся просто пройти по списку токенов слева направо.
Наблюдение 3. Корректность входа гарантируется
В условии сказано, что вход всегда корректен.
Значит, можно не проверять, есть ли код в словаре: он там точно будет.
3. Алгоритм
- Считать всю строку целиком.
- Задать список пар: обычный код Морзе и соответствующий символ.
- Построить словарь
decode:- для каждого кода Морзе заменить:
.на0-на1
- сохранить результат как ключ, а букву или цифру как значение.
- для каждого кода Морзе заменить:
- Разбить входную строку по пробелам на токены.
- Создать пустой ответ.
- Для каждого токена:
- если токен равен
/, добавить в ответ пробел; - иначе добавить
decode[token].
- если токен равен
- Вывести получившуюся строку.
4. Почему это работает
Докажем, что алгоритм действительно восстанавливает исходное сообщение.
Сначала строится таблица, в которой каждому допустимому двоичному коду сопоставлен ровно один символ.
Эта таблица верна, потому что она получена напрямую из стандартной азбуки Морзе заменой:
.на0;-на1.
Затем вход разбивается на токены exactly по тому формату, который описан в условии:
- коды символов разделены пробелами;
- между словами стоит отдельный токен
/.
Теперь рассмотрим любой токен:
- если это
/, по условию он означает разделение слов, значит в ответ нужно добавить пробел; - если это двоичный код, то по гарантии корректности он соответствует некоторой букве или цифре, и словарь возвращает именно этот символ.
Таким образом, каждый токен преобразуется правильно, а значит и вся строка декодируется правильно.
5. Сложность
Пусть n — длина входной строки.
- Построение словаря занимает константное время, потому что символов всего 36.
- Разбор строки и декодирование занимают
O(n), так как каждый символ входа обрабатывается не более нескольких раз.
Итоговая сложность: O(n).
По памяти:
- словарь имеет фиксированный размер;
- дополнительно хранится ответ.
Итог: O(n) памяти с учётом ответа.
6. Код на C++17
#include <iostream>
#include <string>
#include <sstream>
#include <unordered_map>
#include <vector>
using namespace std;
int main() {
string s;
getline(cin, s);
vector<pair<string, char>> morse = {
{".-", 'A'}, {"-...", 'B'}, {"-.-.", 'C'}, {"-..", 'D'}, {"." , 'E'},
{"..-.", 'F'}, {"--.", 'G'}, {"....", 'H'}, {"..", 'I'}, {".---", 'J'},
{"-.-", 'K'}, {".-..", 'L'}, {"--", 'M'}, {"-.", 'N'}, {"---", 'O'},
{".--.", 'P'}, {"--.-", 'Q'}, {".-.", 'R'}, {"...", 'S'}, {"-", 'T'},
{"..-", 'U'}, {"...-", 'V'}, {".--", 'W'}, {"-..-", 'X'}, {"-.--", 'Y'},
{"--..", 'Z'},
{"-----", '0'}, {".----", '1'}, {"..---", '2'}, {"...--", '3'}, {"....-", '4'},
{".....", '5'}, {"-....", '6'}, {"--...", '7'}, {"---..", '8'}, {"----.", '9'}
};
unordered_map<string, char> decode;
for (auto &p : morse) {
string bin;
for (char c : p.first) {
if (c == '.') {
bin += '0';
} else {
bin += '1';
}
}
decode[bin] = p.second;
}
stringstream ss(s);
string token;
string ans;
while (ss >> token) {
if (token == "/") {
ans += ' ';
} else {
ans += decode[token];
}
}
cout << ans << '\n';
return 0;
}
7. Код на Python 3
s = input()
morse = [
(".-", 'A'), ("-...", 'B'), ("-.-.", 'C'), ("-..", 'D'), (".", 'E'),
("..-.", 'F'), ("--.", 'G'), ("....", 'H'), ("..", 'I'), (".---", 'J'),
("-.-", 'K'), (".-..", 'L'), ("--", 'M'), ("-.", 'N'), ("---", 'O'),
(".--.", 'P'), ("--.-", 'Q'), (".-.", 'R'), ("...", 'S'), ("-", 'T'),
("..-", 'U'), ("...-", 'V'), (".--", 'W'), ("-..-", 'X'), ("-.--", 'Y'),
("--..", 'Z'),
("-----", '0'), (".----", '1'), ("..---", '2'), ("...--", '3'), ("....-", '4'),
(".....", '5'), ("-....", '6'), ("--...", '7'), ("---..", '8'), ("----.", '9')
]
decode = {}
for code, ch in morse:
binary = ""
for c in code:
if c == '.':
binary += '0'
else:
binary += '1'
decode[binary] = ch
tokens = s.split()
ans = []
for token in tokens:
if token == "/":
ans.append(" ")
else:
ans.append(decode[token])
print("".join(ans))
Комментарии