diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/algorithms-python-17-04-21.iml b/.idea/algorithms-python-17-04-21.iml new file mode 100644 index 0000000..a293563 --- /dev/null +++ b/.idea/algorithms-python-17-04-21.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..81dd32a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..c95a575 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/task_1.py b/task_1.py new file mode 100644 index 0000000..06f575f --- /dev/null +++ b/task_1.py @@ -0,0 +1,81 @@ +""" +Задание 1. + +Для каждой из трех задач выполнить следующее: + +1) для каждой инструкции рядом в комментарии определите сложность этой инструкции +2) определите сложность алгоритма в целом + +укажите сложность непосредственно в этом файле +точки, где нужно поработать вам, отмечены знаком '!!!' +Не забудтье оценить итоговую сложность каждого из трех алгоритмов. + +Примечание: +Если у вас возникают сложности, постарайтесь подумать как можно решить задачу, +а не писать "мы это не проходили)". +Алгоритмизатор должен развивать мышление, а это прежде всего практика. +А без столкновения со сложностями его не развить. +""" + +import random + + +############################################################################################# +def check_1(lst_obj): + """Функция должна создать множество из списка. + + Алгоритм 3: + Создать множество из списка + + Сложность: n + с => O(n) - линейная. + """ + lst_to_set = set(lst_obj) # O(n) - линейная + return lst_to_set # O(1) - константная + + +############################################################################################# +def check_2(lst_obj): + """Функция должная вернуть True, если все элементы списка различаются. + + Алгоритм 1: + Проходимся по списку и для каждого элемента проверяем, + что такой элемент отстутствует + в оставшихся справа элементах + + Сложность: n * n + с => O(n^2) - квадратичная. + """ + for j in range(len(lst_obj)): # O(n) - линейная (если брать выражение само по себе) + if lst_obj[j] in lst_obj[j+1:]: # O(n) - линейная (если брать выражение само по себе) + return False # O(1) - константная + return True # O(1) - константная + + +############################################################################################# +def check_3(lst_obj): + """Функция должная вернуть True, если все элементы списка различаются. + + Алгоритм 2: + Вначале выполним для списка сортировку, далее, сравниваем элементы попарно + Если присутствуют дубли, они будут находиться рядом. + + Сложность: n + nlogn + n * c + c => O(n log n) -линейно-логарифмическая + (хотя если там не сравнение констант, то сложность квадратичная) + """ + lst_copy = list(lst_obj) # O(n) - линейная + lst_copy.sort() # O(n log n) - линейно-логарифмическая + for i in range(len(lst_obj) - 1): # O(n) - линейная (если брать выражение само по себе) + if lst_copy[i] == lst_copy[i+1]: # O(1) - константная (это же сравнение констант? если конечно элемент списка сам не является списком...) + return False # O(1) - константная + return True # O(1) - константная + +############################################################################################# + + +for j in (50, 500, 1000, 5000, 1000): + # Из 100000 чисел возьмем 'j' случайно выбранных + # Всего 10 тыс. чисел + lst = random.sample(range(-100000, 100000), j) + +print(check_1(lst)) +print(check_2(lst)) +print(check_3(lst)) diff --git a/task_2.py b/task_2.py new file mode 100644 index 0000000..f288758 --- /dev/null +++ b/task_2.py @@ -0,0 +1,44 @@ +""" +Задание 2. + +Реализуйте два алгоритма. + +Первый, в виде функции, должен обеспечивать поиск минимального значения для списка. +В основе алгоритма должно быть сравнение каждого числа со всеми другими элементами списка. +Сложность такого алгоритма: O(n^2) - квадратичная. + +Второй, в виде функции, должен обеспечивать поиск минимального значения для списка. +Сложность такого алгоритма: O(n) - линейная. + +Не забудьте указать где какая сложность. + +Примечание: +Построить список можно через списковое включение. +Если у вас возникают сложности, постарайтесь подумать как можно решить задачу, +а не писать "мы это не проходили)". +Алгоритмизатор должен развивать мышление, а это прежде всего практика. +А без столкновения со сложностями его не развить. +""" + + +def min_n2(lst): # O(n^2) <= n * (n + c) + c + for i in lst: + for j in lst: + if i > j: + break + elif i < j and j == lst[-1]: + return i + + +def min_n(lst): # O(n) <= n + n * c + c + result = lst[0] + for i in lst: + if result > i: + result = i + return result + + +user_list = [2, 3, 4, 10, 1, 8] + +print(min_n2(user_list)) +print(min_n(user_list)) \ No newline at end of file diff --git a/task_3.py b/task_3.py new file mode 100644 index 0000000..e362ba3 --- /dev/null +++ b/task_3.py @@ -0,0 +1,71 @@ +""" +Задание 3. + +Для этой задачи: +1) придумайте 2-3 решения (не менее двух) +2) оцените сложность каждого решения в нотации О-большое +3) сделайте вывод, какое решение эффективнее и почему + +Примечание: +Без выполнения пунктов 2 и 3 задание считается нерешенным. Пункты 2 и 3 можно выполнить +через строки документации в самом коде. +Если у вас возникают сложности, постарайтесь подумать как можно решить задачу, +а не писать "мы это не проходили)". +Алгоритмизатор должен развивать мышление, а это прежде всего практика. +А без столкновения со сложностями его не развить. + +Сама задача: +Имеется хранилище с информацией о компаниях: название и годовая прибыль. +Для реализации хранилища можно применить любой подход, +который вы придумаете, например, реализовать словарь. +Реализуйте поиск трех компаний с наибольшей годовой прибылью. +Выведите результат. +""" + +# В задании не указано, что делать, если у двух компаний одинаковая годовая прибыль и это влияет на результат. +# Поэтому в этом случае в результат попадает случайная(ые) компания(ии) из подобных, если все попасть не могут. + +def max3_1(dct): # O(n log n) <= nlogn + 3 + return sorted(dct, key=dct.get)[-3:] + + +def max3_2(dct): # O(n log n) <= c + n + nlogn + 3 + lst = list(dct.items()) + lst.sort(key=lambda i: i[1]) + return lst[-3:] + + +def max3_3(dct): # O(n) - много кода, но только в одном месте линейная сложность, а в остальных константные + result = [] # O(1) + min_result = [] # O(1) + + def min_res_func(mr): + for i in result: # O(1) ибо длина result всегда 3 + if i[1] < mr[1]: # O(1) + mr = i # O(1) + return mr # O(1) + + for key, value in dct.items(): # O(n) + if len(result) < 3: # O(1) + result.append([key, value]) # O(1) + if len(result) == 3: # O(1) + min_result = result[0] # O(1) + min_result = min_res_func(min_result) # O(1) - ибо длина result всегда 3 + else: # O(1) + if value > min_result[1]: # O(1) + result.remove(min_result) # O(1) - ибо длина result всегда 3 + result.append([key, value]) # O(1) + min_result = min_res_func(result[0]) # O(1) - ибо длина result всегда 3 + return result # O(1) + + +''' +Вывод - третий вариант имеет наименьшую сложность, однако наибольший размер кода. +Так что я бы сказал, что первые два варианта эффективнее при небольшом количестве компаний, а третий - при большом. +''' + +companies = {'A': 12000, 'B': 1000, 'C': 2600, 'D': 15000, 'E': 10000} + +print(max3_1(companies)) +print(max3_2(companies)) +print(max3_3(companies)) \ No newline at end of file diff --git a/task_4.py b/task_4.py new file mode 100644 index 0000000..94e26f3 --- /dev/null +++ b/task_4.py @@ -0,0 +1,83 @@ +""" +Задание 4. + +Для этой задачи: +1) придумайте 2-3 решения (не менее двух) +2) оцените сложность каждого решения в нотации О-большое +3) сделайте вывод, какое решение эффективнее и почему + +Примечание: +Без выполнения пунктов 2 и 3 задание считается нерешенным. Пункты 2 и 3 можно выполнить +через строки документации в самом коде. +Если у вас возникают сложности, постарайтесь подумать как можно решить задачу, +а не писать "мы это не проходили)". +Алгоритмизатор должен развивать мышление, а это прежде всего практика. +А без столкновения со сложностями его не развить. + +Сама задача: +Пользователи веб-ресурса проходят аутентификацию. +В системе хранятся логин, пароль и отметка об активации учетной записи. + +Нужно реализовать проверку, может ли пользователь быть допущен к ресурсу. +При этом его учетка должна быть активирована. +А если нет, то польз-лю нужно предложить ее пройти. + +Приложение должно давать ответы на эти вопросы и быть реализовано в виде функции. +Для реализации хранилища можно применить любой подход, +который вы придумаете, например, реализовать словарь. +""" + + +def check_1(dct): # O(1) - всё постоянное + while True: + user = input('Введите логин: ') + try: + user = dct[user] + break + except KeyError: + pass + if user['activation']: + for _ in range(5): + password = input('Введите пароль: ') + if user['password'] == password: + print('Вы вошли') + break + else: + answer = input('Хотите активировать учётную запись?: ') + if answer.lower() == 'да': + user['activation'] = True + print('Ваша учётная запись активирована') + + +def check_2(dct): # O(n) - линейный только цикл по перебору ключей словаря, остальное всё постоянное + + def login_check(): + for _ in range(5): + user = input('Введите логин: ') + for key in dct: + if key == user: + return user + print("Превышено количество попыток") + + user = login_check() + if dct[user]['activation']: + for _ in range(5): + password = input('Введите пароль: ') + if dct[user]['password'] == password: + print('Вы вошли') + break + else: + answer = input('Хотите активировать учётную запись?: ') + if answer.lower() == 'да': + dct[user]['activation'] = True + print('Ваша учётная запись активирована') + + +# Задание сложнее предыдущего по вариативности на мой взгляд, поэтому варианты весьма похожи. +# Засчёт цикла while True первый вариант может выполняться бесконечно, поэтому второй вариант предпочтительней. +# Хотя по сути лучший решением была бы комбинация, где во втором варианте при вводе логина, используются не два цикла for, а цикл for и try/except + + +users = {'login1': {'password': 'pass1', 'activation': True}, 'login2': {'password': 'pass2', 'activation': False}} +check_1(users) +print(users) \ No newline at end of file diff --git a/task_5.py b/task_5.py new file mode 100644 index 0000000..d839cff --- /dev/null +++ b/task_5.py @@ -0,0 +1,94 @@ +""" +Задание 5. +Задание на закрепление навыков работы со стеком + +Примечание: в этом задании вспомните ваши знания по работе с ООП +и опирайтесь на пример урока + +Реализуйте структуру "стопка тарелок". + +Мы можем складывать тарелки в стопку и при превышении некоторого значения +нужно начать складывать тарелки в новую стопку. + +Структура должна предусматривать наличие нескольких стеков. +Создание нового стека происходит при достижении предыдущим стеком порогового значения. +Реализуйте по аналогии с примером, рассмотренным на уроке, необходимые методы, +для реализации это структуры, добавьте новые методы (не рассмотренные в примере с урока) +для реализации этой задачи. + +После реализации структуры, проверьте ее работу на различных сценариях + +Подсказка: +Отдельне стопки можно реализовать через: +# 1) созд-е экземпляров стека (если стопка - класс) +# 2) lst = [[], [], [], [],....] +""" + +# Реализована система стэков при которой после переполнения первого стэка создаётся новый. +# Каждый стэк кроме первого имеет информацию о своём предшественнике, +# и каждый стэк кроме крайнего имеет информацию о последователе. +# Таким образом если заканчиваются тарелки в крайнем стэке, они берутся из предшественника, +# И если в текущем стэке нет места, создаётся новый. +# Метод get_quantity возвращает количество тарелок во всех стэках цепи + + +class Plate: + + def __init__(self, color='white', shape='circle'): + self.color = color + self.shape = shape + + +class Stack: + + def __init__(self, size, previous=None): + self.size = size + self.previous = previous + self.next = None + self.plates = [] + + def push_in(self, plate): + if len(self.plates) < self.size: + self.plates.append(plate) + elif len(self.plates) >= self.size: + if self.next is None: + self.next = Stack(self.size, self) + self.next.push_in(plate) + + def pop_out(self): + if self.next is not None: + if not self.next.is_empty(): + self.next.pop_out() + return + if not self.is_empty(): + return self.plates.pop() + else: + if self.previous is not None: + self.previous.pop_out() + else: + print('Тарелки кончились') + + def is_empty(self): + return self.plates == [] + + def get_quantity_next(self, init_stack_quantity): + if self.next is not None: + return self.next.get_quantity_next(init_stack_quantity + len(self.next.plates)) + else: + return init_stack_quantity + + def get_quantity(self): + if self.previous is not None: + self.previous.get_quantity() + else: + return self.get_quantity_next(len(self.plates)) + + +stack = Stack(5) +for _ in range(6): + stack.push_in(Plate()) + print(stack.get_quantity()) +for _ in range(7): + stack.pop_out() + print(stack.get_quantity()) + diff --git a/task_6.py b/task_6.py new file mode 100644 index 0000000..e405192 --- /dev/null +++ b/task_6.py @@ -0,0 +1,87 @@ +""" +Задание 6. +Задание на закрепление навыков работы с очередью + +Примечание: в этом задании вспомните ваши знания по работе с ООП +и опирайтесь на пример урока + +Реализуйте структуру "доска задач". + +Структура должна предусматривать наличие несольких очередей задач, например +1) базовой, откуда задачи берутся, решаются и отправляются в список решенных +2) очередь на доработку, когда нерешенные задачи из первой очереди отправляются +на корректировку решения + +После реализации структуры, проверьте ее работу на различных сценариях +""" + +# Первая созданная для доски задач задача создаёт обе нужные очереди и список решённых задач. +# Удобнее было бы реализовать также интерфейс для работы с доской задач, но в момент когда я об этом подумал, +# это требовало бы переделать всю структуру классов, так что пришлось ограничиться ручной проверкой. + +class Queue: + + def __init__(self): + self.tasks = [] + + def to_queue(self, task): + self.tasks.insert(0, task) + + def from_queue(self): + if len(self.tasks) != 0: + return self.tasks.pop() + else: + print("Задач в очереди нет") + + def next_task_description(self): + print(self.tasks[-1].description) + + def get_quantity(self): + return len(self.tasks) + + def __str__(self): + return str(list(map(str, self.tasks))) + + +class Task: + + def __init__(self, description, to_do=None, to_rework=None, done=None): + if to_do is None: + to_do = Queue() + to_rework = Queue() + done = [] + self.to_do = to_do + self.to_rework = to_rework + self.done = done + self.to_do.to_queue(self) + self.description = description + + def add_to_rework(self): + self.to_rework.to_queue(self) + + def is_done(self): + self.done.append(self) + + def __str__(self): + return self.description + + +task = Task('задача 1') +to_do = task.to_do +to_rework = task.to_rework +done = task.done + +task2 = Task('задача 2', to_do, to_rework, done) +print(to_do) +print(to_rework) + +to_do.next_task_description() +to_do.from_queue().is_done() +to_do.from_queue().add_to_rework() +print(to_do) +print(to_rework) + +to_rework.from_queue().is_done() +print(to_do) +print(to_rework) + diff --git a/task_7.py b/task_7.py new file mode 100644 index 0000000..4be9e57 --- /dev/null +++ b/task_7.py @@ -0,0 +1,57 @@ +""" +Задание 7. +Задание на закрепление навыков работы с деком + +В рассмотренном на уроке листинге есть один недостаток +Приведенный код способен "обработать" только строку без пробелов, например, 'топот' + +Но могут быть и такие палиндромы, как 'молоко делили ледоколом' + +Вам нужно доработать программу так, чтобы она могла выполнить проверку на палиндром +и в таких строках (включающих пробелы) +""" + + +class DequeClass: + def __init__(self): + self.elems = [] + + def is_empty(self): + return self.elems == [] + + def add_to_front(self, elem): + self.elems.append(elem) + + def add_to_rear(self, elem): + self.elems.insert(0, elem) + + def remove_from_front(self): + return self.elems.pop() + + def remove_from_rear(self): + return self.elems.pop(0) + + def size(self): + return len(self.elems) + + +def pal_checker(string): + dc_obj = DequeClass() + + string = ''.join(string.split()) # добавленная строчка + + for el in string: + dc_obj.add_to_rear(el) + + still_equal = True + + while dc_obj.size() > 1 and still_equal: + first = dc_obj.remove_from_front() + last = dc_obj.remove_from_rear() + if first != last: + still_equal = False + + return still_equal + + +print(pal_checker("молоко делили ледоколом")) \ No newline at end of file