当前位置: 首页 > news >正文

算法知识笔记

=========================== 第一章 算法简介 ==========================

大O表示法表示了最糟糕情况下的操作次数(运行时间)

O(log n) 对数时间  包括 二分查找(省略了2的底数)

O(n)        线性时间            简单查找

O(n * log n)                      快速排序 (速度较快)

O(n^2)                            选择排序 (速度较慢)

O(n!)                                旅行商的解决方案(非常慢)

========================= 第二章 选择排序 ============================

算法的速度并非时间,而是操作数的增速

数组

链表

读取

O(1)

O(n)

插入

O(n)

O(1)

删除

O(n)

O(1)

======================== 第三章 递归 ===============================

递归只是让解决方案更清晰, 并没有性能上的优势, 实际上在某些情况下使用 while 循环的性能更好.

(如果使用循环 程序的性能会更高, 如果使用递归,程序可能更容易理解)

出处:performance - Recursion or Iteration? - Stack Overflow https://stackoverflow.com/questions/72209/recursion-or-iteration/72694#72694

编写递归函数需要注意两点:基线条件和递归条件 告诉它何时停止.

递归条件是指:函数调用自己 

基线条件是指: 函数不再调用自己(避免形成无限循环)

栈:调用栈(call stack) 调用栈不仅对编程很重要,使用递归也必须理解

计算机在内部使用被称为 调用栈 的 栈。 如果一个栈被用来存储多个函数的变量 被称为调用栈。

虽然栈很方便但是存储详尽的信息会占用大量的内存,每个函数调用都会占用内存,如果栈很高,意味着计算机存储了大量的函数调用的信息,这种情况下: (1)重新编写代码 转而使用循环   (2)使用 尾递归 (高级递归主题)

总结:

      每个递归都有两个条件: 基线条件 和 递归条件

      栈有两种操作: 压入 和 弹出

      所有函数调用 都进入调用栈

      调用栈 可能很长 将占用大量内存

======================= 第四章 快速排序 =========================

快速排序(一种优雅的排序算法)使用 分而治之 (divide and conquer D&C)的策略,分而治之是递归的。

使用 D&C 解决问题需要两个步骤:

     (1)、找出基线条件, 这种条件必须尽可能简单

     (2)、 不断将问题分解(缩小规模), 直到符合基线条件。

====================== 第五章: 散列表 ==========================

散列函数: 即无论给它什么数据, 都还你一个数字(将输入映射到数字)

散列函数必须满足一些要求:

    输出一致: 即输入相同时候, 输出必须一致

    应将不同的输入映射到不同的数字(映射到不同的索引) # (防止冲突)

散列函数知道数组有多大,只返回有效的索引,如果数组包含5个元素就不会返回无效索引100.

python 提供的 散列表 实现为 字典。

用途:

    (1) 将散列表用于查找——电话簿

    (2) 防止重复

    (3) 用作缓存

缓存是一种常用的加速方式, 所有大型网站都使用缓存,而缓存的数据则存储在散列表中。

总结:

散列表适用于:

    模拟映射关系

    防止重复

    缓存/记住数据

冲突:

    散列函数总是将不同的键映射到数组的不同位置,但是实际上不可能编写出这样的散列函数。

解决办法:  

    冲突很糟糕必须要避免,最简单的办法是: 如果两个键映射到了同一个位置,就在这个位置存储一个链表。(但是链表不能太长,否则效果也不好)

经验教训:

    散列函数很重要:前面的散列函数将所有的键都映射到了一个位置, 而最理想的情况是散列函数将键均匀的映射到散列表的不同位置。

    如果散列表存储的链表很长,散列表的速度将急剧下降,然而 如果使用的散列函数好, 这些链表就不会很长。

散列函数很重要,好的散列函数很少导致冲突。

散列表(平均情况)

散列表(最糟情况)

数组

         链表

查找

O(1)

O(n)

O(1)

         O(n)

            插入

            O(1)

O(n)

O(n)

         O(1)

删除

O(1)

O(n)

O(n)

         O(1)

在平均情况下,散列表的查找(获取给定索引处的值)速度与数组一样快,而插入和删除速度与链表一样快,因此兼具两者的优点,在最糟糕情况下散列表各种操作的速度都很慢, 因此:

    使用散列函数时避开最糟糕的情况很重要

        (1)较低的填装因子

        (2)良好的散列函数

填装因子 = 散列表包含的元素数 / 位置总数(分配的位置总数)

散列表使用数组来存储数据。

良好的散列函数让数组中的值呈均匀分布。(SHA函数)

