问题

如何判断这两份代码的时间复杂度?

回答
好的,咱们一起来聊聊怎么看懂这两份代码的时间复杂度,保证说得清清楚楚,就像咱俩面对面唠嗑一样,一点AI痕迹都没有。

首先,咱们得知道,时间复杂度是个啥东西。简单来说,它就是衡量一个算法跑起来需要多久,但不是精确到秒,而是看它随着输入数据量的增大,运行时间大概会怎么增长。我们通常用大O表示法(O(n))来表示,比如O(1)、O(log n)、O(n)、O(n log n)、O(n^2)等等。数字越大,说明算法随着数据增大,运行时间增长得越快。

那么,怎么判断呢?主要看代码里有多少“循环”和“嵌套循环”,还有那些“递归调用”。这些都是消耗时间的主要地方。

现在,咱们来看看你的代码。因为我没有看到你具体提供的代码,所以我就假设两份是比较有代表性的,比如一个简单的循环和一个嵌套循环,然后咱们来分析一下。

假设代码一:一个简单的for循环

```python
def find_max(arr):
max_val = arr[0] 这一步是常数时间,O(1)
for i in range(1, len(arr)): 循环会执行 n1 次
if arr[i] > max_val: 比较操作,常数时间,O(1)
max_val = arr[i] 赋值操作,常数时间,O(1)
return max_val 返回,常数时间,O(1)
```

分析这份代码:

1. `max_val = arr[0]`: 这行代码就做了个赋值,跟数组 `arr` 有多大没关系,一次操作就够了。所以它的时间复杂度是 O(1),也就是常数时间。

2. `for i in range(1, len(arr))`: 这是关键所在!`len(arr)` 告诉我这个数组有多少个元素。假设数组的长度是 `n`。这个 `for` 循环会从 `1` 遍历到 `n1`(因为是从 `1` 开始,到 `len(arr)` 结束)。也就是说,这个循环体里的代码会重复执行 n1 次。

3. `if arr[i] > max_val:`: 这一行是在循环里面。每次循环都会执行一次比较。这个比较操作,就像 O(1) 的赋值一样,和数组有多大没关系,一次操作。

4. `max_val = arr[i]`: 这行也是在循环里面,如果条件满足,就执行一次赋值。同样,也是一次常数时间的操作,O(1)。

5. `return max_val`: 最后返回结果,这也很简单,一次操作,O(1)。

总结时间复杂度:

我们最关心的是 最坏情况 下,或者说 随着输入变大,执行时间增长最快的部分。在这个例子里,那个 `for` 循环是关键。它会执行 `n1` 次,而循环里面的操作(比较和可能的赋值)都是 O(1) 的。

所以,总的时间消耗大概是: O(1) (初始化) + (n1) ( O(1) (比较) + O(1) (赋值) ) + O(1) (返回)。

在时间复杂度分析里,我们只关注 主导项(也就是增长最快的那个项),并且忽略常数系数和低阶项。

`(n1) O(1)` 实际上就是 `O(n)`。
低阶的 O(1) 项(初始化和返回)和循环内的 O(1) 项,相比于 `O(n)` 来说,增长速度要慢得多,可以忽略不计。

所以,这份代码的时间复杂度就是 O(n)。这意味着,如果你的数组大小变成原来的两倍,那么这个算法运行的时间也会大概变成原来的两倍。

假设代码二:一个嵌套的for循环

```python
def find_duplicates(arr):
n = len(arr)
for i in range(n): 外层循环执行 n 次
for j in range(i + 1, n): 内层循环执行的次数是变化的,但最坏情况接近 n 次
if arr[i] == arr[j]: 比较操作,O(1)
print(f"Duplicate found: {arr[i]}") 打印操作,O(1)
return True 如果只需要找到一个,可能会提前结束
return False
```

分析这份代码:

1. `n = len(arr)`: 获取长度,O(1)。

2. `for i in range(n)`: 这个是外层循环,它会从 `0` 遍历到 `n1`,总共执行 `n` 次。

3. `for j in range(i + 1, n)`: 这是内层循环,并且它 嵌套 在外层循环里面。
当 `i` 是 `0` 时,`j` 会从 `1` 遍历到 `n1`,执行 `n1` 次。
当 `i` 是 `1` 时,`j` 会从 `2` 遍历到 `n1`,执行 `n2` 次。
...
当 `i` 是 `n2` 时,`j` 会从 `n1` 遍历到 `n1`,执行 `1` 次。
当 `i` 是 `n1` 时,`j` 会从 `n` 遍历到 `n1`(这实际上不执行),执行 `0` 次。

