算法基础一
Posted DennisJu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法基础一相关的知识,希望对你有一定的参考价值。
背景
- 刷算法题的时候,算法类无论怎样出题大面上的操作都是对基本数据结构的操作,衡量这些操作优劣的标准则通过时间和空间两个方面的“复杂度”去衡量,所以在这里觉得有必要补充一下算法基础的文章。
- 不要把这里的时间和空间简单的理解为我们现实中的程序的执行时长和运行时占用的内存空间,衡量算法的优劣不是在哪一个机器哪种语言那个编译器平台上运行的速度快慢,而是在一种相对宏观的维度,去将耗时操作的执行次数无限放大得出的的,也就是考虑程序执行时最糟糕的情况下我们需要多长时间多少资源才能得出想要的结果。
- 一方面我们从纯理论角度,通常我们用最差时间和空间复杂度来衡量,但根据循环次数我们也会选择其他标准(例如平均时间复杂度)来权衡技术的选择,但大部分情况最合适的还是用最差复杂度的标准来衡量更通用程序更健壮。
- 另一方面,结合实际使用场景,时间和空间复杂度往往是冲突的,相比常听说以时间换空间,以空间换时间这类说法,但只要知道了其中原理任何情景都可以找到合适的解决方案。要是资源允许我比较偏向于空间换时间的做法,毕竟千金难买寸光阴,time更宝贵不是嘛。实际情况是如果你玩个游戏卡一秒钟估计你就回泉水了这谁顶得住,坚决不能让时间过长成为效率拉胯的原因哈哈。
核心内容
- 大O符号表示法:定义为T[n] = O(f(n)),原因就是上面所说,因为硬件资源配置,编译器软件等等因素不尽相同所以,需要一个宏观的测量方法来评估算法的优劣。
- 时间复杂度:
- 基于上面大O符号表示法的描述,将程序执行时间与执行次数n的关系结合,假设执行一次是1s执行n次那便是n秒,如果是n的幂次方次那就是n的幂次方秒,此类情况常见于我们写的for循环中,下面会举例说明。
- 需要注意的一个点,如果你的程序执行跟n没有关系,那他的复杂度就是O(1),即使你有成千上万行代码,例如你写了10w行i = 1;它的执行时间哪怕是半个小时,它的时间复杂度也是O(1), 因为他是有限可数的,所以这里的循环执行n次是理解时间复杂度的核心关键。
- 空间复杂度:
- 临时占用的存储空间情况,跟时间复杂度的理解方式一样,关键看跟n有没有关系,这里就不过多阐述了。
- 基础数据结构(这里只简单罗列后续再补充吧)
- 数组:一组类型相同且连续的存储空间,分配内存的时候给定size往往效率更高,从复杂度的维度上,对遍历查询操作友好,对删除和插入操作没有链表友好。
- 链表:一般是非连续的即使凑巧分配的内存部分有连续的你也无法想数组那样去操作它,从复杂度维度上,对遍历查询没有数组友好,对删除和插入操作友好。
- 堆栈:先进后出,FIFO,类似于往箱子里放衣服,要拿到箱底的衣服要把上面的先取出来,都可以用数组和链表构建,所以熟悉数组和链表基本操作,怎么使用堆栈不在话下,常见,单向链表,双向链表,循环链表
- 队列:先进先出,跟超市排队一个道理,但是不允许插队,希望超市里面你排队的时候也能有这种正义感。
- 图(规划单独章节补充)
- 树(规划单独章节描述补充)
复杂度和大O符号表示法
在n无限大的时候,算法执行效率自上往下依次降低。
- 常熟阶-例如:i = 3;
- 对数阶-例如:for循环中变量i在循环过程中以倍数自增,例如:i * 2;
- 线性阶-例如:一层常规for循环,i以++i的方式自增
- 线性对数阶- 例如两层for循环是对数阶和线性阶情况的合体
- 平方阶,三次方阶,K次方阶-例如2、3、k层for循环,i以++i的方式自增
- 指数阶(爆炸函数,如果你的算法是这样的,不仅你的领导会爆炸,你的代码也会,这些爆炸了那你也就跟着去了,但是也有些例外,例如递归函数,但也要慎用,或者尽量用尾递归)
第二篇内容规划
- 常用的排序和查找方法
本文算是笔者本人比较通俗的理解,如有笔误欢迎沟通讨论哦。
以上是关于算法基础一的主要内容,如果未能解决你的问题,请参考以下文章