AIGC时代算法工程师的面试秘籍(2024.4.29-5.12第十三式) |【三年面试五年模拟】

写在前面

【三年面试五年模拟】旨在整理&挖掘AI算法工程师在实习/校招/社招时所需的干货知识点与面试方法,力求让读者在获得心仪offer的同时,增强技术基本面。也欢迎大家提出宝贵的优化建议,一起交流学习💪

欢迎大家关注Rocky的公众号:WeThinkIn
欢迎大家关注Rocky的知乎:Rocky Ding
获取更多AI行业的前沿资讯与干货资源

大家好,我是Rocky。

《三年面试五年模拟》系列作品帮助很多读者获得了心仪的算法岗offer,收到了大家的很多好评,Rocky觉得很开心也很有意义。

在AIGC时代到来后,Rocky对《三年面试五年模拟》整体战略方向进行了重大的优化重构,在秉持着Rocky创办《三年面试五年模拟》项目初心的同时,增加了AIGC时代核心的版块栏目,详细的版本更新内容如下所示:

  1. 整体架构:分为AIGC知识板块和AI通用知识板块。
  2. AIGC知识板块:分为AI绘画、AI视频、大模型、AI多模态、数字人这五大AIGC核心方向。
  3. AI通用知识板块:包含AIGC、传统深度学习、自动驾驶等所有AI核心方向共通的知识点。

Rocky已经将《三年面试五年模拟》项目的完整版构建在Github上:https://github.com/WeThinkIn/Interview-for-Algorithm-Engineer/tree/main,欢迎大家star!

本文是《三年面试五年模拟》项目的第十三式,考虑到易读性与文章篇幅,Rocky本次只从Github完整版项目中摘选了2024年4月29号-2024年5月12号更新的部分经典&干货面试知识点和面试问题,并配以相应的参考答案(精简版),供大家学习探讨。

在《三年面试五年模拟》版本更新白皮书,迎接AIGC时代中我们阐述了《三年面试五年模拟》项目在AIGC时代的愿景与规划,也包含了项目共建计划,感兴趣的朋友可以点击阅读。

当然的,本项目中的内容难免有疏漏与错误之处,欢迎大家在文末评论进行补充优化,Rocky将及时更新完善到Github上!

希望《三年面试五年模拟》能陪伴大家度过整个AI行业的职业生涯,并且让大家能够持续获益。

So,enjoy(与本文的BGM一起食用更佳哦):

正文开始

目录先行

AI绘画基础:

  1. 目前主流的AI绘画大模型有哪些?

  2. SD模型训练时需要设置timesteps=1000,在推理时却只用几十步就可以生成图片?

深度学习基础:

  1. 什么是模型微调(fine-tuning)?

  2. 深度学习中常用的学习率衰减策略有哪些?

机器学习基础:

  1. 什么是奥卡姆剃刀原理?

  2. 什么是没有免费的午餐定理?

Python编程基础:

  1. Python中PIL和OpenCV处理图像的区别?

  2. Python中全局变量与局部变量之间的区别?

模型部署基础:

  1. 什么是模型蒸馏?

  2. bfloat16精度和float16精度的区别?

计算机基础:

  1. conda创建管理虚拟环境的命令大全

  2. 如何让两台服务器之间ssh免密通信?

大厂高频算法题

  1. 实现快速排序代码

开放性问题:

  1. AIGC时代的ToC产品开发流程是什么样的?

  2. AIGC时代有哪些可以落地的技术方向?

AI绘画基础

【一】目前主流的AI绘画大模型有哪些?

目前,几个主流的文生图大模型包括:

  1. Midjourney系列(V5-V6)
  2. Stable Diffusion系列(1.x、2.x、XL、3)
  3. DaLL·E系列(2-3)
  4. PixArt系列(α、Σ)
  5. Ideogram 1.0
  6. Playground v2.5
  7. Imagen系列(1、2)

【二】SD模型训练时需要设置timesteps=1000,在推理时却只用几十步就可以生成图片?

目前扩散模型训练一般使用DDPM(Denoising Diffusion Probabilistic Models)采样方法,但推理时可以使用DDIM(Denoising Diffusion Implicit Models)采样方法,DDIM通过去马尔可夫化,大大减少了扩散模型在推理时的步数。

深度学习基础

1、什么是模型微调(fine-tuning)?

在AI行业中,模型微调(Fine-tuning)是一种基础有效的技术,特别适用于迁移学习场景,其中预训练模型的参数被稍作训练调整以适应新的、但与原始训练任务相似的任务。这种方法非常适合于数据量有限的情况,可以显著提高模型的性能和泛化能力。

模型微调的基本步骤:

  1. 选择预训练模型

    • 开始微调之前,首先需要一个已经在相关任务上预训练好的模型,通常这些模型在大规模数据集(如ImageNet、Laion等)上进行预训练。因为这些模型已经学习到了丰富的特征表示,可以作为新任务的起点。
  2. 初始化

    • 微调时,通常保留预训练模型的大部分或所有权重,作为新任务训练的初始化点。
  3. 修改模型结构

    • 根据新任务的需求,可能需要对模型的最后几层进行修改。例如,在图像分类任务中,最后的全连接层(输出层)可能需要根据新任务的类别数进行调整。
  4. 重新训练

    • 在新的数据集上继续训练模型。通常只需重新训练模型的一部分,特别是那些针对特定任务调整过的层,而其他层可以保持原始预训练时的参数或者以较小的学习率进行微调,以避免过度拟合。
  5. 调整学习率

    • 微调时通常使用比原始预训练时更小的学习率,这有助于保持已经学习到的有用特征,并仅对它们进行精细的调整。

模型微调的应用场景:

  • AIGC:AI绘画、AI视频、大模型、AI多模态、数字人、AI音频等。
  • 传统深度学习:图像分类、图像分割、目标检测、目标跟踪等。
  • 自动驾驶:车载图像分类、车载图像分割、车载目标检测等。

