[英]How can I improve the runtime of Python implementation of cycle detection in Course Schedule problem?
My aim is to improve the speed of my Python code that has been successfully accepted in a leetcode problem, Course Schedule .我的目标是提高我的 Python 代码的速度,该代码已在leetcode 问题 Course Schedule中成功接受。
I am aware of the algorithm but even though I am using O(1) data-structures, my runtime is still poor: around 200ms.我知道该算法,但即使我使用 O(1) 数据结构,我的运行时间仍然很差:大约 200 毫秒。
My code uses dictionaries and sets:我的代码使用字典和集合:
from collections import defaultdict
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
course_list = []
pre_req_mapping = defaultdict(list)
visited = set()
stack = set()
def dfs(course):
if course in stack:
return False
stack.add(course)
visited.add(course)
for neighbor in pre_req_mapping.get(course, []):
if neighbor in visited:
no_cycle = dfs(neighbor)
if not no_cycle:
return False
stack.remove(course)
return True
# for course in range(numCourses):
# course_list.append(course)
for pair in prerequisites:
pre_req_mapping[pair[1]].append(pair[0])
for course in range(numCourses):
if course in visited:
continue
no_cycle = dfs(course)
if not no_cycle:
return False
return True
What else can I do to improve the speed?我还能做些什么来提高速度?
You are calling dfs()
for a given course
multiple times.您多次为给定
course
调用dfs()
。 But its return value won't change.但它的返回值不会改变。 So we have an opportunity to memoize it.
所以我们有机会记住它。 Change your algorithmic approach (here, to dynamic programming) for the big win.
改变你的算法方法(这里是动态编程)以获得巨大的胜利。 It's a space vs time tradeoff.
这是空间与时间的权衡。 EDIT: Hmmm, you are already memoizing most of the computation with
visited
, so lru_cache
would mostly improve clarity rather than runtime.编辑:嗯,你已经用
visited
记住了大部分计算,所以lru_cache
主要会提高清晰度而不是运行时间。 It's just a familiar idiom for caching a result.这只是缓存结果的一种熟悉的习惯用法。
It would be helpful to add a #
comment citing a reference for the algorithm you implemented.添加
#
注释引用您实现的算法的参考会很有帮助。
This is a very nice expression, with defaulting: pre_req_mapping.get(course, [])
If you use timeit you may find that the generated bytecode for an empty tuple ()
is a tiny bit more efficient than that for an empty list []
, as it involves fewer allocations.这是一个非常好的表达式,默认为:
pre_req_mapping.get(course, [])
如果你使用timeit ,你可能会发现为空元组()
生成的字节码比为空列表[]
,因为它涉及较少的分配。 Ok, some style nits follow, unrelated to runtime.好的,一些风格尼特遵循,与运行时无关。
As an aside, youAreMixingCamelCase and_snake_case.顺便说一句,youAreMixing CamelCase 和_snake_case。 PEP-8 asks you to please stick with just snake_case.
PEP-8 要求你坚持使用 snake_case。
This is a fine choice of identifier name:这是标识符名称的一个很好的选择:
for pair in prerequisites:
But instead of the cryptic [0]
, [1]
dereferences, it would be easier to read a tuple unpack:但不是神秘的
[0]
, [1]
解引用,而是更容易阅读元组解包:
for course, prereq in prerequisites:
if not no_cycle:
is clumsy. if not no_cycle:
是笨拙的。 Consider inverting the meaning of dfs' return value, or rephrasing the assignment as:考虑反转 dfs 的返回值的含义,或将赋值改写为:
cycle = not dfs(course)
I think that you are doing it in good way, but since Python is an interpreted language, it's normal to have slow runtime compared with compiled languages like C/C++ and Java, especially for large inputs.我认为您做得很好,但是由于 Python 是一种解释性语言,与 C/C++ 和 Java 等编译语言相比,运行时间很慢是正常的,尤其是对于大输入。
Try to write the same code in C/C++ for example and compare the speed between them.例如,尝试用 C/C++ 编写相同的代码并比较它们之间的速度。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.