总结:

    散列表示一种功能强大的数据结构,操作速度快,还能以不同的方式建立数据模型。

    可以结合散列函数和数组来创建自己的散列表

    冲突很糟糕,应该使用可以最大限度的减少冲突的散列函数

    散列表适用于模拟映射关系

    一旦填装因子超过 0.7 就该扩充散列表的长度了。

    散列表可以用于缓存数据(web服务器上)

    散列表非常适合用于防止重复

======================= 第六章:广度优先搜索 ======================

解决最短路径问题的算法称为 广度优先搜索。

如果确定从一个地方到另一个地方的最短路径:

(1) 使用图建立问题模型

(2) 使用广度优先搜索解决问题

广度优先搜索的执行过程: 搜索范围从起点开始向外延伸, 即先检查一度关系,再检查二度关系..

队列是一种 先进先出(FIFO)的数据结构

栈是一种 后进先出 (LIFO)的数据结构

更新队列时, 使用术语: 入队 和 出队 (压入, 弹出)

======================= 第七章 狄克斯特拉算法 ======================

狄克斯特拉算法主要包含4步骤:

(1) 找出开销最小的节点,并认为此节点已经被处理过(以防止负权边的形成,狄克斯特拉算法不支持负权边)

(2) 对于找出的最小开销节点的邻居节点,并检查是否有前往它们的更短路径,如果有就更新到其的开销

(3) 重复这个过程直到对图中的所有节点这样检查过了

(4) 计算最终路径

要计算非加权图中的最短路径可使用 广度优先算法, 要计算加权图中的最短路径可使用狄克斯特拉算法。

在无向图中, 每条边都是一个环, 狄克斯特拉算法只适用于有向无环图。

总结:

    广度优先搜索用于在非加权图中查找最短路径

    狄克斯特拉算法用于在加权图中查找最短路径

    仅当权重为正时狄克斯特拉算法才有用

    如果图中有负权边, 使用 贝尔曼-福德算法

====================== 第八章:贪婪算法 =========================

贪婪算法:

    简单易行:每一步都采用最优的做法,(n个局部最优解合起来也是全局最优解)

教室调度问题可以使用 贪婪算法, 但是背包问题就不行了,还要考虑其价值因素。

    

近似算法:

    在获得精确解需要很长时间时,可使用近似算法。

    判断近似算法优劣的标准:

        (1) 速度有多快

        (2) 得到的近似解与最优解的接近程度

NP完全问题:

     旅行商和集合覆盖问题有一些共同之处:就是需要计算所有的解, 并从中选出最小/最短的那个, 这两个问题都属于 NP 完全问题。

     

NP 完全问题的简单定义是, 以难解著称的问题, 如旅行商和集合覆盖问题, 很多非常聪明的人都认为, 根本不可能编写出可快速解决这些问题的算法。

判断一个问题是否是 NP 完全问题:

(1)、 元素较少时算法的运行速度很快,但是随着元素数量的增加,速度会越来越慢。

(2)、 涉及“所有组合” 的问题通常是 NP完全问题。

(3)、 不能将问题分成小问题, 必须考虑各种可能的情况, 这可能就是 NP完全问题。

(4)、 如果问题涉及序列(如旅行商问题中的城市序列)且难以解决,它可能就是 NP完全问题。

(5)、 如果问题涉及集合(如广播台集合)且难以解决, 可能就是NP完全问题

(6)、 如果问题可转换为集合覆盖问题或旅行商问题, 肯定是 NP完全问题。

小结:

(1)、 贪婪算法寻找局部最优解, 企图以这种方式获得全局最优解

(2)、 对于 NP完全问题, 还没有找到快速解决方案

(3)、 面临 NP完全问题时, 最佳做法是使用 近似算法

(4)、 贪婪算法易于实现, 运行速度快, 是不错的近似算法。

====================== 第九章: 动态规划 =====================

背包问题:...

动态规划: 先解决子问题, 再逐步解决大问题。

动态规划功能强大, 能够解决子问题并使用这些答案来解决大问题, 但仅当每个子问题都是离散的, 即不依赖于其他子问题时,动态规划才管用。

计算最终的解时会涉及两个以上的子背包吗?

     为获得背包问题的最优解, 可能需要两件以上的商品, 但是根据动态规划算法的设计,最多只需合并两个子背包, 不过子背包可能包含子背包。

最长公共字串:

     在问题可分解为彼此独立且离散的子问题时, 就可使用动态规划来解决。

example: git diff 等比较两个文件的差异也是使用动态规划实现的。

