Подтвердить что ты не робот

Как получить ДЕЙСТВИТЕЛЬНО быстрый Python через простой цикл

Я работаю над проблемой SPOJ, INTEST. Цель состоит в том, чтобы указать количество тестовых случаев (n) и делителя (k), а затем подать ваши n номера программ. Программа будет принимать каждое число в новой строке stdin и после получения n-го числа сообщит вам, сколько из них было делимым на k.

Единственная проблема в этой проблеме - заставить ваш код быть FAST, потому что k может быть любым размером до 10 ^ 7 и n может достигать 10 ^ 9.

Я пытаюсь написать его на Python и не могу ускорить его. Любые идеи?


Отредактируйте 2: я, наконец, получил это, чтобы пройти через 10.54 секунды. Я использовал почти все ваши ответы, чтобы добраться туда, и поэтому было трудно выбрать один из них как "правильный", но я считаю, что тот, который я выбрал, суммирует его как можно лучше. Спасибо вам всем. Конечный код прохождения ниже.

Изменить: я включил некоторые предлагаемые обновления во включенном коде.


Расширения и сторонние модули запрещены. Код также управляется судовой машиной SPOJ, поэтому у меня нет возможности сменить интерпретаторы.

import sys
import psyco
psyco.full()

def main():
    from sys import stdin, stdout
    first_in = stdin.readline()
    thing = first_in.split()
    n = int(thing[0])
    k = int(thing[1])
    total = 0

    list = stdin.readlines()
    for item in list:
        if int(item) % k == 0:
            total += 1

    stdout.write(str(total) + "\n")

if __name__ == "__main__":
    main()
4b9b3361

Ответ 1

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

  • Psyco с Python 2.5.
  • простой цикл с переменной для учета в
  • мой код был в main() (кроме импорта psyco), который я вызывал.

Последнее, что изменило ситуацию. Я считаю, что это связано с переменной видимостью, но я не совсем уверен. Мое время было 10,81 секунды. Вы можете получить его быстрее со списком.

Edit:

Использование понимания списка привело мое время до 8,23 секунды. Приведение строки from sys import stdin, stdout внутри функции немного сбрито, чтобы сократить время до 8.12 секунд.

Ответ 2

[Отредактировано для отражения новых результатов и передачи кода на spoj]

Как правило, при использовании Python для spoj:

  • Не используйте "raw_input", используйте sys.stdin.readlines(). Это может повлиять на большой вход. Кроме того, если это возможно (и это для этой проблемы), прочитайте все сразу (sys.stdin. Readlines()) вместо чтения строки за строкой ( "для строки в sys.stdin..." ).
  • Аналогично, не используйте "print", используйте sys.stdout.write() - и не забывайте "\n". Конечно, это актуально только при печати несколько раз.
  • Как предложил С.Марк, используйте psyco. Он доступен как для python2.5, так и для python2.6, на spoj (протестировать его, там и легко заметить: решения, использующие psyco, обычно имеют смещение использования памяти 35 Мб). Это очень просто: просто добавьте после "import sys": import psyco; psyco.full()
  • Как предложил Джастин, добавьте свой код (кроме заклинания psyco) внутри функции и просто вызовите его в конце вашего кода.
  • Иногда создание списка и проверка его длины может быть быстрее, чем создание списка и добавление его компонентов.
  • Используйте списки списков (и, если возможно, выражения генератора) над "для" и "пока". Для некоторых конструкций map/reduce/filter также может ускорить ваш код.

Используя (некоторые) эти рекомендации, мне удалось передать INTEST. Тем не менее, альтернативы тестирования.

Ответ 3

Используйте psyco, это будет JIT ваш код, очень эффективный, когда есть большой цикл и вычисления.

Изменить. Похоже, что сторонние модули не разрешены,

Итак, вы можете попробовать преобразовать свой цикл в список понятий, он должен быть запущен на уровне C, поэтому он должен быть немного быстрее.

sum(1 if int(line) % k == 0 else 0 for line in sys.stdin)

Ответ 4

Совсем недавно Alex Martinelli сказал, что вызов кода внутри функции превосходит прогон кода в модуле (я не могу найти сообщение, хотя)

Итак, почему бы вам не попробовать:

import sys
import psyco

psyco.full1()

def main():

    first_in = raw_input()
    thing = first_in.split()
    n = int(thing[0])
    k = int(thing[1])
    total = 0
    i = 0

    total = sum(1 if int(line) % k == 0 else 0 for line in sys.stdin)

    print total
if __name__ == "__main__":
    main()

IIRC причина в том, что код внутри функции может быть оптимизирован.

Ответ 5

Использование списков с помощью psyco является результативным.

Этот код:

 count = 0
 for l in sys.stdin:
     count += not int(l)%k

выполняется в два раза быстрее, чем

count = sum(not int(l)%k for l in sys.stdin)

при использовании psyco.

Ответ 6

Для других читателей вот инструкция задачи INTEST. Он предназначен для проверки пропускной способности ввода-вывода.

В моей системе я смог сэкономить 15% от времени выполнения, заменив цикл следующим:

print sum(1 for line in sys.stdin if int(line) % k == 0)