在此问题中,我怎样才能减少代码的运行时间

How can i reduce the runtime of my code in this question

提问人:MrTraitor 提问时间:10/29/2023 更新时间:10/31/2023 访问量:135

问:

问题 - 给定两个字符串 和 ,返回 中第一次出现的索引,或者如果不是 的一部分。(问题来自Leetcode) 示例 - 输入:输出:和 输入: 输出:needlehaystackneedlehaystack-1needlehaystackhaystack = "sadbutsad", needle = "sad"0haystack = "leetcode", needle = "leeto"-1

我的代码

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        if needle not in haystack:
            return -1 
        else:
            for i in range (0, (len(haystack)-len(needle))+1):
                if haystack[i:i+len(needle)] == needle:
                    return i
                    break

enter image description here

Python 性能 big-o

评论

0赞 Charles Duffy 10/29/2023
如果练习是自己做而不是使用库调用,那么真正高性能的子字符串搜索方法涉及矢量化之类的事情,你不能直接在 Python 中做,但需要调用 C 或汇编。
0赞 Jérôme Richard 10/29/2023
@CharlesDuffy 请注意,“矢量化”有两个含义。在 Python 中,尤其是与 Numpy 相关的库中,矢量化意味着使用本机函数来加快计算速度。在母语中,这意味着使用 SIMD 指令(显式或非显式)。前者可能会也可能不会使用 SIMD 指令。
0赞 MrTraitor 10/29/2023
@StevenRumbalski谢谢你,我不知道这一点,但我解决这个问题的目标是了解它是如何工作的,而不是使用现有的函数。
0赞 Charles Duffy 10/29/2023
为什么numpy会给一个完全好的预先存在的术语附加一个新的和不同的含义?
1赞 Charles Duffy 10/29/2023
@MrTraitor,如果您的目标是了解它是如何工作的,请阅读源代码。该源代码不是用 Python 编写的。

答:

1赞 Kelly Bundy 10/29/2023 #1
class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        return haystack.find(needle)

证明它更快:LeetCode 的测试很小,所以我为每个输入运行了 100000 次解决方案:

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        for _ in range(100000):
            result = self.real_strStr(haystack, needle)
        return result
    def real_strStr(self, haystack: str, needle: str) -> int:
        return haystack.find(needle)

这在大约 1300 毫秒内被接受。有了你的,它会在大约 5400 毫秒内被接受。

请注意,如果没有重复,这大约是 0.013 毫秒和 0.054 毫秒。因此,通常情况下,LeetCode 向您展示的 40 毫秒的时间几乎完全由法官花费,在本案中约为 99.9%。只有大约 0.1% 的时间来自实际的解决方案代码。你得到的时间几乎完全取决于运气,你的解决方案的速度并不重要。

评论

1赞 Bill 10/29/2023
这个答案已经在 @Steven Rumbalski 的评论中提出。随后的评论表明他们想在不使用此内置函数的情况下解决问题。
1赞 Kelly Bundy 10/29/2023
@Bill没关系。评论不是用来回答的,评论也不是问题。
0赞 Bill 10/29/2023
评论是为了澄清问题。但是,好吧,我们会让 OP 决定您的答案是否正确。那不是我说的。
2赞 Kelly Bundy 10/29/2023
@Bill 评论也不是为了澄清问题。作者以外的用户可以在那里要求澄清,但作者应该在问题中添加信息,而不是在评论中。
0赞 Kelly Bundy 10/29/2023
@Bill 无论如何,是的,当然这个解决方案是微不足道的。答案的价值主要在于演示/解释 LeetCode 糟糕的测量及其常规结果的完全无意义。
2赞 Jab 10/29/2023 #2

专注于纯 python 解决方案,而不是使用任何内置函数来为您执行此操作。我可以为您的代码提供一些改进。

您可以记住针的长度,因此您不必经常调用长度。此外,您返回后不需要休息。它只是回来了。

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        if needle not in haystack:
            return -1 
        else:
            needle_length = len(needle)
            for i in range(len(haystack) - needle_length + 1):
                if haystack[i: i+needle_length] == needle:
                    return i

注意:由于将长度存储为变量,此解决方案将使用稍多的内存,但根据循环次数,将花费更少的时间

评论

0赞 Kelly Bundy 10/29/2023
我也用这个做了测试,它确实比他们的快,但只是稍微快一点:~4800 毫秒。
0赞 Jab 10/29/2023
@KellyBundy 什么稍微快一点?您的解决方案显然是最佳解决方案,但使用纯 python 并专注于改进 OP 的代码是我的目标。
1赞 Mark 10/29/2023
如果目标是避免使用内置功能,例如为什么要使用内置的?一旦你循环了一遍,没有找到这个词,你甚至需要它吗?find()in
0赞 Jab 10/29/2023
完全有道理,但 OP 要求改进他们的代码
0赞 MrTraitor 10/29/2023
@Jab是的,这确实减少了运行时间,令人惊讶的是,它还使用了更少的内存,您编辑的代码运行时间 = 37 毫秒,使用的内存 = 16MB(在 LeetCode 上),而我的原始代码运行时间 = 40 毫秒,使用的内存 = 16.2MB。更令人惊讶的是,您编辑的代码比使用现有函数的@KellyBundy代码使用的内存更少haystack.find(needle)
-2赞 Bill 10/29/2023 #3

在你的代码中,有一件事有点低效,那就是你首先搜索整个字符串,看看其中是否存在。如果 Leetcode 测试数据中只有很少的示例不包含字符串,那么您的代码将比其他代码做得更差。needle

这更快吗?

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        i_start = 0
        n = len(needle)
        while True:
            try:
                i = haystack.index(needle[0], i_start)
            except ValueError:
                return -1
            if haystack[i:i+n] == needle:
                return i
            i_start = i + 1
        return -1

评论

0赞 Bill 10/29/2023
哦,好吧。你知道为什么吗?
0赞 Bill 10/29/2023
啊,是的,好点子!我更新了代码来解决这个问题。
0赞 Bill 10/29/2023
再次更新了它。您现在还能看到其他问题吗?
0赞 Kelly Bundy 10/29/2023
现在它被接受了,但比他们的了大约 17 倍。(我不得不将重复次数减少到 10000 次,但仍然需要 ~9400 毫秒。
1赞 Kelly Bundy 10/29/2023
您的最新编辑将其降低到比他们慢 ~9.3 倍。随着(并适应这一点)它会下降到比他们慢 ~6.7 倍。haystack.index(needle[0], i_start)