微调的好处:

  • 加速训练:由于模型从有效的初始状态开始学习,微调通常比从头开始训练快得多。
  • 需要更少的数据:微调可以在相对较少的数据上进行,因为模型已经从预训练中获得了大量的通用知识。
  • 提高性能:通过利用预训练模型的知识,可以提高模型在新任务上的表现,特别是当新任务的数据不足以从头开始训练复杂模型时。

总的来说,模型微调是一种高效利用已有知识以适应新任务的方法,特别适用于数据资源有限的场景。

2、深度学习中常用的学习率衰减策略有哪些?

在AI领域中,合适的学习率调整策略对于模型的训练效果和收敛速度至关重要。

学习率衰减(或调整)是用来在训练过程中逐步减小学习率的方法,目的是帮助模型更好地收敛,避免训练过程中的振荡或不稳定。

以下是几种常用的学习率衰减方法:

1. 固定学习率衰减

这是最简单的衰减方法之一,其中学习率按预定的固定间隔和固定因子进行减少。例如,每过10个epoch将学习率乘以0.1。

2. 指数衰减

在指数衰减模式下,学习率按照指数函数逐步减小,通常定义为:
Learning Rate = Initial Learning Rate × e − decay rate × epoch \text{Learning Rate} = \text{Initial Learning Rate} \times e^{-\text{decay rate} \times \text{epoch}} Learning Rate=Initial Learning Rate×edecay rate×epoch
其中,decay rate是一个预先设定的常数,epoch是当前的训练轮数。

3. 时间基衰减

时间基衰减与指数衰减类似,但学习率的衰减与训练的具体时间(通常是epoch数)更直接相关:
Learning Rate = Initial Learning Rate 1 + decay rate × epoch \text{Learning Rate} = \frac{\text{Initial Learning Rate}}{1 + \text{decay rate} \times \text{epoch}} Learning Rate=1+decay rate×epochInitial Learning Rate

4. 阶梯衰减

在阶梯衰减中,学习率在一系列预设的epoch(如每20个epoch)后显著下降。这种衰减通常是手动设置的,非常直观,允许模型在较高的学习率下快速学习,并在训练后期通过较低的学习率细化模型。

5. 余弦衰减

余弦衰减是一种较新的策略,它模仿了余弦函数的形状来调整学习率,从初始学习率逐渐减小到接近零的值。这种方法在一些周期性或重启的训练策略中特别有效,可以帮助模型跳出局部最小值。

6. 适应性学习率方法

这包括像Adam和RMSprop这样的优化算法,这些算法本身就能够调整每个参数的学习率,通常基于历史梯度的平方(用于归一化梯度)。这些方法自动调整学习率,无需显式的衰减策略。

7. 热身和重启

  • 学习率热身:在训练初期,学习率从一个较低的值逐渐增加到设定的初始学习率。这有助于模型在训练初期稳定下来,防止初始学习率过高导致的不稳定。
  • 周期性重启:学习率按周期性地增加和减少,每次“重启”都从较高的学习率开始,然后再次衰减。这种方法有助于模型跳出局部最小值,寻找更好的全局最小值。

这些学习率调整方法可以单独使用,也可以结合使用,以达到最佳的训练效果。选择哪种衰减策略取决于具体任务、模型的复杂性以及训练数据的特点。在实际应用中,通常需要通过多次实验来确定最合适的学习率调整策略。

机器学习基础

1、什么是奥卡姆剃刀原理?

在机器学习领域中,奥卡姆剃刀(Occam’s Razor)原理是一个重要的理论指导原则,通常被表述为:“面对一个具体问题,选择最合适和最简单的能够满足需求的算法模型。”

这一原则来源于14世纪的逻辑学家威廉·奥卡姆,他主张:“如无必要,勿增实体。”

这在传统深度学习领域已经经过大量的验证,比如说图像分类领域的ResNet、图像分割领域的U-Net、目标检测领域的YOLO,这些都是能够跨过周期的AI算法模型,都具备简洁、稳定、高效等特点。

奥卡姆剃刀在机器学习领域中的应用

在机器学习模型的设计和训练过程中,奥卡姆剃刀原则可以解释为:当两个或多个不同复杂度的模型都能够合理地解释或预测数据时,应选择最简单的那个。这一原则的应用主要体现在以下几个方面:

  1. 模型的泛化能力:简单的模型通常比复杂的模型更容易泛化到未见过的新数据上。复杂的模型可能会在训练数据上表现得非常好,但可能会因为过拟合而在新数据上表现不佳。

  2. 避免过拟合:在选择模型时,遵循奥卡姆剃刀原则有助于减少过拟合的风险。简单模型在参数少和结构简单的情况下,对数据的噪声和偶然的特征不那么敏感。

  3. 计算效率:简单模型通常计算需求较低,更快速且易于部署。在资源受限的环境中,如移动设备或嵌入式系统中,简单模型尤其受到青睐。

  4. 可解释性:简单模型通常更容易被理解和解释。在需要对模型的性能进行解释的领域(如金融、医疗等领域)中,简单模型可能更受欢迎。

如何实现奥卡姆剃刀原则

在实践中,实现奥卡姆剃刀原则可以通过以下策略:

  • 深入理解应用长颈:只有深入理解实际场景,在能够知道其中的特点与痛点,才能高屋建瓴为算法解决方案与产品的构建提供指导思想。
  • 选择合适的算法模型:根据实际场景,选择适当复杂度的模型。
  • 使用优化技巧:在模型训练过程中使用正则化项、修改模型部分结构等方法,来优化模型性能。
  • 交叉验证:使用交叉验证来评估不同模型的性能,帮助选择最合适的模型。