小结:

     (1)、 需要在给定约束条件下优化某种指标时, 动态规划很有用。

     (2)、 问题可分解为离散子问题时, 可使用动态规划解决

     (3)、 每种动态规划解决方案都涉及网络

     (4)、 单元格中的值通常就是你要优化的值

     (5)、 ..

====================== 第10章: K最近邻算法 =====================

使用KNN 做两项工作:

(1)、 分类就是编组

(2)、 回归就是预测结果(比如一个数字)

如果在以后算法中使用 KNN 就最好研究一下 余弦相似度, 比如有两个人的口味都差不多,但是评分标准不一样, 一个较为严格,所以对电影评分的时候一个给了 5分 一个却给了三分,  所以这时候为了获取最精确的结果应该使用 余弦相似度来衡量。

OCR的第一步是查看大量的数字图像并提取特征, 被称为训练, 大多数机器学习算法都包含训练的步骤, 要让计算机完成任务必须先训练它。

创建垃圾邮件过滤器:

     垃圾邮件过滤器使用一种简单算法—— 朴素贝叶斯分类器。

小结:

(1)、 KNN用于分类和回归, 需要考虑最近的邻居。

(2)、 分类就是编组。

(3)、 回归就是预测结果(数字)

(4)、 特征抽取意味着将物品转换为一系列可比较的数字

(5)、 能否挑选合适的特征事关KNN算法的成败。

==================== 第十一章: 接下来.. ======================

二叉树:..

B数是一种特殊的二叉树, 数据库常用它来存储数据。

如果对数据库或高级数据结构兴趣可以研究下: 数据结构 B树, 红黑树, 堆, 伸展树。

红黑树是处于平衡状态的特殊二叉查找树。

反向索引: 类似于一个散列表,将单词映射到包含它的页面, 这种数据结构被称为 反向索引, 常用于创建搜索引擎。

傅里叶变换:Better Explained 是一个杰出的网站, 致力于以通俗易懂的语言解释数学。

比如:能告诉我们一杯冰沙含有哪些成分, 给点一首歌曲, 傅里叶变换能够将其中的各种频率分离出来。

傅里叶变换非常合适用于处理信号, 可使用它来压缩音乐。

并行算法:

     为提高算法的速度, 可以让代码在多个内核中并行的执行。

并行算法设计起来很难, 要确保它们能够正确地工作并实现期望的速度提升也很难,有一点是确定的,那就是速度的提升并非线性的, 因此即使笔记本电脑装备了两个而不是一个内核, 算法的速度也不可能提高一倍, 其中的原因有两个:

(1)、 并行性管理开销: 假设对一个对1000个元素的数组排序, 如何在两个内核之间分配这项任务呢, 如果让内核对其中 500个元素进行排序, 再将两个排好序的数组合并成一个有序数组, 那么合并也是需要时间的。

(2)、负载均衡: 假设你需要完成10个任务, 因此你给每个内核都分配5个任务, 但是分配给内核A的任务很容易10秒钟完成了,而内核B却1分钟才能完成,意味着A闲了50秒,而B却忙死忙活,如何均匀的分配任务,让两个内核一样忙呢。

要改善性能和可扩展性, 并行算法是不错的选择。

MapReduce:

     有一种特殊的并行算法很流行, 就是分布式算法, 在并行算法只需要两到四个内核时,完全可以在笔记本电脑上运行它, 但是如果需要数百个内核呢, 在这种情况下,可让算法在多台计算机上运行, MapReduce是一种流行的分布式算法, 可以在流行的开源工具 Apache Hadoop使用它。

分布式算法为何有用?

     假设有一个数据库表,包含数十亿乃至数万亿行, 需要对其执行复杂的SQL查询, 在这种情况下,不能使用MySQL,因为数据表的行数超过数十亿后, 处理起来将很吃力, 相反需要通过 Hadoop来使用 MapReduce。

分布式算法非常适合用于在短时间内完成海量任务, 其中MapReduce基于两个简单的理念:映射(map)和归并(reduce)函数。

映射函数:如 arr1 = [1,2,3]   arr2 = map(lambda x: 2 * x, arr1) 将数组每个元素翻倍。

归并函数: 其理念就是将很多项归并为一项, 映射是将一个数组转换为另一个数组。

MapReduce使用这两个简单概念在多台计算机上执行数据查询, 数据集很大,包含数十亿行时, 使用MapReduce只需几分钟就可获得结果,而传统数据库需要耗费数小时。

