25.11.24刷题日记——python内置默认大整数运算的用时开销陷阱

25.11.24刷题日记——python内置默认大整数运算的用时开销陷阱

养眼一下)

美图

在正式介绍之前,我们先看两端相同功能的代码:

代码1:

class Solution:
    def prefixesDivBy5(self, nums: List[int]) -> List[bool]:
        ans = []
        temp = 0 
        for num in nums:
            temp = temp * 2 + num
            if temp % 5 == 0:
                ans.append(True)
            else:
                ans.append(False)
        return ans

代码2:

class Solution:
    def prefixesDivBy5(self, nums: List[int]) -> List[bool]:
        ans = [False] * len(nums)
        x = 0
        for i, bit in enumerate(nums):
            x = (x << 1 | bit) % 5
            ans[i] = x == 0
        return ans

上面两个程序其实都是leetcode的题目1018. 可被 5 整除的二进制前缀的正确解法,但是在测试集上的耗时却天差地别,代码1耗时138ms,代码2耗时3ms,那么是为什么呢?

结论:因为第一段代码中的 temp 不断变大,导致 Python 的大整数运算成本急剧上升;第二段代码始终保持 x < 5,计算量恒定,因此快 100 倍以上。


深度解析

第一段代码的性能问题:temp = temp \* 2 + num

随着读取更多 bit,temp 会越来越大,例如:

nums = [1,0,1,1,0,1,1,1,0,1,...](长度1e5)

此时 temp 代表当前前缀的二进制值,最后可以变成一个至少 3 万位以上的大整数

在 Python 中,整数是 任意精度大整数,不是固定的 32bit 或 64bit。

因此,当 temp 很大时:

❗ 每次 temp * 2 都是 O(n) 时间复杂度

n = temp 的 bit 数(越来越大)。

举例:

当前 temp 的 bit 长度 一次乘 2 的耗时(大致)
64 bit(8 bytes)
1024 bit(128 bytes) 变慢
100k bit(12.5 KB) 很慢
1M bit(125 KB) 非常慢

所以时间复杂度是:

O(1 + 2 + 3 + … + n) ≈ O(n²)(大整数累积开销)


第二段代码:x = (x << 1 | bit) % 5 始终保持 x ∈ {0,1,2,3,4}

关键就是:

⭐ x 每次都取 % 5,不会超过 4

所以 (x << 1 | bit) 也只在 0~9 之间,非常小,运算始终 O(1)。

对整个 nums 长度 N 的复杂度:O(N)


性能差异直观示例

假设 nums 长度 = 100000:

第一段代码

  • temp 最终变成一个 100000 比特的超大整数
  • 每次乘法都要处理越来越大的大整数
  • 实际会到 几十毫秒甚至几百毫秒级

第二段代码

  • x 全程 < 5
  • 每次循环常数时间
  • 实际只有约 0.5ms ~ 1ms

所以差了 100 倍非常正常。

在c++的算法实现中早已经有大整数的加减乘除相关的算法题,python具体的大整数的操作也是类似的,具体算法的关键词是高精度加减乘除,具体实现即是用数组列表去存对于的数字的每位,然后基于这个数组去模拟运算过程,加减法时间复杂度是O(N) ,乘除的时间复杂度是O(N^2),这里N代表对应数组的长度。
相关题目链接:
P1601 A+B Problem(高精) – 洛谷

P2142 高精度减法 – 洛谷

P1480 A/B Problem – 洛谷

P1303 A*B Problem – 洛谷

所以在我们使用python进行运算的时候,需要注意评估我们的中间临时变量的可能取值范围,适当在不影响算法结果的前提下需要取模控制数位长度。

参考文献

[1].https://cloud.tencent.com/developer/article/1877295

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