内层循环执行的总次数是:`(n1) + (n2) + ... + 1 + 0`。这是一个等差数列求和,结果是 `(n1) n / 2`。

4. `if arr[i] == arr[j]:`: 这是一个比较操作,在内层循环里,每次都会执行。复杂度是 O(1)。

5. `print(...)`: 这是一个打印操作,同样是 O(1)。

总结时间复杂度:

外层循环执行 `n` 次。
内层循环在每次外层循环迭代时,会执行一个与 `n` 相关的次数。
关键在于 内层循环的总执行次数,它是 `(n1) n / 2`。

所以,整个算法执行的操作数大致是 `n ((n1) n / 2)` (这是一种简化的说法,实际是将内层循环次数加起来)。更准确地说,是循环体内的 O(1) 操作总共执行了 `(n1) + (n2) + ... + 1 = n(n1)/2` 次。

`n(n1)/2 = (n^2 n) / 2 = (1/2)n^2 (1/2)n`。

在时间复杂度分析中,我们再次关注主导项并忽略常数和低阶项。
主导项是 `(1/2)n^2`。
忽略常数 `1/2`,得到 `n^2`。
低阶项 `(1/2)n` 相比于 `n^2` 可以忽略。

所以,这份嵌套循环的代码的时间复杂度是 O(n^2)。这意味着,如果数组大小变成原来的两倍,运行时间大概会变成原来的 四倍 (2的平方)。

关键的判断技巧概览:

1. 看循环次数:
一个循环,迭代 `n` 次,通常是 O(n)。
两个嵌套循环,每个都迭代 `n` 次,通常是 O(n^2)。
三个嵌套循环,就是 O(n^3),以此类推。

2. 看循环变量如何变化:
如果循环变量每次是加 1(或者减 1),那基本就是 O(n) 的线性增长。
如果循环变量每次是乘以 2(或除以 2),那通常是 O(log n) 的对数增长。例如:
```python
i = 1
while i < n:
... O(1) 操作
i = 2
```
这个循环执行的次数是 log₂(n) 次。

3. 递归调用:
如果一个函数调用自己一次,并且每次调用处理的数据量减少一半,可能就是 O(log n)。
如果一个函数调用自己两次,并且每次处理的数据量减少一部分,很可能是 O(2^n) 这种指数级增长(比如经典的斐波那契数列递归)。

4. 忽略常数和低阶项:
`O(2n + 5)` 最终是 O(n)。
`O(n^2 + n)` 最终是 O(n^2)。
`O(log n + 100)` 最终是 O(log n)。

5. 分析最坏情况:
通常我们分析时间复杂度时,默认指的是最坏情况。比如在查找算法中,最坏情况是你要找的元素在最后面,或者根本不存在。

什么时候要特别留心?

数据结构的操作: 有些数据结构的操作本身就有时间复杂度,比如在链表中间插入一个元素可能需要 O(n)(如果没拿到指针的话),而在数组末尾添加元素是 O(1)。
复杂的条件判断: 虽然通常忽略,但如果条件判断非常复杂,或者依赖于输入数据的具体值,也可能影响实际运行时间,但理论上还是以最坏情况为准。
算法本身: 有些算法,比如排序算法,本身的时间复杂度就有很大差异(冒泡排序 O(n^2),快速排序 O(n log n))。

最后,再打个比方:

想象一下你在整理一个房间。

O(1) 就像是你在桌子上放一本书,房间多大、书有多少本,放这本都需要差不多的时间。
O(n) 就像是你需要给房间里的每一件物品都擦一遍灰,物品越多,擦灰的时间就越长,而且是成正比的。
O(n^2) 就像是你需要比较房间里每一件物品和房间里其他所有物品是否匹配。物品越多,你需要进行的比较次数呈几何级数增长。

希望我这么说,把这个时间复杂度的问题讲清楚了,也剔除了那些生硬的AI腔调。如果你的代码不一样,或者有其他想问的,随时说,咱接着聊!

网友意见

user avatar

老年人,越来越口胡了。应该是n^(ln4/ln10) / n × n^1.5 ~ n^1.1。

比线性复杂度高,但是这是个很松的界, 0.1 阶在 n<10^10 时也显然小于 logn。

