白话算法:时间复杂度和大O表示法
https://www.jianshu.com/p/59d09b9cee58
唐先僧 关注
2017.01.27 11:05* 字数 2209 阅读 4410评论 4喜欢 28赞赏 1

每一个优秀的开发者脑中都有时间概念。他们想给用户更多的时间让用户做他们想做的事情。他们通过最小化时间复杂度来实现这一目的。
在你能理解程序的时间复杂度之前,你需要了解最常使用它的地方:算法设计。
所以究竟什么是算法?
简单来说,算法就是一系列被控制的步骤,你通过按序执行这些步骤可以实现一些目标或者产生一些输出。让我们以你祖母烘烤蛋糕的菜单为例子。等等,这也可以算作算法?当然算!

function 烘烤蛋糕(风味, 加冰){"1. 烤箱预热到350度(华氏)2. 混合面粉、酵母粉、盐3. 打发黄油和糖直到蓬松4. 添加鸡蛋5. 将黄油和鸡蛋混到面粉中6. 添加牛奶和 " + 风味 + "7. 继续搅拌8. 放入盘中9. 烘烤30分钟
10." 如果要 加冰 ,加点冰 "
10. 大快朵颐
"
}
BakeCake('香草味', 要加冰) => 美味

算法在检查时间复杂度时非常有用,因为它可以以各种形态和大小出现。
就犹如你可以用100中不同的方式来切开一个派一样,你可以用多种不同的算法来解决同一个问题。有的解决方法效率更高,比其他的方法需要更少的时间和更少的空间。
所以问题就是:我们怎么分析确认哪一个算法效率最高?
数学!程序的时间复杂度分析仅是一个极其简单的数学方法,这种方法就是分析一个算法对于给定数量的输入需要多长时间来完成任务。这通常定义为大O表示法。
你会问,什么是大 O 表示法?
如果你答应不会放弃并且继续阅读,我会告诉你。
大O表示法就是将算法的所有步骤转换为代数项,然后排除不会对问题的整体复杂度产生较大影响的较低阶常数和系数。
数学家可能会对我的“整体影响”假设有点沮丧,但是开发人员为了节省时间,这种方式更容易简化问题:

规律       Big-O2             O(1)   --> 就是一个常数2n + 10       O(n)   --> n 对整体结果会产生最大影响5n^2         O(n^2) --> n^2 具有最大影响

简而言之,这个例子所要表达的就是:我们只关注表达式中对表达式最终结果会产生最大影响的因子。(当常数非常大而n很小的时候并不是这样的,但是我们现在不要担心这种情况)。
下面是一些常用的时间复杂度以及简单的定义。更完整的定义可以翻阅维基百科。

**O(1)— **常量时间:给定一个大小为n的输入,概算法只需要一步就可以完成任务。
**O(log n)— **对数时间:给定大小为n的输入,该算法每执行一步,它完成任务所需要的步骤数目会以一定的因子减少。
**O(n)— **线性时间:给定大小为n的输入,该算法完成任务所需要的步骤直接和n相关(1对1的关系)。
O(n²)—二次方时间:给定大小为n的输入,完成任务所需要的步骤是n的平方。
**O(C^n)— **指数时间:给定大小为n的输入,完成任务所需要的步骤是一个常数的n次方(非常大的数字)。

有了这些概念,我们一起来看看每一个复杂度完成任务所需要的步骤数:


let n = 16;O (1) = 1 step "(awesome!)"O (log n) = 4 steps "(awesome!)" -- assumed base 2O (n) = 16 steps "(pretty good!)"
O(n^2) = 256 steps "(uhh..we can work with this?)"
O(2^n) = 65,536 steps "(...)"

如你所见,随着算法复杂度的提高,事情的复杂度也会以数量级增长。幸运的是,计算机足够强悍能够相对快速的处理非常复杂的问题。
所以我们怎样使用大O表示法来分析我们的代码?
这里有一些简便的例子向你展示怎么将这些知识运用到已有的或者你自己写的代码。
在我们的例子中将使用如下的数据结构:

var friends = {'Mark' : true,'Amy' : true,'Carl' : false,'Ray' : true,
'Laura' : false,
}
var sortedAges = [22, 24, 27, 29, 31]

O(1)— 常量时间
当你知道key(objects)或者index(arrays)时进行查找只需要一步就可以完成,所用时间就是一个常量。

//If I know the persons name, I only have to take one step to check:function isFriend(name){ //similar to knowing the index in an Array return friends[name];
};
isFriend('Mark') // returns True and only took one step
function add(num1,num2){ // I have two numbers, takes one step to return the valuereturn num1 + num2
}

O (log n)— 对数时间
如果你知道在一个数组的哪一侧进行查找一个指定值时,你可以排除掉另外一半进而节约时间。