总之,奥卡姆剃刀原则是一种有助于指导机器学习领域的算法工程师工作的哲学思想,它鼓励我们针对实际场景寻找最简洁的算法模型。在模型选择和开发过程中恰当地应用这一原则,可以帮助开发出既有效又高效的机器学习算法解决方案。

2、什么是没有免费的午餐定理?

在机器学习和优化领域,没有免费的午餐定理(No Free Lunch Theorem, NFL)是一个非常重要的概念,由David Wolpert和William Macready在1997年首次提出。

这个定理深刻地表述了机器学习领域一个看似简单却深刻的观点:所有的优化算法在所有可能的问题上的平均性能都是相同的

定理的基本内容

没有免费的午餐定理主要针对机器学习算法和优化搜索算法,它表明没有任何一个算法能在所有可能的问题上都表现得比其他算法更好。

换句话说,一个算法如果在某类问题上表现出色,那么必然存在另一类问题,在那里它的表现就不那么理想。这意味着机器学习算法的效果很大程度上依赖于它所应用的细分领域与具体问题(具体问题具体分析)。

更深层次的挖掘,Rocky认为NFL定理告诉我们,在机器学习领域,所有的行为与优化,都是“有得必有失的”,这个哲学思想也可以让算法工程师们破圈,不仅仅用于AI行业。

Python编程基础

1、Python中PIL和OpenCV处理图像的区别?

Python中的Pillow/PIL(Python Imaging Library)和OpenCV(Open Source Computer Vision Library)都是强大的图像处理库,但它们各有特点和优势,适用于不同的应用场景。

以下是两者之间的详细对比:

  1. 数据类型:Pillow读取图像时返回的是PIL.Image.Image类型的对象。而OpenCV读取图像时返回的是NumPy数组。
  2. 颜色格式:OpenCV默认使用BGR颜色格式读取图像。而Pillow使用的是更常见的RGB格式。
  3. 应用专长:Pillow主要专注于图像的加载、处理和保存,提供了广泛的图像处理能力,如图像缩放、裁剪、过滤、图像合成等,更加侧重于图像处理的基本操作和图像的IO操作。OpenCV是一个专注于实时计算机视觉的库,它的功能不仅限于图像处理,还包括视频处理、人脸识别、对象检测、复杂图像分析等,适用于需要快速有效处理大量数据的应用。
  4. 性能和效率:对于高性能的实时计算机视觉任务,OpenCV通常比Pillow表现得更好,因为OpenCV底层使用了优化的C++代码,同时支持多线程和GPU加速。在常规图像处理任务中,Pillow更易于使用,且对于基本的图像处理任务已经足够快,并且易于集成到Python应用中。

总结

Pillow适合于需要处理图像文件、执行基本图像处理任务的应用,而OpenCV适合于需要实施复杂的图像分析、计算机视觉处理或实时视频处理的项目。选择哪个库取决于你的具体需求、项目复杂度以及性能要求。

2、Python中全局变量与局部变量之间的区别?

在Python中,全局变量和局部变量的区别主要体现在变量的作用域、声明位置以及在程序中的可访问性上。理解这些差异有助于我们更好地管理数据的流向和变量的生命周期,防止不必要的编程错误。

全局变量

  1. 定义与作用域

    • 全局变量是在函数外部定义的,其作用域覆盖了整个代码文件/定义它的模块。
    • 在任何函数内部和外部都可以访问全局变量(除非被局部作用域的同名变量遮蔽)。
  2. 使用场景

    • 当多个函数需要访问同一数据时,可以使用全局变量。
    • 用于定义整个应用程序可能需要的配置信息或共享数据。

局部变量

  1. 定义与作用域

    • 局部变量是在函数内部/代码块中定义的,它只在定义它的函数或代码块内部有效。
    • 函数或代码块执行完毕后,局部变量的生命周期结束,它们所占用的内存也随之释放。
  2. 使用场景

    • 当变量的用途仅限于特定函数或代码块时,应使用局部变量。
    • 局部变量有助于保持函数的独立性,使函数更易理解和重用。
  3. 优势

    • 局部变量避免了函数间的数据交互问题,减少了代码的耦合度。
    • 使用局部变量可以提高代码的可读性和维护性。

访问和修改全局变量

在Python中,如果你需要在一个函数内部修改全局变量,你必须使用global这个全局关键字来进行声明:

x = 10  # 全局变量

def update():
    global x
    x = 20  # 修改全局变量

def print_x():
    print(x)  # 访问全局变量

update()
print_x()  # 输出: 20

如果不使用global全局关键字,对全局变量的修改实际上会创建一个同名的新的局部变量,而不会改变全局变量的值。

模型部署基础

1、什么是模型蒸馏?

模型蒸馏(Model Distillation)是一种模型压缩技术,旨在将一个**大型复杂模型(通常称为“教师模型”)的知识转移到一个小型简单模型(称为“学生模型”)**中。

模型蒸馏技术最开始由Hinton等人于2015年提出,主要用于改进小型模型的性能,使其在保持较低计算成本的同时,能够逼近大型模型的性能。

模型蒸馏的基本原理

模型蒸馏的基本思想是使用大型模型的输出(软标签)来训练小型模型。

大型模型的输出通常包含了关于类别概率的更多信息,这些信息比硬标签(即实际的类别标签)更能表达不同类别之间的相对关系。通过训练小型模型去学习逼近这些软标签,小型模型可以学习到更细致的决策边界。

模型蒸馏的步骤

  1. 训练教师模型
    教师模型通常是一个大型深度网络,能够在AI细分任务上达到SOTA精度。

  2. 生成软标签
    使用教师模型对训练数据集进行预测,记录输出的类别概率(软标签)。这些概率不仅表示最可能的类别,还提供了对其他类别的预测概率,包含了更丰富的信息。

  3. 训练学生模型
    学生模型的结构比教师模型简单,其训练过程不仅使用真实的标签(硬标签),还使用教师模型生成的软标签。通常,训练过程中会使用一个**温度参数(T)**来调整软标签的"软化"程度。损失函数是硬标签的损失和软标签的损失的加权和。

  4. 评估学生模型
    在独立的测试数据上评估学生模型的性能,验证其是否成功学习到了教师模型的知识。

