Оптимизация кода Python быстрее, чем за 4 секунды

Я написал код для решения онлайн-проблемы, Вот.

mustConstraint = set()
notConstraint = set()
violated = 0
satisfied = 0 

for i in range(0, int(input(''))):
    constraint = input('')
    mustConstraint.add(frozenset(constraint.split()))

for i in range(0, int(input(''))):
    constraint = input('')
    notConstraint.add(frozenset(constraint.split()))

for i in range(0, int(input(''))):
    group = input('')
    group = set(group.split())

    for x in mustConstraint:
        if x & group == x:
            satisfied +=1
        
    for y in notConstraint:
        if y & group == y:
            violated += 1

violated += len(mustConstraint) - satisfied

print(violated)

Подводя итог проблемы, первая строка входных данных содержит положительное целое число X с X => 0. Следующие X строк входных данных будут содержать два слова, разделенных пробелами. Эти два слова должны быть в одной группе. следующая строка ввода будет содержать еще одно положительное целое число Y, где Y => 0. Следующие строки ввода Y будут содержать два слова, разделенные пробелом. эти два слова не должны быть в одной группе. следующая строка входных данных будет содержать целое положительное число G с G >= 1. Каждая следующая строка входных данных G будет состоять из трех разных слов, разделенных одинарными пробелами. Эти три слова были помещены в одну группу.

Выведите целое число от 0 до X+Y — количество нарушенных ограничений.

Я настоятельно рекомендую вам посетить проблемный сайт здесь, так как проблему гораздо легче понять с помощью предоставленных примеров случаев и их пояснений.

К сожалению, поскольку последняя партия содержит около 300 000 входных данных, мои вложенные циклы for работают слишком медленно и не укладываются в 4-секундный лимит. Может ли кто-нибудь помочь мне оптимизировать мой код?

Большая часть задержки происходит из-за этого блока:

for i in range(0, int(input(''))):
    group = input('')
    group = set(group.split())

    for x in mustConstraint:
        if x & group == x:
            satisfied +=1
        
    for y in notConstraint:
        if y & group == y:
            violated += 1

вложенные циклы for выполняют 100 000 ^ 2 итерации каждый, что в общей сложности составляет 20 миллиардов итераций из этого блока кода (2 * 100 000 ^ 2)

если бы кто-то мог найти способ сократить количество итераций, это имело бы существенное значение.

Пожалуйста, опишите здесь, что делает код, а не просто ссылку на внешний сайт. И результаты должны быть опубликованы в виде текста, а не скриншотов.

Barmar 14.07.2024 00:27

Я не понимаю, что делают все int(input('')) — вы используете их как заполнитель для чего-то другого? пожалуйста, объясните полностью.

Vin 14.07.2024 00:28

@Vin Первая строка ввода — это количество строк имен. Итак, for i in range(0, int(input(''))): читает количество строк, затем читает это количество строк.

Barmar 14.07.2024 00:30

Я не занимаюсь соревновательным программированием, но я бы сказал, что решение для многих входных данных связано с разработкой алгоритма, а не с его реализацией. Вы могли бы написать свой код на ASM, мне кажется, ваше решение слишком наивно; это источник проблемы с производительностью.

MufasaChan 14.07.2024 00:31

Самая очевидная оптимизация — заменить x & group == x на x.issubset(y). issubset()можно использовать короткое замыкание, чтобы большие наборы не были такими медленными.

Barmar 14.07.2024 00:32

Я вижу, что вы приняли ответы здесь и в своем предыдущем вопросе. Пожалуйста, не забудьте исправить оба вопроса, как указано в их комментариях (в данном случае первый комментарий @Barmar). Помните, что вопросы и ответы здесь должны быть полезны всем, включая будущих посетителей с такими же/похожими проблемами. (На самом деле мне не следовало отвечать здесь до того, как вы это исправили, я просто слишком устал, чтобы заметить это сам, и прочитал комментарии только потом.)

no comment 14.07.2024 03:07

@nocomment Исправлено, спасибо за отзыв!

F-22 Destroyer 14.07.2024 03:45

Спасибо. Хотя, как вы сами сказали: «проблему гораздо легче понять с помощью приведенных примеров случаев и их пояснений». Поэтому лучше приведите пример случая + объяснение. Я бы даже придумал свой, так как сайт мне не нравится. Например, поместить Бэтмена и Робина в список «обязательных», а Бэтмена и Джокера — в список «нельзя». Гораздо лучше, чем бессмысленные названия сайта.

