diff --git a/conditions/lesson05/tasks.md b/conditions/lesson05/tasks.md new file mode 100644 index 00000000..148654ae --- /dev/null +++ b/conditions/lesson05/tasks.md @@ -0,0 +1,171 @@ +# Задача 1: Туда-сюда + +**Условие:** +Строка называется **палиндромом**, если она читается одинаково слева направо и справа налево. При этом **регистр букв игнорируется**: `'A'` и `'a'` считаются одинаковыми символами. + +Ваша задача — определить, является ли заданная строка палиндромом. + +Допишите код в файле [task1](https://github.com/EvgrafovMichail/python_mipt_dafe_tasks/blob/main/solutions/lesson05/task1.py). + +**Входные данные:** +- `text` — строка, состоящая из букв английского алфавита в верхнем и нижнем регистре длиной от 0 до 1000. + +**Выходные данные:** +- `True`, если строка является палиндромом (с учётом игнорирования регистра), `False` - иначе. + +**Примеры:** + +| Входные данные | Выходные данные | +|----------------|-----------------| +| `"aba"` | `True` | +| `"Aa"` | `True` | +| `"hello"` | `False` | + + +# Задача 2: Mr. Mojo Risin +**Условие:** +Два слова называются **анаграммами**, если одно можно получить из другого перестановкой букв. При этом **регистр букв имеет значение**: символы `'A'` и `'a'` считаются **разными**. + +Ваша задача — определить, являются ли два заданных слова анаграммами. Решение должно работать за **O(N + M)** времени и использовать не более **O(1)** дополнительной памяти (где **N** и **M** — длины слов). + +Допишите код в файле [task2](https://github.com/EvgrafovMichail/python_mipt_dafe_tasks/blob/main/solutions/lesson05/task2.py). + +**Входные данные:** +- `word1` — непустая строка из букв английского алфавита (верхний и нижний регистр), длиной от 1 до 1000; +- `word2` — непустая строка из букв английского алфавита (верхний и нижний регистр), длиной от 1 до 1000. + +**Выходные данные:** +- `True`, если слова являются анаграммами (с учётом регистра), `False` - иначе. + +**Примеры:** + +| Входные данные | Выходные данные | +|---------------------|-----------------| +| `listen`
`silent`| `True` | +| `abc`
`aac` | `False` | + + +# Задача 3: ?! +**Условие:** +Вам дана строка. Требуется определить, состоит ли она **исключительно из знаков пунктуации** (без букв, цифр, пробелов и любых других символов). + +К знакам пунктуации относятся: **!"#$%&\'()*+,-./:;<=>?@[\\]^_{|}~`** + +Пустая строка **не считается** строкой из пунктуации. + +Допишите код в файле [task3](https://github.com/EvgrafovMichail/python_mipt_dafe_tasks/blob/main/solutions/lesson05/task3.py). + +**Входные данные:** +- `text` — строка из букв, цифр, пробелов и знаков препинания, длиной от 0 до 1000 символов. + +**Выходные данные:** +- `True`, если строка **непустая** и **каждый её символ** является знаком пунктуации, `False` — иначе. + +**Примеры:** + +| Входные данные | Выходные данные | +|----------------|-----------------| +| `"!?."` | `True` | +| `"Hello!"` | `False` | +| `""` | `False` | + +# Задача 4: Разархиватор +**Условие:** +Некоторый архиватор сжимает тексты, состоящие **только из букв** (без пробелов и других символов), следующим образом: +- Если в тексте встречается подстрока, повторяющаяся **N раз подряд**, она заменяется на запись вида `подстрока*N`. +- Все такие фрагменты (сжатые и несжатые) записываются в результат через **пробел**. + +Например, строка `'AbcDAbcDAbcDAbcDefGhIGhI'` может быть заархивирована как `'AbcD*4 ef GhI*2'`. + +Ваша задача — реализовать **разархиватор**: по заархивированной строке восстановить исходный текст. + +Допишите код в файле [task4](https://github.com/EvgrafovMichail/python_mipt_dafe_tasks/blob/main/solutions/lesson05/task4.py). + +**Входные данные:** +- `compress_text` — строка, содержащая токены, разделённые пробелами, длиной не более 1000. Каждый токен состоит: + - либо только из букв (например, `ef`); + - либо имеет формат `B*N`, где `B` — непустая строка из букв, `N` — целое неотрицательное число (например, `AbcD*4`). + +**Выходные данные:** +- Строка, состоящая **только из букв** — результат разархивации. + + +**Примеры:** + +| Входные данные | Выходные данные | +|------------------------|-------------------------------| +| `AbcD*4 ef GhI*2` | `AbcDAbcDAbcDAbcDefGhIGhI` | +| `a*3 b*2` | `aaabb` | + +# Задача 5: Простые (или нет) регулярные выражения + +**Условие:** + +В программировании при работе со строками вы повстречаетесь с так называемыми регулярными выражениями. Они много, где используются, но сегодня с помощью них мы будем проверять соответствует ли строка нужному формату. Использовать настоящие регулярные выражения мы не будем, так как они достаточно сложные, поэтому работать мы будем со своим аналогом. +Итак, регулярное выражение – это строка, содержащая следующие символы: + +- `d` означает, что в строке в этом месте записано целое число; +- `w` означает, что в строке в этом месте записано слово, состоящее только из букв; +- `s` означает, что в строке в этом месте записана строка, состоящая только из букв или цифр; +- любой символ не буква и не цифра (может быть пробел) - это означает, что в этом месте стоит (один) написаный символ. + +В регулярном выражении не могут подряд стоять `dd`, `ww`, `ss`, `sd`, `sw`, `ws`, `ds`. + +Мы утверждаем, что строка соответствует регулярному выражению, если порядок символов в строке соответствует порядку символов в регулярном выражении. +То есть, например, если регулярное выражение равно `“d-dw”` – это означает, что в строке должно быть записано целое число, потом `-`, потом опять число, потом строка из букв и если чего-то нет, например, второго числа или наоборот есть лишнее, например после первого числа идет буква, то мы говорим, что строка не соответствует регулярному выражению. Таким образом, строка `"12-45abc"` соответствует регулярному выражению, а строки `"1-abs"`, `"1-b123r"`, `"1--123vdg"` - нет. + +*Использование модуля `re` или других инструментов для работы с регулярными выражениями запрещено.* + +Допишите код в файле [task5](https://github.com/EvgrafovMichail/python_mipt_dafe_tasks/blob/main/solutions/lesson05/task5.py). + +**Входные данные:** +- `reg_expr` - cтрока, состоящая из букв `d`, `w` и `s` и символов (не буквы и не цифры) - регулярное выражение. Длина строки находится в диапазоне от 0 до 10; +- `text` - строка, состоящая из букв английского алфавита верхнего и нижнего регистра, цифр и других символов - строка, которую надо проверить на соответствие регулярному выражению. Длина строки от 0 до 100. + +**Выходные данные:** +- `True` - если строка соответствует регулярному выражению, `False` - иначе. + +**Примеры:** + +| Входные данные | Выходные данные | +|------------------------|-----------------| +| `d-dw`
`123-456abc` | `True` | +| `d-dw`
`123-456` | `False` | +| `s-dw`
`123a-456abc`| `True` | + +# Задача 6: У самурая нет цели, есть только путь + +**Условие:** + +Вы разрабатываете файловое хранилище в Unix-подобной системе. Пользователи вашего хранилища могут получать доступ к файлам и к директориям, указав абсолютный путь до требуемого ресурса. Поисковый движок вашей файловой системы при поиске ресурса в точности повторяет обход файловой системы, описанный пользователем. Поскольку пользователи могут писать неоптимальные запросы на обход файловой системы (путь к ресурсу), перед вами встала задача реализации алгоритма упрощения пути, с целью избежать лишних обходов директорий. + +В Unix-подобной файловой системе одиночная точка `.` обозначает текущий каталог, двойная точка '..' обозначает перемещение на один уровень вверх, а несколько косых черт, таких как `//`, интерпретируются как одна косая черта. Последовательности точек, не охваченные предыдущими правилами (например, `...`), рассматриваются как допустимые имена файлов или каталогов. + +Упрощенный канонический путь должен соответствовать следующим правилам: + +- Он должен начинаться с одной косой черты `/`. +- Каталоги в пути должны быть разделены только одной косой чертой `/`. +- Он не должен заканчиваться косой чертой `/`, если только это не корневой каталог. +- Он должен исключить любые одиночные или двойные точки, используемые для обозначения текущих или родительских каталогов. + +Ваша задача реализовать алгоритм для упрощения переданного пути. + +Если изначальный путь поднимается выше корневого каталога, например, `/../` или `/a/../../`, то необходимо вернуть пустую строку. + +Допишите код в файле [task6](https://github.com/EvgrafovMichail/python_mipt_dafe_tasks/blob/main/solutions/lesson05/task6.py). + +**Входные данные:** + +- `path` - строка, состоящая из букв английского алфавита в верхнем и нижнем регистре, и символов `.`, `/`, `_`. Длина строки находится в диапазоне от 1 до 1000. + +**Выходные данные:** +- Строка - упрощенный абсолютный канонический путь. + +**Примеры:** + +| Входные данные | Выходные данные | +|-----------------------------------------|-------------------------------| +| `"/home/"` | `"/home"` | +| `/home/user/./Documents/../Pictures` | `"/home/user/Pictures"` | +| `/home//foo/` | `"/home/foo"` | +| `/../foo/` | `""` | diff --git a/solutions/lesson05/__init__.py b/solutions/lesson05/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/solutions/lesson05/task1.py b/solutions/lesson05/task1.py new file mode 100644 index 00000000..9a17211e --- /dev/null +++ b/solutions/lesson05/task1.py @@ -0,0 +1,3 @@ +def is_palindrome(text: str) -> bool: + # ваш код + return False \ No newline at end of file diff --git a/solutions/lesson05/task2.py b/solutions/lesson05/task2.py new file mode 100644 index 00000000..36750380 --- /dev/null +++ b/solutions/lesson05/task2.py @@ -0,0 +1,3 @@ +def are_anagrams(word1: str, word2: str) -> bool: + # ваш код + return False \ No newline at end of file diff --git a/solutions/lesson05/task3.py b/solutions/lesson05/task3.py new file mode 100644 index 00000000..e368e2f4 --- /dev/null +++ b/solutions/lesson05/task3.py @@ -0,0 +1,3 @@ +def is_punctuation(text: str) -> bool: + # ваш код + return False diff --git a/solutions/lesson05/task4.py b/solutions/lesson05/task4.py new file mode 100644 index 00000000..4c4e9086 --- /dev/null +++ b/solutions/lesson05/task4.py @@ -0,0 +1,3 @@ +def unzip(compress_text: str) -> str: + # ваш код + return compress_text \ No newline at end of file diff --git a/solutions/lesson05/task5.py b/solutions/lesson05/task5.py new file mode 100644 index 00000000..076c5bb6 --- /dev/null +++ b/solutions/lesson05/task5.py @@ -0,0 +1,3 @@ +def reg_validator(reg_expr: str, text: str) -> bool: + # ваш код + return False \ No newline at end of file diff --git a/solutions/lesson05/task6.py b/solutions/lesson05/task6.py new file mode 100644 index 00000000..1b914ada --- /dev/null +++ b/solutions/lesson05/task6.py @@ -0,0 +1,3 @@ +def simplify_path(path: str) -> str: + # ваш код + return path \ No newline at end of file diff --git a/tests/test_lesson05_tasks.py b/tests/test_lesson05_tasks.py new file mode 100644 index 00000000..2ab63e3b --- /dev/null +++ b/tests/test_lesson05_tasks.py @@ -0,0 +1,151 @@ +import pytest + +from solutions.lesson05.task1 import is_palindrome +from solutions.lesson05.task2 import are_anagrams +from solutions.lesson05.task3 import is_punctuation +from solutions.lesson05.task4 import unzip +from solutions.lesson05.task5 import reg_validator +from solutions.lesson05.task6 import simplify_path + +@pytest.mark.parametrize("s, expected", [ + pytest.param("", True, id="empty_string"), + pytest.param("a", True, id="single_char"), + pytest.param("aa", True, id="two_same"), + pytest.param("ab", False, id="two_different"), + pytest.param("aba", True, id="odd_palindrome"), + pytest.param("abba", True, id="even_palindrome"), + pytest.param("abcba", True, id="long_odd_palindrome"), + pytest.param("abccba", True, id="long_even_palindrome"), + pytest.param("abc", False, id="not_palindrome"), + pytest.param("Aa", True, id="case_sensitive_mismatch"), + pytest.param("Racecar", True, id="real_word_case_sensitive"), + pytest.param("aA", True, id="reverse_case"), + pytest.param("abcdefedcba", True, id="long_true"), + pytest.param("abcdefedcbx", False, id="long_false"), +]) +def test_is_palindrome(s, expected): + assert is_palindrome(s) == expected + + +@pytest.mark.parametrize("w1, w2, expected", [ + pytest.param("listen", "silent", True, id="classic_anagram"), + pytest.param("evil", "vile", True, id="another_anagram"), + pytest.param("a", "a", True, id="single_char_same"), + pytest.param("A", "A", True, id="single_upper_same"), + pytest.param("A", "a", False, id="case_sensitive_diff"), + pytest.param("Listen", "Silent", False, id="mixed_case_not_anagram"), + pytest.param("Aa", "aA", True, id="same_chars_permuted"), + pytest.param("Ab", "ab", False, id="one_letter_case_diff"), + pytest.param("abc", "cba", True, id="permuted_same_case"), + pytest.param("abc", "Cba", False, id="case_breaks_anagram"), + pytest.param("aabbcc", "abcabc", True, id="repeated_letters"), + pytest.param("aabbcc", "aabbcd", False, id="extra_different_char"), +]) +def test_are_anagrams_linear(w1, w2, expected): + assert are_anagrams(w1, w2) == expected + + +@pytest.mark.parametrize("s, expected", [ + pytest.param("!!!", True, id="only_exclamations"), + pytest.param("...?", True, id="dots_and_question"), + pytest.param("", False, id="empty_string"), + pytest.param("a", False, id="letter"), + pytest.param("1", False, id="digit"), + pytest.param(" ! ", False, id="space_inside"), + pytest.param("!?.", True, id="symbols_only"), + pytest.param("!a!", False, id="letter_in_middle"), + pytest.param(" ", False, id="only_space"), + pytest.param(".,;", True, id="commas_dots_semicolons"), + pytest.param("", False, id="commas_dots_semicolons"), +]) +def test_is_only_punctuation(s, expected): + assert is_punctuation(s) == expected + +@pytest.mark.parametrize("compressed, expected", [ + pytest.param("AbcD*4 ef GhI*2", "AbcDAbcDAbcDAbcDefGhIGhI", id="example"), + pytest.param("a*3 b*2", "aaabb", id="simple_letters"), + pytest.param("Hello", "Hello", id="star_one"), + pytest.param("xyz", "xyz", id="no_compression"), + pytest.param("", "", id="empty_input"), + pytest.param("Test*2 Space", "TestTestSpace", id="mixed"), + pytest.param("a*10", "aaaaaaaaaa", id="ten_a"), + pytest.param("x y z", "xyz", id="three_plain"), + pytest.param("Word word", "Wordword", id="case_sensitive"), +]) +def test_decompress(compressed, expected): + assert unzip(compressed) == expected + +@pytest.mark.parametrize("regexp, s, expected", [ + pytest.param("d", "123", True, id="d_valid_number"), + pytest.param("d", "0", True, id="d_zero"), + pytest.param("d", "abc", False, id="d_letters_instead_of_digits"), + pytest.param("d", "", False, id="d_empty_string"), + pytest.param("w", "hello", True, id="w_lowercase_word"), + pytest.param("w", "HelloWorld", True, id="w_mixed_case_word"), + pytest.param("w", "hello123", False, id="w_word_with_digits"), + pytest.param("w", "", False, id="w_empty_string"), + pytest.param("s", "abc123", True, id="s_alphanum"), + pytest.param("s", "ABC99", True, id="s_uppercase_and_digits"), + pytest.param("s", "abc_123", False, id="s_contains_underscore"), + pytest.param("s", "", False, id="s_empty_string"), + pytest.param("d-d", "12-34", True, id="d_dash_d_valid"), + pytest.param("d-d", "12--34", False, id="d_dash_d_double_dash"), + pytest.param("d-d", "12-abc", False, id="d_dash_d_letters_after_dash"), + pytest.param("d-d", "1234", False, id="d_dash_d_missing_dash"), + pytest.param("w.w", "hi.there", True, id="w_dot_w_valid"), + pytest.param("w.w", "hi..there", False, id="w_dot_w_double_dot"), + pytest.param("w.w", "hi1.there", False, id="w_dot_w_digit_in_first_word"), + pytest.param("s.s", "h1i.th32ere", True, id="s_dot_s_valid"), + pytest.param("s.s", "hi4..t2here", False, id="s_dot_s_double_dot"), + pytest.param("d-dw", "12-45abc", True, id="example_valid"), + pytest.param("d-dw", "1-abs", False, id="example_second_part_not_digit"), + pytest.param("d-dw", "1-b123r", False, id="example_letter_after_dash"), + pytest.param("d-dw", "1--123vdg", False, id="example_double_dash"), + pytest.param("d-dw", "123-456XYZ", True, id="d-dw_all_caps"), + pytest.param("d-dw", "0-0a", True, id="d-dw_minimal_valid"), + pytest.param("d@d", "5@7", True, id="d_at_d_valid"), + pytest.param("d@d", "5@@7", False, id="d_at_d_double_at"), + pytest.param("w s", "hi 123", True, id="w_space_s_valid"), + pytest.param("w s", "hi123", False, id="w_space_s_missing_space"), + pytest.param("w s", "hi 123!", False, id="w_space_s_extra_char_in_s"), + pytest.param("", "", True, id="empty_regexp_empty_string"), + pytest.param("", "a", False, id="empty_regexp_non_empty_string"), + pytest.param("d", "", False, id="non_empty_regexp_empty_string"), + pytest.param("d!", "5!", True, id="d_exclam_valid"), + pytest.param("d!", "5", False, id="d_exclam_missing_exclam"), + pytest.param("d!", "5!!", False, id="d_exclam_extra_exclam"), + pytest.param("s", "a1", True, id="s_letter_digit"), + pytest.param("s", "1a", True, id="s_digit_letter"), + pytest.param("s", "a!1", False, id="s_contains_exclamation"), + pytest.param("d-w-s", "123-abc-XY1Z23", True, id="d_w_s_valid"), + pytest.param("d-w-s", "123-abc-XYZ_123", False, id="d_w_s_underscore_in_s"), +]) +def test_match_pattern(regexp, s, expected): + assert reg_validator(regexp, s) == expected + + +@pytest.mark.parametrize("path, expected", [ + pytest.param("/home/", "/home", id="trailing_slash"), + pytest.param("/../", "", id="go_above_root"), + pytest.param("/home//foo/", "/home/foo", id="double_slash"), + pytest.param("/home/./foo/", "/home/foo", id="current_dir_dot"), + pytest.param("/./././", "/", id="only_dots_and_slashes"), + pytest.param("/a/./b/../../c/", "/c", id="complex_up_and_down"), + pytest.param("/a/b/c/../../../", "/", id="back_to_root"), + pytest.param("/", "/", id="root_only"), + pytest.param("/.", "/", id="root_with_dot"), + pytest.param("/..", "", id="root_with_double_dot"), + pytest.param("/...", "/...", id="triple_dot_as_name"), + pytest.param("/..a", "/..a", id="dot_dot_a_as_name"), + pytest.param("/a.b/c.d", "/a.b/c.d", id="names_with_dots"), + pytest.param("/a//b////c/d//././/..", "/a/b/c", id="messy_path"), + pytest.param("/a/./b/./c/./d", "/a/b/c/d", id="dots_everywhere"), + pytest.param("/a/./b/../../c/./d/", "/c/d", id="up_down_with_dots"), + pytest.param("/../foo", "", id="up_then_valid"), + pytest.param("/../../foo", "", id="multiple_up_then_valid"), + pytest.param("/../../../", "", id="three_up_from_root"), + pytest.param("/home/foo/./../../../", "", id="too_many_up"), + pytest.param("/_a.b/c__1/..", "/_a.b", id="names_with_underscores_and_dots"), +]) +def test_simplify_path(path, expected): + assert simplify_path(path) == expected \ No newline at end of file