温度调整(Temperature Scaling)

在蒸馏过程中,温度参数T用于控制软标签的平滑程度。较高的温度会使得概率分布更加平滑,使得学生模型能够从教师模型的预测中学到更细微的差别。损失函数通常是交叉熵损失,计算学生模型预测和软标签之间的差异。

模型蒸馏的优势

  • 效率提升:学生模型通常比教师模型更小、更快,适合部署在资源受限的环境中。
  • 泛化能力:学生模型通过学习教师模型的软标签,通常可以获得比直接训练更好的泛化能力。

实际应用

模型蒸馏已被广泛应用于多种任务,如AI绘画、图像分类、图像分割、目标检测、语音识别和自然语言处理等,特别是在需要模型部署到移动设备或需要实时处理的场景中。

总之,模型蒸馏是提高模型部署效率的有效技术,特别适合于需要在保持模型性能的同时减小模型大小和提升计算速度的应用场景。

2、bfloat16精度和float16精度的区别?

BFLOAT16

定义与结构
BFLOAT16是一种16位宽的浮点数格式,由Google针对Tensor Processing Units (TPUs)开发,特别适用于AI算法应用。它的结构如下:

  • 1位符号位
  • 8位指数
  • 7位尾数

这种格式与标准的32位浮点数(FP32)共享相同的指数范围,但尾数精度较低。这意味着BFLOAT16在表示大范围数值时与FP32相近,但在表示精度上有所折衷。

优点

  • 较大的动态范围:与Float16相比,BFLOAT16能够表示更大范围的数值,这归功于它更大的指数范围。这对于深度学习中的梯度和归一化运算非常重要,因为这些操作可能涉及广泛的数值范围。
  • 与FP32兼容性好:由于指数位与FP32相同,BFLOAT16可以无损地转换为FP32,这简化了混合精度训练的实现,同时减少了转换过程中的精度损失。

缺点

  • 较低的数值精度:因为尾数位只有7位,相比于Float16的10位尾数,BFLOAT16在表示精确数值时的能力较弱。

Float16(FP16)

定义与结构
Float16是IEEE定义的16位浮点数标准,结构如下:

  • 1位符号位
  • 5位指数
  • 10位尾数

Float16提供了较FP32更低的精度和较小的数值范围,但在存储和计算效率上具有优势。

优点

  • 较高的数值精度:Float16的10位尾数提供了比BFLOAT16更高的精度,适合需要高精度计算的应用。
  • 计算加速:在支持Float16运算的硬件上(如GPU),使用Float16可以显著加速计算过程,尤其是在AI模型训练和推理中。

缺点

  • 较小的动态范围:Float16的5位指数提供的动态范围较小,可能导致在一些AI训练场景中出现梯度消失或爆炸问题。
  • 兼容性问题:Float16到FP32的转换可能会涉及更复杂的数值调整,可能导致精度损失。

应用场景

  • BFLOAT16:由于其较大的动态范围和与FP32的良好兼容性,非常适合用于AI模型的训练和推理,尤其是在Google的TPU上。
  • Float16:适用于对计算精度要求较高的场景,并且在NVIDIA及其他厂商的GPU上得到了广泛支持,尤其适合于需要加速的AI算法任务。

计算机基础

Rocky从工业界、应用界、竞赛界以及学术界角度出发,总结沉淀AI行业中需要用到的实用计算机基础知识,不仅能在面试中帮助到我们,还能让我们在日常工作中提高效率

1、conda创建管理虚拟环境的命令大全

在AIGC时代,各种AI工作流飞速繁荣,我们要做好每个工作流与算法解决方案的环境配置与隔离,避免冲突,以免导致日常工作中的思维混乱。

Conda是一个主流的包管理器和环境管理器,常用于数据科学、机器学习和科学计算领域。使用Conda可以轻松地创建、管理和共享虚拟环境,下面是Conda在虚拟环境管理方面的一些常用命令:

创建虚拟环境

  • 创建新的虚拟环境

    conda create -n myenv
    

    这会创建一个名为 myenv 的新虚拟环境。

  • 指定Python版本

    conda create -n myenv python=3.8
    

    创建一个包含特定 Python 版本(例如 Python 3.8)的虚拟环境。

    • 指定环境保存地址
    conda create -p /本地路径/myenv python=3.8
    

激活和停用虚拟环境

  • 激活虚拟环境

    conda activate myenv
    

    激活名为 myenv 的虚拟环境。

  • 停用虚拟环境

    conda deactivate
    

    停用当前激活的虚拟环境。

管理虚拟环境中的包

  • 安装包

    conda install numpy
    

    在当前激活的环境中安装包(例如安装 NumPy)。

  • 列出环境中的包

    conda list
    

    显示当前环境中安装的所有包。

  • 更新包

    conda update numpy
    

    更新当前环境中的特定包(例如 NumPy)。

  • 卸载包

    conda remove numpy
    

    从当前环境中卸载特定的包。

管理环境

  • 列出所有虚拟环境

    conda env list
    或者
    conda info --envs
    

    这些命令显示所有已创建的虚拟环境。

  • 复制虚拟环境

    conda create -n myenv2 --clone myenv
    

    创建一个名为 myenv2 的新环境,这是 myenv 的完整副本。

  • 删除虚拟环境

    conda remove -n myenv --all
    

    删除名为 myenv 的虚拟环境。

  • 导出环境到文件

    conda env export > environment.yml
    

    将当前环境的所有包导出到 environment.yml 文件中,便于再现环境。

  • 从文件创建环境

    conda env create -f environment.yml
    

    根据 environment.yml 文件创建虚拟环境。

