-
Notifications
You must be signed in to change notification settings - Fork 0
first commit #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
first commit #4
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| """ | ||
| Задание 1. | ||
| Приведен код, который позволяет сохранить в | ||
| массиве индексы четных элементов другого массива | ||
| Сделайте замеры времени выполнения кода с помощью модуля timeit | ||
| Оптимизируйте, чтобы снизить время выполнения | ||
| Проведите повторные замеры. | ||
| Добавьте аналитику: что вы сделали и почему!!! | ||
| Без аналитики задание не принимается | ||
| """ | ||
|
|
||
| # Оказывается list comprehension работает медленнее обычного цикла, интересно. | ||
| # Оптимизированный вариант - func_4. По сути я просто совместил индексы и элементы от индексов в enumerate объекте, | ||
| # что видимо ускорило работу, потому что каждый раз находить элемент по индексу дольше, чем один раз использовать | ||
| # enumerate(). | ||
|
|
||
| from timeit import timeit | ||
|
|
||
|
|
||
| def func_1(nums): | ||
| new_arr = [] | ||
| for i in range(len(nums)): | ||
| if nums[i] % 2 == 0: | ||
| new_arr.append(i) | ||
| return new_arr | ||
|
|
||
|
|
||
| def func_2(nums): | ||
| return [i for i in range(len(nums)) if nums[i] % 2 == 0] | ||
|
|
||
|
|
||
| def func_3(nums): | ||
| return [i for i, j in enumerate(nums) if j % 2 == 0] | ||
|
|
||
|
|
||
| def func_4(nums): | ||
| new_arr = [] | ||
| for i, j in enumerate(nums): | ||
| if j % 2 == 0: | ||
| new_arr.append(i) | ||
| return new_arr | ||
|
|
||
|
|
||
| print(timeit("func_1([1, 3, 1, 3, 4, 5, 1])", globals=globals())) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [1, 3, 1, 3, 4, 5, 1] - на таких массивах вы не получите объективные цифры
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Хорошо, что на уроке об этом говорилось. Ах да, не говорилось. Я пробовал на массиве побольше, но не настолько |
||
| print(timeit("func_2([1, 3, 1, 3, 4, 5, 1])", globals=globals())) | ||
| print(timeit("func_3([1, 3, 1, 3, 4, 5, 1])", globals=globals())) | ||
| print(timeit("func_4([1, 3, 1, 3, 4, 5, 1])", globals=globals())) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| """ | ||
| Задание 2. | ||
| Приведен код, который формирует из введенного числа | ||
| обратное по порядку входящих в него цифр. | ||
| Задача решена через рекурсию | ||
| Выполнена попытка оптимизировать решение через мемоизацию. | ||
| Сделаны замеры обеих реализаций. | ||
| Сделайте аналитику, нужна ли здесь мемоизация или нет и почему?!!! | ||
| Будьте внимательны, задание хитрое. Не все так просто, как кажется. | ||
| """ | ||
|
|
||
| # Мемоизация не нужна в данном случае, потому что данные, возвращаемые каждой новой вызываемой рекурсией - разные. | ||
| # Но в контексте 10000 повторений одной и той же рекурсии с одним и тем же входным числом (!!!), | ||
| # мемоизация становится незаменима, потому что по сути рекурсия работает 1 раз, а потом все данные берутся из кэша. | ||
| # Отсюда при замерах и создаётся ощущение, что мемоизация помогает. На самом деле это обманка. | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. выполнено |
||
|
|
||
| from timeit import timeit | ||
| from random import randint | ||
|
|
||
|
|
||
| def recursive_reverse(number): | ||
| if number == 0: | ||
| return '' | ||
| return f'{str(number % 10)}{recursive_reverse(number // 10)}' | ||
|
|
||
|
|
||
| num_100 = randint(10000, 1000000) | ||
| num_1000 = randint(1000000, 10000000) | ||
| num_10000 = randint(100000000, 10000000000000) | ||
|
|
||
| print('Не оптимизированная функция recursive_reverse') | ||
| print( | ||
| timeit( | ||
| "recursive_reverse(num_100)", | ||
| setup='from __main__ import recursive_reverse, num_100', | ||
| number=10000)) | ||
| print( | ||
| timeit( | ||
| "recursive_reverse(num_1000)", | ||
| setup='from __main__ import recursive_reverse, num_1000', | ||
| number=10000)) | ||
| print( | ||
| timeit( | ||
| "recursive_reverse(num_10000)", | ||
| setup='from __main__ import recursive_reverse, num_10000', | ||
| number=10000)) | ||
|
|
||
|
|
||
| def memoize(f): | ||
| cache = {} | ||
|
|
||
| def decorate(*args): | ||
|
|
||
| if args in cache: | ||
| return cache[args] | ||
| else: | ||
| cache[args] = f(*args) | ||
| return cache[args] | ||
| return decorate | ||
|
|
||
|
|
||
| @memoize | ||
| def recursive_reverse_mem(number): | ||
| if number == 0: | ||
| return '' | ||
| return f'{str(number % 10)}{recursive_reverse_mem(number // 10)}' | ||
|
|
||
|
|
||
| print('Оптимизированная функция recursive_reverse_mem') | ||
| print( | ||
| timeit( | ||
| 'recursive_reverse_mem(num_100)', | ||
| setup='from __main__ import recursive_reverse_mem, num_100', | ||
| number=10000)) | ||
| print( | ||
| timeit( | ||
| 'recursive_reverse_mem(num_1000)', | ||
| setup='from __main__ import recursive_reverse_mem, num_1000', | ||
| number=10000)) | ||
| print( | ||
| timeit( | ||
| 'recursive_reverse_mem(num_10000)', | ||
| setup='from __main__ import recursive_reverse_mem, num_10000', | ||
| number=10000)) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| """ | ||
| Задание 3. | ||
| Приведен код, формирующий из введенного числа | ||
| обратное по порядку входящих в него | ||
| цифр и вывести на экран. | ||
| Сделайте профилировку каждого алгоритма через cProfile и через timeit | ||
| Обязательно предложите еще свой вариант решения и также запрофилируйте! | ||
| Сделайте вывод, какая из четырех реализаций эффективнее и почему!!! | ||
| Без аналитики задание считается не принятым | ||
| """ | ||
|
|
||
| # Я не нашёл информации о том какой сложности является функция str(), но логически это либо линейная, либо константная. | ||
| # Этого хватит для аналитики этого задания, хотя хотелось бы узнать, какая всё-таки у неё сложность, пожалуйста с: | ||
| # Для простоты, в этом задании говорю об str() как о линейной, потому что во-первых я всё же склоняюсь к этому варианту, | ||
| # А во вторых это бОльшая из двух. | ||
|
|
||
| # Самый эффективный вариант - через срез (3), что вполне логично, | ||
| # потому что в данной функции всего две операции, обе линейные и простые. | ||
| # Вариант через reverse() (5) на втором месте по скорости. Тут уже 4 линейные операции, но всё ещё простые. | ||
| # На третьем - вариант через цикл (2). Цикл ещё и с набором математических операций, | ||
| # поэтому медленнее простых вариантов выше, но быстрее рекурсий ниже | ||
| # Рекурсия данная в задании (1) выполняется немного быстрее, чем моя рекурсия (4), потому что в ней нет | ||
| # постоянных конвертаций чисел в строку и наоборот, а всегда происходит работа только с числами. | ||
|
|
||
| from timeit import timeit | ||
| from cProfile import run | ||
|
|
||
|
|
||
| def revers_1(enter_num, revers_num=0): | ||
| if enter_num == 0: | ||
| return revers_num | ||
| else: | ||
| num = enter_num % 10 | ||
| revers_num = (revers_num + num / 10) * 10 | ||
| enter_num //= 10 | ||
| return revers_1(enter_num, revers_num) | ||
|
|
||
|
|
||
| def revers_2(enter_num, revers_num=0): | ||
| while enter_num != 0: | ||
| num = enter_num % 10 | ||
| revers_num = (revers_num + num / 10) * 10 | ||
| enter_num //= 10 | ||
| return revers_num | ||
|
|
||
|
|
||
| def revers_3(enter_num): | ||
| enter_num = str(enter_num) | ||
| revers_num = enter_num[::-1] | ||
| return revers_num | ||
|
|
||
|
|
||
| def reverse_4(num): | ||
| if num // 10 == 0: | ||
| return num % 10 | ||
| else: | ||
| return f'{num % 10}{reverse_4(num // 10)}' | ||
|
|
||
|
|
||
| def reverse_5(num): | ||
| num = list(str(num)) | ||
| num.reverse() | ||
| return ''.join(num) | ||
|
|
||
|
|
||
| print(timeit('revers_1(1234567890)', globals=globals())) | ||
| print(timeit('revers_2(1234567890)', globals=globals())) | ||
| print(timeit('revers_3(1234567890)', globals=globals())) | ||
| print(timeit('reverse_4(1234567890)', globals=globals())) | ||
| print(timeit('reverse_5(1234567890)', globals=globals())) | ||
| run('revers_1(1234567890)') | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. выполнено |
||
| run('revers_2(1234567890)') | ||
| run('revers_3(1234567890)') | ||
| run('reverse_4(1234567890)') | ||
| run('reverse_5(1234567890)') | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| """ | ||
| Задание 4. | ||
| Приведены два алгоритма. В них определяется число, | ||
| которое встречается в массиве чаще всего. | ||
| Сделайте профилировку каждого алгоритма через timeit | ||
| Попытайтесь написать третью версию, которая будет самой быстрой. | ||
| Сделайте замеры и опишите, получилось ли у вас ускорить задачу. | ||
| Без аналитики задание считается не принятым! | ||
| """ | ||
|
|
||
| # func_2 = n * (n + 1) + n + n | ||
| # func_1 = n * (n + 1) | ||
| # func_3 = n * (n) + n | ||
|
|
||
| # Вторая функция самая долгая, потому что помимо квадратичной сложности полученной при взаимодействии цикла и | ||
| # функции count() в ней также метод append() повторяется n раз, а также в конце функции выполняются две операции | ||
| # с линейной сложностью. | ||
| # Первая функция работает значительно быстрее второй, потому что при всё той же квадратичной сложности, | ||
| # в ней уже n раз выполняется не append(), а простые операции сравнения. | ||
| # К тому же в первой функции нет конечных операций с линейной сложностью. | ||
| # Моя функция (третья) выполняется чуть медленнее первой при небольшом размере списка, но быстрее уже при длине | ||
| # списка в 2 раза бОльшей, чем у списка представленного в задании. Связанно это с тем, что при бОльшей длине | ||
| # время на операцию с линейной сложностью в конце функции невелируется более быстро работающей составляющей с | ||
| # квадратичной сложностью (max и count), чем составляющая с этой же сложностью в первой функции. | ||
|
|
||
|
|
||
| from timeit import timeit | ||
|
|
||
| array = [1, 3, 1, 3, 4, 5, 1] | ||
| # array = [1, 3, 1, 3, 4, 5, 1, 6, 7, 6, 8, 9, 7, 10] | ||
|
|
||
|
|
||
| def func_1(): | ||
| m = 0 | ||
| num = 0 | ||
| for i in array: | ||
| count = array.count(i) | ||
| if count > m: | ||
| m = count | ||
| num = i | ||
| return f'Чаще всего встречается число {num}, ' \ | ||
| f'оно появилось в массиве {m} раз(а)' | ||
|
|
||
|
|
||
| def func_2(): | ||
| new_array = [] | ||
| for el in array: | ||
| count2 = array.count(el) | ||
| new_array.append(count2) | ||
|
|
||
| max_2 = max(new_array) | ||
| elem = array[new_array.index(max_2)] | ||
| return f'Чаще всего встречается число {elem}, ' \ | ||
| f'оно появилось в массиве {max_2} раз(а)' | ||
|
|
||
|
|
||
| def func_3(): | ||
| num = max(array, key=array.count) | ||
| return f'Чаще всего встречается число {num}, ' \ | ||
| f'оно появилось в массиве {array.count(num)} раз(а)' | ||
|
|
||
|
|
||
| print(timeit('func_1()', globals=globals())) | ||
| print(timeit('func_2()', globals=globals())) | ||
| print(timeit('func_3()', globals=globals())) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. выполнено |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| """ | ||
| Задание 5.** | ||
| Приведен наивный алгоритм нахождения i-го по счёту | ||
| простого числа (через перебор делителей). | ||
| Попробуйте решить эту же задачу, | ||
| применив алгоритм "Решето Эратосфена" (https://younglinux.info/algorithm/sieve) | ||
| Подсказка: | ||
| Сравните алгоритмы по времени на разных порядковых номерах чисел: | ||
| 10, 100, 1000 | ||
| Опишите результаты, сделайте выводы, где и какой алгоритм эффективнее | ||
| Подумайте и по возможности определите сложность каждого алгоритма. | ||
| Укажите формулу сложности О-нотация каждого алгоритма | ||
| и сделайте обоснование результатам. | ||
| """ | ||
|
|
||
| # Сложность обоих алгоритмов - O(n^2) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. у Решета другая сложность
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Какая же там тогда сложность? Как бы, у simple тоже сложность по факту не n^2, но найти в интернете я ничего на эту тему не смог, а на занятии об этом не говорилось. |
||
| # Но суть в том, что при одинаковом первом линейном множителе (n - количество чисел с 2 до искомого простого числа), | ||
| # второй линейный множитель абсолютно разный. В первом варианте это количество всех чисел до числа, | ||
| # перебираемого в данный момент, а во втором это количество простых чисел до этого числа, что в разы меньше. | ||
| # Именно поэтому новый алгоритм выполняется в разы быстрее старого. | ||
|
|
||
|
|
||
| from timeit import timeit | ||
|
|
||
|
|
||
| def simple(i): # n * (const * n + const) => O(n^2) | ||
| """Без использования «Решета Эратосфена»""" | ||
| count = 1 | ||
| n = 2 | ||
| while count <= i: | ||
| t = 1 | ||
| is_simple = True | ||
| while t <= n: | ||
| if n % t == 0 and t != 1 and t != n: | ||
| is_simple = False | ||
| break | ||
| t += 1 | ||
| if is_simple: | ||
| if count == i: | ||
| break | ||
| count += 1 | ||
| n += 1 | ||
| return n | ||
|
|
||
|
|
||
| def eratosfen(i): # n * (const * n + const) => O(n^2) | ||
| simples = [] | ||
| n = 2 | ||
| while len(simples) < i: | ||
| is_simple = True | ||
| for j in simples: | ||
| if n % j == 0: | ||
| is_simple = False | ||
| break | ||
| if is_simple: | ||
| simples.append(n) | ||
| n += 1 | ||
| return simples[-1] | ||
|
|
||
|
|
||
| i = int(input('Введите порядковый номер искомого простого числа: ')) | ||
| print(simple(i)) | ||
| print(eratosfen(i)) | ||
| print(timeit(f'simple({i})', globals=globals())) | ||
| print(timeit(f'eratosfen({i})', globals=globals())) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Даниил. "Оказывается list comprehension работает медленнее обычного цикла, интересно."
они быстрее
вы неверно сделали замеры