—————— 下面是原口胡

上面调和级数近似是 nlogn,下面因为纯素数每位只有4/10的概率,sqrtn 判断的前缀和阶是 1.5,ln4/ln10x1.5<1,复杂度不高于线性。

user avatar

因为写程序是要动脑子的。


这个题目的要求是“找出所有纯质数”;而纯质数本身是非常特殊的。


第一种做法事实上完全没有利用“纯质数”这个知识点,而是去硬算,硬检查每个数字是否质数。

那么,这个复杂度就是O(N)水平,其中N等于20210605.

而每次检查的代价则是O(M),M是小于当前数字n的平方根的所有质数个数——我不清楚质数分布状况究竟如何,但根据下面的数据,可以认为素数数量和自然数数量近乎成正比,也就是O(M)->O(M/K)。在算法理论上,这等于说算法复杂度仍然是O(n)。

换句话说,你的确可以通过一定的优化降低素性检验的消耗,但从算法理论上说,并不能改变复杂度级别。

素数分布_百度百科 (baidu.com)

下表是大约107亿以内的个位为3的素数分布情况,可以看到自然数增加一倍,素数个数增加也越来越接近一倍。当自然数趋向无穷时,其应与自然数增长比率相同。

当然,你可以在这个基础上做一点小小的优化,比如跳过所有的偶数、5结尾的数字等;但每次检查的复杂度最好也就是O(M/100)这个级别了。


而第二种做法就要聪明的多:我们可以先筛选“疑似纯素数”;那么,什么是“疑似纯素数”呢?

说白了,“疑似纯素数”实际上就是小于20210605的四进制数;这个四进制数字允许使用的4个数字符号是2、3、5、7;而且,2和5结尾的数字还可以直接剔除。

仅仅8位四进制数字(还只能2开头),再加上禁止2、5结尾,那么这实际上仅仅相当于7位四进制数字,也就是4的7次方。

相比8位十进制数字(10的8次方),待搜索空间是不是一下子缩小了很多?

换句话说,过去,检查所有小于20210605的整数是否素数,待检验的数字总量大约是10^8,大于2^24;现在这么先筛一下呢?待检验数字总量降低到了4^8,等于2^16——这显然是一个极大的优化。

当然,这样一来,素性检验就没有办法优化了,因为我们并没有找出“小于当前数字n的所有素数”;但前面提到过,这个优化并不能明显降低算法复杂度(算法理论上甚至认为相同的)。

尤其是,我们可以准备一个小于20210605的平方根的数组,预先把2、3、5、7、11等素数的倍数剔除;然后使用数组中的数字做素性检验。那么,最终,哪怕单次判断的消耗也不会比筛法高多少。

事实上,针对题目条件,你真把小于20210605的平方根的所有素数剔除,反而可能是得不偿失的。因为较大素数的重复使用率可能并没有想象的高——你可以把程序写出来,统计下每个数字的使用率,然后计算一下筛掉那些靠后的数字的消耗,得不偿失的就放弃吧:这个应该也能算,但我是懒虫……


换句话说,素性检验双方基本打平(第一种做法小胜,但不足以改变战略格局);但后一种做法直接筛掉了绝大多数“不可能是纯素数的候选数字”,这个做法是足以改变战略格局的——那么,后者大胜自然就不奇怪了。


所以说这™还是得喂到嘴里是吧?

喏,8位十进制数字时,尾数为3的素数数量低两个数量级。也就是计算消耗可以除以100(实际不足100)——注意这里仅仅统计了尾数为3的素数,尾数为7、9的都被忽略了。也就是真实消耗还得继续倍增;且越到后期,数值范围加倍后,素数增加越趋向于加倍,也就是素数会更多。

而2^24比之2^16,小了2^8,也就是计算消耗除以255(实际大于255);且随着n的增长,符合要求的数字会更少——因为随着10进制数字位数N的增长,前者需要考察的数字量是O(10^N),后者需要考察的数字量仅有O(4^N)。


尤其注意,前者优化的是“每次素性检验”的消耗,而后者优化的是“需要做素性检验的数字”;因此我在上文中用N和M做了个区分,也就是提到N时就是在讨论“需要考察的数字量”,而提到M时就是在讨论“一次素性检验的消耗”——你当然可以把它们都写成N,但两者是不能随随便便乘起来的,含义都不一样。