这些命令为使用Conda管理虚拟环境提供了全面的控制,使得在不同项目之间隔离依赖关系和环境配置变得简单。这对于确保项目的可重现性和避免依赖冲突非常重要。

2、如何让两台服务器之间ssh免密通信?

在Ubuntu系统中设置基于SSH密钥的认证,可以在两台服务器之间进行无密码连接。这对于自动化任务(如文件传输、备份和远程命令执行)特别有用。以下是设置SSH密钥认证的步骤:

  1. 创建.ssh目录

假定有2台Linux服务器主机,分别为A,B。

我们先在所有服务器主机上创建ssh目录并赋予权限:

mkdir /root/.ssh 
chmod 700 /root/.ssh
  1. 生成公钥与私钥

我们接着需要生成所有服务器主机的公钥与私钥,执行以下命令:

$ cd ~  # 进⼊入用户目录
$ ssh-keygen -t rsa -P ""  # 生成ssh密码,-t 参数表示生成算法,可以选择rsa和dsa;-P表示使用的密码,""表示无密码。
  1. 将公钥追加authorized_keys文件中

将第一台服务器主机A上生成公钥追加到authorized_keys文件中:

$ cd ~/.ssh  # 进入.ssh目录
$ cat id_rsa.pub >> authorized_keys   # 将id_rsa.pub的内容追加到authorized_keys文件中

接下来我们使用同样的命令在服务器主机B上生成id_rsa.pub并写入到服务器主机A的authorized_keys文件中,再将服务器主机A的authorized_keys文件复制到服务器主机B的对应路径下即可:/root/.ssh/

大厂高频算法题

1、实现快速排序代码

快速排序(Quick Sort)是一种高效的排序算法,由C. A. R. Hoare在1960年提出。它是一种分治法(Divide and Conquer)策略的典型应用。

快速排序的原理:

  1. 选择基准值(Pivot)
    快速排序首先从数组中选择一个元素作为基准值,这个值称为“pivot”。选择的方法可以多样,如选择第一个元素、最后一个元素、中间元素或随机元素。

  2. 分区操作
    数组被分为两个部分,使得:

    • 左边部分的所有元素都不大于基准值,
    • 右边部分的所有元素都不小于基准值。

    此时,基准值处于整个数组中的最终位置。

  3. 递归排序
    递归地对基准左侧和右侧的两个子数组进行快速排序,直到子数组的长度为1或0,此时数组已经完全排序。

快速排序主要有两种实现方式,分别是递归方式和迭代方式。

下面我们首先来看一下递归方式实现的快速排序的代码:

Python代码实现(递归版本):

以下是快速排序的一个简单Python实现,其中使用了Lomuto分区方案:

def quick_sort(arr):
    def partition(low, high):
        pivot = arr[high]
        i = low - 1
        for j in range(low, high):
            if arr[j] <= pivot:
                i += 1
                arr[i], arr[j] = arr[j], arr[i]
        arr[i + 1], arr[high] = arr[high], arr[i + 1]
        return i + 1

    def quick_sort_recursive(low, high):
        if low < high:
            pi = partition(low, high)
            quick_sort_recursive(low, pi - 1)
            quick_sort_recursive(pi + 1, high)

    quick_sort_recursive(0, len(arr) - 1)
    return arr

# 测试用例
test_cases = [
    [10, 7, 8, 9, 1, 5],
    [1, 2, 3, 4, 5],
    [5, 4, 3, 2, 1],
    [],
    [1],
    [11, 11, 11, 11]
]

# 展示排序结果
for case in test_cases:
    print(f"Original: {case}")
    print(f"Sorted: {quick_sort(case)}\n")

# 代码运行结果
Original: [10, 7, 8, 9, 1, 5]
Sorted: [1, 5, 7, 8, 9, 10]

Original: [1, 2, 3, 4, 5]
Sorted: [1, 2, 3, 4, 5]

Original: [5, 4, 3, 2, 1]
Sorted: [1, 2, 3, 4, 5]

Original: []
Sorted: []

Original: [1]
Sorted: [1]

Original: [11, 11, 11, 11]
Sorted: [11, 11, 11, 11]

测试用例及其输出:

上面的代码对包含多种情况的测试用例进行了排序,包括:

  • 普通未排序数组,
  • 已排序数组,
  • 逆序数组,
  • 空数组,
  • 单元素数组,
  • 所有元素相同的数组。

这些测试用例涵盖了快速排序可能面临的一些典型情况,并显示了算法处理这些情况的能力。每个测试用例的输出将展示原始数组和排序后的数组,以验证排序过程的正确性。

非递归(迭代)版本的快速排序可以使用一个显式的栈来模拟递归过程。这种方法避免了递归可能带来的栈溢出问题,并直观地展示了算法的控制流程。下面是如何使用栈实现快速排序的迭代版本:

Python代码实现(迭代版本):

def quick_sort_iterative(arr):
    if arr == []:
        return arr
    # 创建一个栈
    stack = []
    # 初始范围从0到数组长度减一
    stack.append(0)
    stack.append(len(arr) - 1)

    # 只要栈非空,就继续运行
    while stack:
        # 弹出 high 和 low
        high = stack.pop()
        low = stack.pop()

        # 使用Lomuto分区方案
        pivot = arr[high]
        i = low - 1
        for j in range(low, high):
            if arr[j] <= pivot:
                i += 1
                arr[i], arr[j] = arr[j], arr[i]
        # 交换pivot到正确位置
        i += 1
        arr[i], arr[high] = arr[high], arr[i]
        pi = i

        # 如果有左子数组,将其范围入栈
        if pi - 1 > low:
            stack.append(low)
            stack.append(pi - 1)
        
        # 如果有右子数组,将其范围入栈
        if pi + 1 < high:
            stack.append(pi + 1)
            stack.append(high)

    return arr