no comment 14.07.2024 03:52
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
8
107
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете использовать операции над множествами более эффективно:

Для повышения эффективности читайте все входные данные одновременно.

Используйте словари для хранения ограничений и наборов для представления групп.

Эффективно проверяйте ограничения, перебирая каждую группу и обновляя счетчик нарушений.

Так:

import sys

input = sys.stdin.read
data = input().splitlines()

index = 0

# Read must constraints
must_constraint_count = int(data[index])
index += 1
must_constraints = []
for _ in range(must_constraint_count):
    must_constraints.append(set(data[index].split()))
    index += 1

# Read not constraints
not_constraint_count = int(data[index])
index += 1
not_constraints = []
for _ in range(not_constraint_count):
    not_constraints.append(set(data[index].split()))
    index += 1

# Read groups
group_count = int(data[index])
index += 1
groups = []
for _ in range(group_count):
    groups.append(set(data[index].split()))
    index += 1

# Check constraints
satisfied = 0
violated = 0

# Check must constraints
for must in must_constraints:
    in_same_group = False
    for group in groups:
        if must.issubset(group):
            satisfied += 1
            in_same_group = True
            break
    if not in_same_group:
        violated += 1

# Check not constraints
for not_c in not_constraints:
    for group in groups:
        if not_c.issubset(group):
            violated += 1
            break

print(violated)

Обработка ввода: для повышения эффективности весь ввод считывается одновременно с использованием sys.stdin.read.

Хранение ограничений. Ограничения хранятся в списках наборов для удобства проверки.

Группы обработки: группы хранятся в виде наборов, что позволяет использовать быструю проверку подмножества.

Проверка ограничений:

Для каждого обязательного ограничения проверьте, не является ли набор ограничений подмножеством какой-либо группы. Если да, то он удовлетворен. Если нет, то оно нарушено.

Для каждого не-ограничения проверьте, является ли набор ограничений подмножеством какой-либо группы. Если да, то оно нарушено.

Производительность:

Использование множеств и метода issubset() делает проверку ограничений эффективной.

Чтение всех входных данных одновременно и их обработка в памяти позволяет избежать множественных операций ввода-вывода, что ускоряет выполнение.

Дополнительную помощь по сложным общим операциям можно найти в Шпаргалке Big-O.

Кроме того, Временная сложность Python очень хорошо объясняет характеристики производительности встроенных типов данных Python.

«Это уменьшает количество итераций» — Так ли это? Как же так? - "и значительно улучшает производительность" - Так ли это? Сколько?

no comment 14.07.2024 01:57

Насколько я могу судить, ответьте на оба моих вопроса: Нет, это не так. Представленный на сайте, он терпит неудачу при первом большом тестовом примере, как и код ОП. Как и ожидалось.

no comment 14.07.2024 03:17

Ответ отличный, и это явные улучшения, но он все еще не соответствует временному ограничению в 4 секунды. Спасибо за ваш отзыв!

F-22 Destroyer 14.07.2024 03:19

Спасибо за ответ! Правки помогли разобраться, спасибо за вашу помощь; не было кнопки слияния, которую можно было бы нажать, я новичок в этом пользовательском интерфейсе, я отредактировал оригинал.

Stina Andersson 14.07.2024 19:26

Все еще примерно так же неэффективен, как и раньше, и по-прежнему не проходит первый большой тестовый пример.

no comment 14.07.2024 20:06
Ответ принят как подходящий

Два решения, оба легко проходят все тесты.

Решение 1. Минимальные изменения

Замените большие внутренние петли крошечными петлями над тремя парами группы, т. е. измените

    for x in mustConstraint:
        if x & group == x:
            satisfied +=1
        
    for y in notConstraint:
        if y & group == y:
            violated += 1

к этому:

    a, b, c = group
    for pair in {a, b}, {a, c}, {b, c}:
        if pair in mustConstraint:
            satisfied += 1
        if pair in notConstraint:
            violated += 1

Решение 2. Всего две операции над набором

Все три раздела определяют набор пар. Помогает поместить это в функцию. Затем найдите/подсчитайте нарушения:

  • Пары, которые должны быть, но не являются.
  • Пары, которых не должно быть, но которые есть.
from itertools import combinations

def pairs():
    return {
        frozenset(pair)
        for _ in range(int(input()))
        for pair in combinations(input().split(), 2)
    }

must = pairs()
must_not = pairs()
are = pairs()

print(len(must - are) + len(must_not & are))

Другие вопросы по теме