算法学习-时间复杂度

浅浅谈一下这两个概念在生活中所遇到的吧,还是师兄的毕业大论文中,涉及到地理围栏的一个算法,师兄提出了将此算法应用,然后说到这个算法的时间复杂度和空间复杂度是多少多少,这应该是特别有印象接触这两个词语的开始。

到后面我在背前端的面试题的时候,不可避免的涉及到了诸多不同的排序算法,在https://blog.csdn.net/Better_Xing/article/details/114937915这一篇的文章里,我有了一个算是更加深刻的了解吧,但其实还只是一个非常模糊的概念,也不算非常正式的一个学习吧。当我面试航天宏图的时候,面试官问了我冒泡排序和快速排序的时间复杂复杂度分别是多少,我回答对了前者,错了后者,也仅仅是凭着记忆的印象来完成这个问题的回答而已,然后我手写出来了这俩算法,有点巧的是在open with live server的过程中,出了一些小小的问题哈哈,没能解决出来也是我的遗憾了。下面正式学习吧,结束回忆之旅,这该死的爱恨纠葛。

时间复杂度

这里还是借用百度百科的一个定义吧:https://baike.baidu.com/item/%E6%97%B6%E9%97%B4%E5%A4%8D%E6%9D%82%E6%80%A7/5930669?fromtitle=%E6%97%B6%E9%97%B4%E5%A4%8D%E6%9D%82%E5%BA%A6&fromid=1894057&fr=aladdin

时间复杂性,又称时间复杂度算法时间复杂度是一个函数,它定性描述该算法的运行时间。这是一个代表算法输入值的字符串长度的函数。时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数。使用这种方式时,时间复杂度可被称为是渐近的,亦即考察输入值大小趋近无穷时的情况。

这是百度百科中时间复杂度的一个目录,过多的赘述就不了,都是繁杂深奥的一些“正式话语”。 

 时间复杂度是一个函数,这个函数是用来描述算法的运行时间的。在程序员写代码的过程中,时间复杂度是用来方便开发者估算出程序的运行时间的,通常是用算法的操作单元数来代表程序的消耗时间(毕竟不能真的用运用时间来算哈哈,这和自己的电脑的配置应该也是有一些关系的,和运行内存有关系,配置好的电脑跑代码就是快),所以默认CPU的每个单元运行消耗的时间都是一模一样的。假设算法的问题的规模是n(我的理解可能就是算法的最大数据量吧,比如说问一百个人、一千个人、一万个人中男女生有多少,这个人数就是问题的规模),操作单元数量使用函数f(n)来表示,随着n的增大,f(n)自然也会有增长,并和n有一定的关系,这就是算法的渐近时间复杂度,也就是时间复杂度,记为O(f(n))。

大O

大O是算法执行时间的上届,也就是这个问题的解决算法在最差最差的情况下所需要消耗的时间,而数据量和数据的顺序对算法的执行时间有非常非常大的影响。大O可以理解为在输入某个数据的时候,算法运行的时间比输入其他的数据的运算时间都要长,也就是数据里的刺头,最为麻烦的存在。

举个例子吧,插入排序的时间复杂度是O(n^2) ,但是插入排序的时间复杂度和输入数据有很大关系,如果数据是有序的,时间复杂度就会变成O(n),如果数据是倒序的,时间复杂度就是O(n^2) ,最坏的情况就是倒序的情况,但这里我们也得将插入排序的时间复杂度定义为O(n^2) 。

快排的时间复杂度是O(logn),最差的情况是O(n^2) ,但由于业界的默认,还得是前者,不是最差的情况,如果贼有权威的人再发话(可能改成最差的情况也不是不可能哈哈,不过都叫快速排序了怎么也得快一点是吧)。

二分查找(这还是有基础学过的,即定义两个端点,然后取中间,再定义左右的一个端点为中间量,如此反复的定义完直到寻找到最后的结果,不过这是针对有序数组才能够进行二分查找)的时间复杂度是O(logn),每次二分,数据的规模都会减半,直到找到最后的结果,即数据的规模变成1,这就变成了求解2的多少次方等于n的方程求解问题。

分析复杂度的规则:

1.多个时间复杂度相加,如果都和n相关,则取复杂度高的那一个,例如::O(nlogn + n) = O(nlogn),O(nlogn + n^2) = O(n^2)。

2.多个时间复杂度相加,如果其中有些项的复杂度和n不相关则不能忽略任何项,例如:O(AlogA + B),O(AlogA + B^2)。

3.两个循环依次执行,则取时间复杂度高的那个,嵌套多个循环则需要累乘复杂度。

常见的时间复杂度:

O(1)常数复杂度

let n=1

var n=1

const n=1

 O(logn):对数复杂度

//二分查找非递归
var search = function (nums, target) {
  let left = 0,
    right = nums.length - 1;
  while (left <= right) {
    let mid = Math.floor((left + right) / 2);
    if (nums[mid] === target) {
      return mid;
    } else if (target < nums[mid]) {
      right = mid - 1;
    } else {
      left = mid + 1;
    }
  }
  return -1;
};

 O(n):线性时间复杂度

for (let i = 1; i <= n; i++) {
  console.log(i);
}

 O(n^2):平方

for (let i = 1; i <= n; i++) {
  for (let j = 1; j <= n; j++) {
    console.log(i);
  }
}
  
for (let i = 1; i <= n; i++) {
  for (let j = 1; j <= 30; j++) { //嵌套的第二层如果和n无关则不是O(n^2)
    console.log(i);
  }
}

 O(2^n):指数复杂度

for (let i = 1; i <= Math.pow(2, n); i++) {
  console.log(i);
}
//输出从1到2的n次方的数字

 O(n!):阶乘

for (let i = 1; i <= factorial(n); i++) {
  console.log(i);
}

时间复杂度优化:

1. 算法优化:例如1到n求和,可以循环累加,但也可以运用求和公式

2.空间换时间:间是宝贵的,我们计算一个非常耗时的任务,可能要等上很久,突然的断电,或者意外情况可能会导致非常大的损失,空间是廉价的,最多我们购买更大内存的服务器,花钱就可以解决,在后面的章节有非常多的这样的例子,比如用setmap加快查找的速度,用二叉搜索树或者字典树加快字符串的搜索。

时间复杂度案例:

有一个字符串数组,将数组中的每个字符串按照字母排序,然后在将整个字符串数组按照字典顺序排序。求整个操作的时间复杂度。

时间复杂度不是O(n*nlogn + nlogn) = O(n^2logn)

假设最长字符串的长度是s,数组中有n个字符串,对每个字符串排序 O(slogs),将数组中的每个字符串按照字母排序O(n * slogs),将整个字符串数组按字典排序 O(s * nlogn),所以最后的时间复杂度是O(n * slogs) + O(s * nlogn) = O(nslogs + nslogn) = O(ns * (logs+logn))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值