//You decrease the amount of work you have to do with each stepfunction thisOld(num, array){var midPoint = Math.floor( array.length /2 );if( array[midPoint] === num) return true;if( array[midPoint] < num ) --> only look at second half of the arrayif( array[midpoint] > num ) --> only look at first half of the array//recursively repeat until you arrive at your solution}
thisOld(29, sortedAges) // returns true
//Notes//There are a bunch of other checks that should go into this example for it to be truly functional, but not necessary for this explanation.//This solution works because our Array is sorted//Recursive solutions are often logarithmic//We'll get into recursion in another post!

###O(n)— 线性时间
你必须通过遍历整个数组(或者list)来完成这一任务。单一for循环的时间复杂度通常都是线性的。此外数组方法比如indexOf的复杂度也是线性的。你不过是使用已经抽象了的循环过程。


//The number of steps you take is directly correlated to the your input size
function addAges(array){
var sum = 0;
for (let i=0 ; i < array.length; i++){ //has to go through each value
sum += array[i]
}
return sum;
}
addAges(sortedAges) //133


O(n²)— 二次方时间
for循环嵌套的复杂度就是二次方的,因为你在一个线性操作里执行另外一个线性操作(或者说: n*n =n² )


//The number of steps you take is your input size squaredfunction addedAges(array){var addedAge = [];for (let i=0 ; i < array.length; i++){ //has to go through each valuefor(let j=i+1 ; j < array.length ; j++){ //and go through them againaddedAge.push(array[i] + array[j]);}}return addedAge;
}
addedAges(sortedAges); //[ 46, 49, 51, 53, 51, 53, 55, 56, 58, 60 ]
//Notes//Nested for loops. If one for loop is linear time (n)//Then two nested for loops are (n * n) or (n^2) Quadratic!

O(2^n)—指数时间
指数复杂度通常出现在这种情况:你对数据了解甚少,但是你必须尝试其所有的排列或者组合。
//The number of steps it takes to accomplish a task is a constant to the n power

//实例

//尝试找出长度为n的密码中所以字符的组合
每当你在编写需要快速运行的代码时都应该做代码时间复杂度分析。
当你有不同的方法来解决一个问题时,比较明智的做法是先实现一个能够工作的解决方案。但是从长远来看,你需要一个尽可能快速且高效的解决方案。
为了帮助你完成解决问题的过程,可以问这些简单的问题:

1、这个可以解决问题吗?是 =>2、你有时间考虑时间复杂度吗是 =>进入第三步
否 =>稍后再回来,现在就跳转到第六步3、它覆盖了所有的边界条件?是 =>
4、我的复杂度已经尽可能低?
否 =>重写或者修改解决方案 -> 回到步骤1
是 =>进入步骤5
5、我的代码D.R.Y(Don't Repeat Yourself) 是 =>
6、欢呼吧!否 =>将代码重构到D.R.Y,然后再欢呼!

在任何(和所有)尝试解决问题的时候都应该进行时间复杂度分析。长此以往将你成为优秀的开发者。你的同事和用户都会因此而喜欢你。
再次说明,作为一个程序员你所面临的绝大多数问题-不管是算法问题还是编程问题-没有几百个也有几十个中解决办法。他们在怎么解决问题的方法上会不一样,但是它们都能解决那个问题。
你可以在使用集合还是图来存储数据之间做出选择。你也可以决定是否在团队项目中使用Angular、React或者Backbone。所有这些解决方案以不同的方式解决同一个问题。
鉴于这一点,很难说某一个答案对于这些问题是“正确的”或者“最好的”。但是可以说对于给定的问题存在“更好”或者“更糟糕”的答案。
就我们前面的一个例子,如果你的团队中一半的人都有使用React的经验,那么使用React是一个更佳的答案,这个方案可以花更少的时间就能搭建起来并运行起来。
描述一个更好的解决方案的能力通常源于一些类似的时间复杂度分析。
简而言之,如果你尝试解决一个问题,那就解决的完美一些。并且使用一些大O表示法来帮助你指出怎么做。
最终总结:

**O(1)— **常数时间:该算法仅仅使用一步就可以完成任务
**O(log n)— **对数时间:该算法每执行一步,它完成任务所需要的步骤数目会以一定的因子减少。
**O(n)— **线性时间:该算法完成任务所需要的步骤直接和n相关(1对1的关系)。
**O(n²)— **二次方时间:完成任务所需要的步骤是n的平方。
**O(C^n)— **指数时间:完成任务所需要的步骤是一个常数的n次方(非常大的数字)。

这里还有一些有用的资源,可以了解更多信息:
维基百科
大O小抄是一个非常棒的资源,它提供了常用的算法时间复杂度,并以图表的形式呈现。

本文译自 Algorithms in plain English: time complexity and Big-O notation

白话算法:时间复杂度和大O表示法相关推荐

  1. 算法时间复杂度的渐近表示法

    基础知识点 一个算法的时间复杂度,指算法运行的时间. 假设数据输入规模是n,算法的复杂度可以表示为f(n)的函数 接受上界不接受下界 大O记号(不唯一)(一般找最邻近它的那个) 假设f(n)和g(n) ...

  2. a*算法的时间复杂度_算法的时间复杂度:大O表示法

    本文讨论一下算法的时间复杂度问题,用到的素材取自<算法图解>一书,强烈推荐, 如有不妥,请联系我! 二分查找 随便想一个1-100的数字. 你的目标是以最少的次数猜到这个数字.你每次猜测后 ...

  3. 算法的时间复杂度(大O表示法)

    首先我们先来看个例子, 我想找个1-100的数字`,你的目标是以最少的次数猜到这个数字.你每次猜测后,我会说小了.大了或对了.下面我们来看下两种简单的方法(方法有很多种),再来引入算法的运行时间!`` ...

  4. 【算法】时间复杂度/运行时间——大O表示法

    对于所有算法,我们都要讨论其运行时间.一般而言,应该选择效率最高的算法,以最大程度地减少运行时间或占用空间. 大O表示法 是一种特殊的表示法,指出了算法的速度有多快.大O表示法 并不能表示具体算法任务 ...

  5. 一文彻底掌握时间复杂度和大O表示法

    预备知识: 计算机基础知识 高中数学知识 时间复杂度用来干嘛 时间复杂度是衡量算法好坏的一个重要指标,另一个重要指标是空间复杂度. 算法 我们先来了解一下算法,对于一个计算机程序,其算法就是其内部执行 ...

  6. 算法与数据结构(part1)--算法简介及大O表示法

    学习笔记,仅供参考 文章目录 算法与数据结构--基于python 数据结构和算法简介 算法引入 例题A 算法的概念 例题A的优化 算法效率的衡量 时间复杂度与大O记法 例题A的时间复杂度 如何理解大O ...

  7. 算法时间复杂度分析——大O、大Ω、大θ、小o,小ω

    最近开始转战传统算法分析的研究工作了,重新拾起以前学过的一些内容. 目录 一.概述 二.对常见的Ο和Ω进行分析 2.1 大O表示法 2.2 大Ω表示法 三.P问题,NP问题,NP-hard问题,NPC ...

  8. 时间复杂度分析-大O表示法

    开篇词 | 从今天起,跨过"数据结构与算法"这道坎 你好,我是王争,毕业于西安交通大学计算机专业.现在回想起来,本科毕业的时候,我的编程水平其实是很差的.直到读研究生的时候,一个师 ...

  9. 算法概念:大O表示法/小o表示法/Ω/Θ

    如果算法A需要的时间与f(n)成正比,则算法A称为f(n)阶,表示为O(f(n)).函数f(n)称为算法的增率函数(growth-rate function).该表示法使用大写字母O来表示(order ...

  10. 2.1 数学基础、大O表示法、洛必达法则相对增长率、T(N) = O( f(N) )、Ω( g(N) )、Ω( h(N) )、o( p(N) )

    2.1 数学基础 ①定义2.1:如果存在正常数 c 和 n0,使得当 N≤cf(N) ,则记为 T(N) = O( f(N) ) 解释:T(N) 的增长率 ≤ f(N) 定义2.2: 如果存在正常数 ...

最新文章

  1. 新生选课系统使用指南
  2. 马斯克,带动大盘的男人:财报一出市值飙升 840 亿!
  3. 常用解决方案技术一览
  4. WPF DataGrid、ListView 简单绑定
  5. Android Studio 从安装到 Hello World
  6. 服务器系统防火墙例外,Windows Server 2012设置端口例外、防火墙设置方法
  7. JPA:确定关系的归属方
  8. 【软件开发底层知识修炼】二十二 ABI-应用程序二进制接口 二
  9. 设计模式(14)-Flyweight Pattern
  10. 计算机与在勘察地质中的应用,地质勘察中计算机信息技术的应用
  11. OMS 订单管理系统
  12. 昆明理工大学计算机面试题,2016年昆明理工大学管理与经济学院F003运筹学复试笔试仿真模拟题...
  13. 2017年5月14日爱奇艺算法比赛
  14. 有哪些 Java 源代码看了后让你收获很多,代码思维和能力有较大的提升?
  15. 什么是计算机内存?它的用途是什么?
  16. contiki学习笔记(四)、contiki系统UDP通信原理(单播、多播、RPL介绍)
  17. w ndows10装什么浏览器,Windows10系统默认启用IE浏览器方法
  18. 禁止 mysql nobody_Warning: mysql_real_escape_string(): Access denied for user 'nobody'@'localhost'
  19. OkHttpClient简单封装
  20. PKU2069 Super Star 点集最小外接球

热门文章

  1. PoEdu - Windows阶段班 【Po学校】Windows编程 Lesson004_003-2 文件操作
  2. 微信JS SDK网页接口
  3. DBA和开发同事的一些代沟(一)
  4. 企业架构:使用TOGAF进行产品开发
  5. MySQL-快速入门(14)MySQL性能优化
  6. 织梦搜索结果增加dede:type、dede:arclist、dede:channelartlist、dede:tag等标签支持
  7. 设计模式(一):代理模式
  8. C++ 第四章 4.1
  9. 插入css样式表的三种方法
  10. 生成[1,2,,3,4,5,6,7,8,9]的随机数组?