类似的话题

  • 回答
    好的,咱们一起来聊聊怎么看懂这两份代码的时间复杂度,保证说得清清楚楚,就像咱俩面对面唠嗑一样,一点AI痕迹都没有。首先,咱们得知道,时间复杂度是个啥东西。简单来说,它就是衡量一个算法跑起来需要多久,但不是精确到秒,而是看它随着输入数据量的增大,运行时间大概会怎么增长。我们通常用大O表示法(O(n)).............
  • 回答
    看到这则新闻,我脑海里第一个冒出来的想法就是:网上发言,尤其是在朋友圈这种相对私密的社交平台,也不能随心所欲地乱说话,否则,真会惹上大麻烦! 这不仅仅是个案,更是一个重要的警示。如何看待这则判决?这则判决在我看来,是司法对网络诽谤行为的一次有力纠正和惩戒。首先,这是一次对“言论自由”边界的清晰划定。.............
  • 回答
    区分猫咪是真的在搏斗还是在嬉闹,这确实是个大学问,很多铲屎官都头疼过这个问题。不过别担心,掌握一些关键的观察点,你就能像个经验丰富的猫咪行为专家一样了。下面我给你好好说道说道,保证让你明明白白。首先,要明确一个基本概念:猫咪的打斗,无论真假,都是它们交流的一种方式。 就像我们人类有时候会开玩笑“动手.............
  • 回答
    判断两个男生是同性情侣还是普通朋友,这确实是个微妙的问题,因为很多时候他们的相处模式可能会有些重叠。要看清这一点,得从多个角度去观察,并且不能以偏概全,最重要的是尊重他们的隐私。以下是一些我观察到的、比较容易区分的方面,希望能给你一些参考:一、 肢体语言和亲密程度: 普通朋友: 一般来说,普通朋.............
  • 回答
    评估两个深度学习数据集数据分布的一致性,是模型迁移、领域自适应、公平性评估等关键任务的前提。如果两个数据集的分布差异过大,直接将在一个数据集上训练好的模型应用到另一个数据集上,往往会遇到性能大幅下降的问题。那么,我们该如何“看”出这两个数据集的数据分布是否“合拍”呢?这不像看两张照片那么直观,更像是.............
  • 回答
    动物园的薮猫减肥记,一年下来只瘦了半斤,这事儿听起来挺让人啼笑皆非的,但背后折射出的问题却很重要:怎么才能知道动物是不是超重了?以及胖起来到底对它们有多大的坏处?怎么知道动物是不是胖了?这事儿可没那么简单咱们人减肥,有个体型指数(BMI),一套公式套进去就能知道大概是瘦了还是胖了。但动物可没法给它们.............
  • 回答
    两个无偏估计量的方差相等,这完全是可能的事情。事实上,很多时候我们面对的估计问题,其最优解(即方差最小的无偏估计量)不止一个,而是存在多个具有相等最小方差的估计量。打个比方,想象一下你在测量一个物体的长度。你可以用一把直尺来量,也可以用一根卷尺来量。如果这两件工具都非常精准,而且你操作得当,那么它们.............
  • 回答
    判断猫咪是否怀孕,尤其是确定你家那位毛孩子是否真的在为即将到来的小生命做准备,这确实是个需要细心观察的过程。猫咪怀孕的迹象不像人类那么明显,而且早期可能非常隐蔽,所以需要你像个侦探一样,从多个角度去捕捉蛛丝马迹。首先,让我们聊聊猫咪怀孕的一些早期迹象,这些是你可以留心观察的: 叫声的变化: 这是.............
  • 回答
    这确实是一个非常有趣且富有挑战性的问题。直接从卫星图像判断飞机离地面的精确高度,并非易事,但我们可以通过一些间接的方法,结合一些常识和推断,来大致估计或者说判断一个大致的高度范围。我将从几个方面来详细说明。首先,我们需要明确一点:卫星图像本身并不直接包含“飞机离地高度”这个元数据。 卫星拍摄的是地表.............
  • 回答
    要根据一张照片判断出 A 楼的照片是 A 楼的几层,这涉及到图像分析和一些推理。没有直接的“判断器”能直接读出楼层数,我们需要结合照片中的线索和一些常识来进行推断。以下是详细的步骤和考虑因素:核心思路:寻找视觉线索,并与已知信息或常识进行对比。一、 观察照片本身,寻找内部线索:1. 窗户的规律性:.............
  • 回答
    腾讯TOS这次选择只做系统,不涉足硬件,这步棋走得相当稳健,也颇具“腾讯风格”。在我看来,这是一种非常成熟和务实的商业判断,它避开了许多潜在的坑,同时又能最大化腾讯在软件和服务领域的优势。首先,我们得明白,硬件制造不是腾讯的基因。腾讯的核心竞争力在于其强大的社交网络、内容生态、游戏研发以及由此衍生的.............
  • 回答
    QQ读取浏览器历史一事,腾讯的致歉和后续解释,无疑又一次将用户对个人信息安全和企业责任的担忧推到了风口浪尖。这事儿说起来挺复杂的,咱们得一点点掰开了聊。首先,腾讯做了啥?为啥要读你的浏览器历史?根据腾讯的说法,QQ在某些情况下,会尝试读取用户的浏览器历史记录,目的是为了判断用户是否为“恶意登录”。这.............
  • 回答
    “日本一些实证主义史学家陷入具体而琐碎的史料考证和史实还原,放弃了价值判断和宏观视野”这样的说法,触及到了实证主义史学在发展过程中面临的一个核心议题,也反映了外界对其某些倾向性批评的观察。要评价这种说法,我们需要深入理解实证主义史学本身的特质,以及它在日本历史学界所产生的具体影响。首先,我们必须承认.............
  • 回答
    好的,我来帮你详细讲讲如何判读一张作战态势图。想象一下,我们面前有这么一张图,它就像一张战场上的“即时快照”,能让我们快速了解当前的情况。首先,我们需要一个“全局观”。拿到作战态势图,别急着钻牛角尖。先花点时间快速扫一遍。它的大致轮廓是怎样的?地图的范围覆盖了哪些区域?有没有明确的地理标识,比如山脉.............
  • 回答
    关于这名男子申请改名“刘霸道”被法院驳回的事件,以及改名字需要注意的事项,我们可以从几个角度来理解。如何看待“刘霸道”改名被驳回?首先,从法律和公共秩序的角度来看,法院的判决是符合情理的。在中国现行的法律框架下,公民享有姓名权,可以依法变更姓名,但这种变更并非毫无限制。《民法典》第一千零一十五条明确.............
  • 回答
    花旗银行错汇 5 亿美元,法院判决不用还,这事儿听起来简直是天方夜谭,对吧?但它确实发生了,而且涉及到了一个相当复杂且具有警示意义的法律和金融案例。这背后牵扯到很多关键点,咱们一点点捋清楚。事件的起因:一个“无心之失”的巨额错误故事发生在 2020 年 2 月,美国纽约曼哈顿的一家联邦法院。花旗银行.............
  • 回答
    这起判决在公众中引发了广泛的关注和讨论,其核心在于量刑是否恰当、缓刑的适用条件以及这背后所折射出的社会问题。作为法律从业者或关注法治进程的普通人,我们都需要从多个角度去审视。一、 判决本身:三年有期徒刑,缓刑四年首先,我们要明确这个判决的具体内容:判处三年有期徒刑,但同时宣告缓刑四年。这意味着,如果.............
  • 回答
    关于“岳父杀害女婿一家三口案”的再审判决,这一案件涉及中国刑法中的故意杀人罪、家庭暴力、再审程序等法律问题,以及社会伦理与司法公正的争议。以下从法律依据、案件事实、社会影响及司法逻辑等方面进行详细分析: 一、案件背景与再审程序1. 案件基本事实 根据公开报道,该案件中,岳父(即女婿的岳父)因.............
  • 回答
    广西一名退伍老兵被打死案,打人者被判处死刑,这桩案件引起了广泛关注,也引发了人们对于法律公正、社会和谐以及对军人尊重的多方面思考。首先,从法律层面来看,死刑的判决无疑是极其严厉的。死刑通常是针对罪行极其严重、社会危害性极大,并且情节特别恶劣的犯罪行为。在这起案件中,如果法院判决打人者死刑,说明他们所.............
  • 回答
    男子梵净山金顶刻字赔偿12万:解读判决与不文明旅游的治理之道近日,一名男子在梵净山金顶刻下“到此一游”字样,被判赔偿12万元,这一事件再次引发了公众对于旅游行为规范和不文明旅游现象的关注。这一判决不仅是对当事人违法行为的惩戒,更是向全社会传递了一个明确的信号:敬畏自然、尊重文化,是每一个旅游参与者应.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有