# 测试用例
test_cases = [
    [10, 7, 8, 9, 1, 5],
    [1, 2, 3, 4, 5],
    [5, 4, 3, 2, 1],
    [],
    [1],
    [11, 11, 11, 11]
]

# 展示排序结果
for case in test_cases:
    print(f"Original: {case}")
    print(f"Sorted: {quick_sort_iterative(case)}\n")

# 代码运行结果
Original: [10, 7, 8, 9, 1, 5]
Sorted: [1, 5, 7, 8, 9, 10]

Original: [1, 2, 3, 4, 5]
Sorted: [1, 2, 3, 4, 5]

Original: [5, 4, 3, 2, 1]
Sorted: [1, 2, 3, 4, 5]

Original: []
Sorted: []

Original: [1]
Sorted: [1]

Original: [11, 11, 11, 11]
Sorted: [11, 11, 11, 11]

在迭代版本的快速排序中,我们使用了栈来保存将要处理的子数组的索引。这种方法模拟了递归调用栈的行为:

  • 首先,将整个数组的起始和结束索引推入栈中。
  • 然后,使用一个循环,直到栈为空,在每次迭代中:
    • 从栈中弹出一个子数组的界限(highlow)。
    • 执行分区操作,确定 pivot 的最终位置。
    • 根据 pivot 的位置,决定是否将左子数组或右子数组的索引范围推回栈中。

这种迭代方法避免了递归的深度调用,特别是对于那些可能导致递归深度很深的大数组来说,是一个更稳定的选择。

迭代版本的快速排序在时间复杂度和空间复杂度上的表现与递归版本相似,但有一些关键的实现细节差异:

时间复杂度

  • 最佳和平均情况:对于平均分布的数据,快速排序的时间复杂度通常是 O ( n log ⁡ n ) O(n \log n) O(nlogn)。这是因为每次分区大约将数组分成两半,需要递归或迭代地应用这一过程大约 log ⁡ n \log n logn 次。
  • 最坏情况:在最坏的情况下,如果每次选择的基准都是最小或最大的元素,快速排序的时间复杂度会退化到 O ( n 2 ) O(n^2) O(n2)。这种情况在数组已经基本有序的情况下可能发生(完全正序或完全逆序),每次分区操作只能减少一个元素。

空间复杂度

  • 递归版本:递归版本的快速排序在最坏情况下的空间复杂度可以达到 O ( n ) O(n) O(n),这是由递归调用栈深度决定的。在平均情况下,由于递归的深度接近 log ⁡ n \log n logn,其空间复杂度是 O ( log ⁡ n ) O(\log n) O(logn)
  • 迭代版本:迭代版本使用一个显式的栈来存储未处理的子数组的界限。虽然这避免了函数调用的开销,但栈的空间使用仍然可以在最坏情况下达到 O ( n ) O(n) O(n),特别是当数组几乎有序时,可能需要将许多小的子数组范围推入栈。在平均情况下,空间复杂度通常也是 O ( log ⁡ n ) O(\log n) O(logn),因为每次都将数组大致分成两部分。

稳定性

  • 不稳定排序:相等的元素可能由于分区而交换其原始顺序。

实用性和选择

尽管迭代版本避免了递归的潜在栈溢出问题,它在空间和时间上的复杂度与递归版本相似。选择递归还是迭代版本通常取决于具体的应用场景以及对栈溢出的考虑。迭代版本更适合于那些对栈空间使用有严格限制的环境,例如嵌入式系统或者非常大的数据集处理。

在实际应用中,可以通过随机选择基准值或使用“三数取中”法来选择基准值,以避免最坏情况的发生,从而使得快速排序的性能更加稳定。此外,对于小数组,可以切换到插入排序以提高效率,因为小数组上的插入排序可能比快速排序更快。这种组合策略在实际库中如C++的STL中被广泛应用。

开放性问题

Rocky从工业界、应用界、竞赛界以及学术界角度出发,思考总结AI行业的一些开放性问题,这些问题不仅能够用于面试官的提问,也可以用作面试者的提问,在面试的最后阶段让大家进入更深刻的探讨与交流。

与此同时,这些开放性问题也是贯穿我们职业生涯的本质问题,需要我们持续的思考感悟。这些问题没有标准答案,Rocky相信大家心中都有自己对于AI行业的认知与判断,欢迎大家在留言区分享与评论。

1、AIGC时代的ToC产品开发流程是什么样的?

这是一个很好的问题,AIGC时代的ToC产品和移动互联网时代的ToC产品有很多相似的地方,我们可以借鉴一下:

  1. 需求分析和规划:明确应用功能,目标受众,进行市场调研;确定技术栈和开发方法。
  2. 设计阶段:用户界面和用户体验设计;系统架构设计。
  3. 开发阶段:AIGC算法的开发和集成;前端和后端的开发。
  4. 测试阶段:功能测试、性能测试、压力测试、用户接受度测试等。
  5. 部署和上线:应用程序的部署;线上用户的测试使用。
  6. 维护和迭代:根据用户反馈进行优化迭代;定期版本更新与维护。

2、AIGC时代有哪些可以落地的技术方向?

Rocky认为,目前来看有六个方向可以说是在AIGC时代有非常强的势能与落地前景:

  1. AI绘画
  2. AI视频
  3. 大模型
  4. AI多模态
  5. 数字人
  6. AI音频

推荐阅读

1、加入AIGCmagic社区知识星球

AIGCmagic社区知识星球不同于市面上其他的AI知识星球,AIGCmagic社区知识星球是国内首个以AIGC全栈技术与商业变现为主线的学习交流平台,涉及AI绘画、AI视频、ChatGPT等大模型、AI多模态、数字人、全行业AIGC赋能等50+应用方向,内部包含海量学习资源、专业问答、前沿资讯、内推招聘、AIGC模型、AIGC数据集和源码等