布隆过滤器和 HyperLogLog

     给定一个元素,需要判断是否包含在这个集合中,为快速做出判断可使用散列表。 但是当数据量非常大,导致散列表占用大量存储空间的时候,需要另一种创造性的解决方案!

     布隆过滤器: 是一种概率性数据结构, 所以提供的答案有可能不对,但也有可能是正确的,google为了判断某一个网页是否收集过,可不使用散列表而是使用布隆过滤器, 使用散列表时答案绝对可靠, 而是用布隆过滤器时答案可能是正确的。

布隆过滤器的优点就是占用的存储空间很少, 使用散列表时必须存储google搜集过的所有的URL, 但是使用布隆过滤器不用这样做, 布隆过滤器非常适用于不要求答案绝对准确的情况。

HyperLogLog 是一种类似于布隆过滤器的算法, 近似的计算集合中不同的元素数..

面临海量数据只要求答案八九不离十时, 可考虑使用概率型算法。

SHA算法(secure hash algorithm):给定一个字符串,SHA返回其散列值。

可使用 SHA 判断两个文件是否相同。

检查密码: .. 网站一般注册保存的用户的原始密码字符串的散列值, 反向不能计算出原始密码,增强了安全性。

SHA实际上是一系列算法: SHA-0, SHA-1, SHA-2, SHA-3,目前 SHA-0, SHA-1已被发现存在一些缺陷, 当前最安全的密码散列函数是 bcrypt。

SHA是一个局部不敏感的散列算法, 比如 kuing -> adtf03e2..  如果修改了 king -> e34fo7b8..  可以看出再次生成的散列值截然不用,而不是局部有所差别, 因此无法让攻击者通过比较散列值的相似性而破解密码。但是有时候却希望结果相反, 也就是局部敏感, 这种情况下可使用 Simhash, 如果对字符串做细微的修改,Simhash生成的散列值也只存在细微的差别, 这可以通过比较散列值来判断两个字符串的相似程度。

(1)、 google 可使用 simhash 判断网页是否收集

(2)、 论文查重

(3)、 上传核查是否为侵权内容

Diffie-Hellman 密钥交换: 也就是如何对消息加密, 以便只有收件人才能看懂。

Diffie-Hellman 算法解决了两个问题:

(1)、双方无需知道加密算法, 不必协商要使用的加密算法

(2)、要破解加密的消息比登天还难

使用两个密钥, 公钥和私钥, 公钥是公开的,任何人可用来加密消息, 然后传给接收的一方, 而接收方使用只有自己知道的私钥进行解密。

Diffie-Hellman算法以及替代者 RSA依然被广泛应用。

线性规划:

     作者认为线性规划是最酷的算法之一, 所以留到最后讲。

线性规划用于在给定约束条件下最大限度的改善指定的指标。

线性规划使用 Simplex算法..

========================== over  ===========================

http://www.dtcms.com/a/326830.html

相关文章:

  • 学习日志31 python
  • 【C++】STL——priority_queue的使用与底层模拟实现
  • 查看 php 可用版本
  • Nestjs框架: RBAC基于角色的权限控制模型初探
  • STM32TIM定时器
  • 请求报文和响应报文(详细讲解)
  • Wed前端第二次作业
  • C语言增删查改实战:高效管理顺序表
  • docker安装searxng
  • monorepo架构设计方案
  • CICD部署流程详解文档笔记
  • 在 Ubuntu 中docker容器化操作来使用新建的 glibc-2.32
  • [激光原理与应用-244]:设计 - 光学 - CLBO晶体使用一段时间后,输出功率就会下降,原因有哪些?
  • OpenBMC中的snk-psu-manager:架构、原理与应用深度解析
  • 高防IP能为网站防御哪些网络攻击?
  • 从零开始学JAVAWeb-5
  • 腾讯云Edgeone限时免费
  • for循环详解与实战技巧
  • Edit Distance
  • 传统制造业减人不减效:一线用工优化的3个投入方向,用对工具比盲目裁员更关键
  • 对抗样本攻击检测与防御
  • 车载软件架构 --- 车辆量产后怎么刷写Flash Bootloader
  • BLE ADV
  • special topic 9 (2) and 1011(1)division one
  • 深入解析Windows系统下UDP绑定失败的原理与系统级解决方案
  • 数据库三范式入门教程
  • Windows11 PowerShell CMD
  • Ascend DrivingSDK 中的 modulated_deform_conv2d(一)
  • GESP2023年9月认证C++一级( 第三部分编程题(1)买文具)
  • MATLAB实现遗传算法求解路网路由问题