那该如何加入星球呢?很简单,我们只需要扫下方的二维码即可。知识星球原价:299元/年,前200名限量活动价,终身优惠只需199元/年。大家只需要扫描下面的星球优惠卷即可享受初始居民的最大优惠:

2、Stable Diffusion XL核心基础知识,从0到1搭建使用Stable Diffusion XL进行AI绘画,从0到1上手使用Stable Diffusion XL训练自己的AI绘画模型,AI绘画领域的未来发展等全维度解析文章正式发布

码字不易,欢迎大家多多点赞:

Stable Diffusion XL文章地址:https://zhuanlan.zhihu.com/p/643420260

3、Stable DiffusionV1-V2核心原理,核心基础知识,网络结构,经典应用场景,从0到1搭建使用Stable Diffusion进行AI绘画,从0到1上手使用Stable Diffusion训练自己的AI绘画模型,Stable Diffusion性能优化等全维度解析文章正式发布

码字不易,欢迎大家多多点赞:

Stable Diffusion文章地址:https://zhuanlan.zhihu.com/p/632809634

4、ControlNet核心基础知识,核心网络结构,从0到1使用ControlNet进行AI绘画,从0到1上手构建ControlNet高级应用等全维度解析文章正式发布

码字不易,欢迎大家多多点赞:

ControlNet文章地址:https://zhuanlan.zhihu.com/p/660924126

5、LoRA系列模型核心基础知识,从0到1使用LoRA模型进行AI绘画,从0到1上手训练自己的LoRA模型,LoRA变体模型介绍,优质LoRA推荐等全维度解析文章正式发布

码字不易,欢迎大家多多点赞:

LoRA文章地址:https://zhuanlan.zhihu.com/p/639229126

6、最全面的AIGC面经《手把手教你成为AIGC算法工程师,斩获AIGC算法offer!(2024年版)》文章正式发布

码字不易,欢迎大家多多点赞:

AIGC面经文章地址:https://zhuanlan.zhihu.com/p/651076114

7、10万字大汇总《“三年面试五年模拟”之算法工程师的求职面试“独孤九剑”秘籍》文章正式发布

码字不易,欢迎大家多多点赞:

算法工程师三年面试五年模拟文章地址:https://zhuanlan.zhihu.com/p/545374303

《三年面试五年模拟》github项目地址(希望大家能给个star):https://github.com/WeThinkIn/Interview-for-Algorithm-Engineer

8、Stable Diffusion WebUI、ComfyUI、Fooocus三大主流AI绘画框架核心知识,从0到1搭建AI绘画框架,从0到1使用AI绘画框架的保姆级教程,深入浅出介绍AI绘画框架的各模块功能,深入浅出介绍AI绘画框架的高阶用法等全维度解析文章正式发布

码字不易,欢迎大家多多点赞:

AI绘画框架文章地址:https://zhuanlan.zhihu.com/p/673439761

9、其他

Rocky将YOLOv1-v7全系列大解析文章也制作成相应的pdf版本,大家可以关注公众号WeThinkIn,并在后台 【精华干货】菜单或者回复关键词“YOLO” 进行取用。

Rocky一直在运营技术交流群(WeThinkIn-技术交流群),这个群的初心主要聚焦于技术话题的讨论与学习,包括但不限于算法,开发,竞赛,科研以及工作求职等。群里有很多人工智能行业的大牛,欢迎大家入群一起学习交流~(请添加小助手微信Jarvis8866,拉你进群~)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/648408.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

引入安全生产培训云平台,实现“人人讲安全、个个会应急”

引入安全生产培训云平台&#xff0c;旨在全面提升企业及员工的安全意识与应急处理能力&#xff0c;通过数字化手段实现“人人讲安全、个个会应急”的目标。这一平台的构建和应用&#xff0c;不仅促进了安全知识的普及&#xff0c;还极大提高了培训的效率与效果。以下是该平台几…

Backend - postgresSQL DB 存储过程(数据库存储过程)

目录 一、存储过程的特性 &#xff08;一&#xff09;作用 &#xff08;二&#xff09;特点 &#xff08;三&#xff09;编码结构的区别 二、定时执行存储过程 三、2种编码结构 &#xff08;一&#xff09;函数结构 1. SQL代码 2. 举例 &#xff08;1&#xff09;例1-循…

邦之信短信分析:验证码短信、营销短信与通知短信的差异化解析

在数字通讯时代&#xff0c;短信已成为我们日常生活中不可或缺的一部分。其中&#xff0c;验证码短信、营销短信和通知短信各自扮演着不同的角色。今天&#xff0c;飞鸽将带您深入了解这三种短信类型之间的核心差异。 1. 验证码短信 验证码短信广泛应用于各类电商网站和…

【UE5.1 角色练习】07-AOE技能

目录 效果 步骤 一、准备技能动画 二、准备粒子特效 三、技能蓝图 四、相机震动 前言 在上一篇&#xff08;【UE5.1 角色练习】06-角色发射火球-part2&#xff09;基础上继续实现角色释放AOE技能的功能。 效果 步骤 一、准备技能动画 1. 在项目设置中添加一个操作映…

如何恢复已删除/丢失的照片/视频?

“嗨&#xff0c;我把我所有的世界杯照片和视频都存储在我的数码相机存储卡上。但是&#xff0c;当我将存储卡与计算机连接时&#xff0c;它会要求我格式化存储卡。我格式化了存储卡&#xff0c;但我所有的世界杯照片和视频都不见了。这对我来说是一场大灾难。是否有可能恢复丢…

[图解]产品经理创新模式01物流变成信息流

1 00:00:01,570 --> 00:00:04,120 有了现状的业务序列图 2 00:00:04,960 --> 00:00:08,490 我们就来改进我们的业务序列图了 3 00:00:08,580 --> 00:00:11,010 把我们要做的系统放进去&#xff0c;改进它 4 00:00:13,470 --> 00:00:15,260 怎么改进&#xff1f;…

【MATLAB】信号的熵

近似熵、样本熵、模糊熵、排列熵|、功率谱熵、奇异谱熵、能量熵、包络熵 代码内容&#xff1a; 获取代码请关注MATLAB科研小白的个人公众号&#xff08;即文章下方二维码&#xff09;&#xff0c;并回复信号的熵本公众号致力于解决找代码难&#xff0c;写代码怵。各位有什么急需…

Pytorch DDP分布式细节分享

自动微分和autograde 自动微分 机器学习/深度学习关键部分之一&#xff1a;反向传播&#xff0c;通过计算微分更新参数值。 自动微分的精髓在于它发现了微分计算的本质&#xff1a;微分计算就是一系列有限的可微算子的组合。 自动微分以链式法则为基础&#xff0c;依据运算逻…

Tomcat源码解析(七):底层如何获取请求url、请求头、json数据?

Tomcat源码系列文章 Tomcat源码解析(一)&#xff1a;Tomcat整体架构 Tomcat源码解析(二)&#xff1a;Bootstrap和Catalina Tomcat源码解析(三)&#xff1a;LifeCycle生命周期管理 Tomcat源码解析(四)&#xff1a;StandardServer和StandardService Tomcat源码解析(五)&…

知攻善防应急响应靶机训练-Web3

前言 本次应急响应靶机采用的是知攻善防实验室的Web-3应急响应靶机 靶机下载地址为&#xff1a; https://pan.quark.cn/s/4b6dffd0c51a 相关账户密码 用户:administrator 密码:xj123456xj123456 解题过程 第一题-攻击者的两个IP地址 直接查看apache的log日志搜索.php 发现…

学习Uni-app开发小程序Day26

这一章学习的内容细节较多&#xff0c;主要是分为&#xff1a;首次加载减少网络消耗、获取图片的详细信息、图片的评分和避免重复评分、将图片下载到本地并且获取设备的授权 加载图片减少网络消耗 这里突出这个功能&#xff0c;是根据老师视频上的描述&#xff0c;个人觉得很…

Spark介绍

Spark简介 Spark,是一种通用的大数据计算框架,正如传统大数据技术Hadoop的MapReduce、Hive引擎,以及Storm流式实时计算引擎等. Spark是加州大学伯克利分校AMP实验室(Algorithms Machines and People Lab)开发的通用内存并行计算框架,用于构建大型的、低延迟的数据分析应用程序…

Python图像处理库全面详细解析

目录 引言 PIL和Pillow&#xff1a;基础但强大的图像处理 PIL到Pillow的演变 功能亮点 实际应用案例 Pillow的适用场景 结论 ​编辑 OpenCV&#xff1a;计算机视觉的瑞士军刀 OpenCV的核心特点 功能亮点 实际应用案例 OpenCV的适用场景 结论 ​编辑 Scikit-Imag…

pytest:指定测试用例执行顺序

在自动化测试中&#xff0c;测试用例的执行顺序有时对测试结果具有重要影响。本文将介绍如何在pytest框架中使用pytest-ordering插件以及Collection hooks来控制测试用例的执行顺序。 方式1&#xff1a; 使用pytest-ordering插件控制执行顺序 1.1 安装pytest-ordering插件 首…

Python编程的黑暗魔法:模块与包的神秘力量!

哈喽&#xff0c;我是阿佑&#xff0c;今天给大家讲讲模块与包~ 文章目录 1. 引言1.1 模块化编程的意义1.2 Python中模块与包的概念概述 2. 背景介绍2.1 Python模块系统模块的定义与作用Python标准库简介 2.2 包的结构与目的包的定义与目录结构包在项目组织中的重要性 3. 创建与…

用three.js+echarts给公司写了一个站点数据大屏系统经验总结

时间过的好快,参加公司的新项目研发快一年了,五一机器人项目首秀,我们遇到了高并发集中下单情景,然后海量数据处理场景来了,给我在后端领域的高并发实践业务上画上了漂亮的一笔经验。人都是在磨练中成长,我很感谢这次给我的机会,虽然有点累,但也有点小成就。正好现在有…

基于RK3568核心板的雷视融合一体机,助力交通管理智能化升级

随着5G网络与智慧交通车路协同系统在全国各点的落地&#xff0c;作为提升交通安全的前沿技术方案也愈发受到重视。 在交通信控领域&#xff0c;以往的感知技术、无论是地磁、线圈还是摄像头&#xff0c;功能都仅仅局限于数清经过了多少车辆&#xff0c;无法满足交通数字化管理…

aosp14的分屏接口ISplitScreen接口获取方式更新-学员疑问答疑

背景&#xff1a; 有学员朋友在学习马哥的分屏pip自由窗口专题时候&#xff0c;做相关分屏做小桌面项目时候&#xff0c;因为原来课程版本是基于android 13进行的讲解的&#xff0c;但是现在公司已经开始逐渐进行相关的android 14的适配了&#xff0c;但是android 14这块相比a…

挖矿宝藏之系统日志

什么是日志&#xff1f; 日志是指系统或应用程序在运行过程中产生的记录文件&#xff0c;这些文件记录了系统或应用程序的运行情况、错误信息、用户操作等。 日志的主要作用 记录信息&#xff1a;日志可以记录系统或应用程序的启动、运行、停止等状态信息&#xff0c;以及用户的…

sourcetree推送到git上面

官网&#xff1a;Sourcetree | Free Git GUI for Mac and Windows 下载到1次提交 下载后打开 点击跳过 下一步 名字邮箱 点击clone 把自己要上传的代码粘贴到里面去 返回点击远程->点击暂存所有 加载完毕后&#xff0c;输入提交内容提交 提交完成了 2次提交 把文件夹内的…