时间复杂度

算法核心——空间复杂度和时间复杂度超详细解析

﹥>﹥吖頭↗ 提交于 2019-12-04 10:26:50
算法核心——空间复杂度和时间复杂度超详细解析 一、什么是算法 算法 : 一个有限指令集 接受一些输入(有些情况下不需要收入) 产生输出 一定在有限步骤之后终止 每一条指令必须: 有充分明确的目标,不可以有歧义 计算机能处理的范围之内 描述应不依赖于任何一种计算机语言以及具体的实现手段 其实说白了, 算法 就是 一个计算过程解决问题的方法 。我们现在已经知道 数据结构 表示 数据是怎么存储的 ,而“ 程序 = 数据结构 + 算法 ”,数据结构是 静态 的,算法是 动态 的,它们加起来就是 程序 。 对算法来说 有输入,有输出 ,相当于 函数 有 参数 有 返回值 。我们写算法的时候习惯把算法 封装 到一个函数中。 二、什么是好的算法 好,从上面我们知道了什么是 算法 ,下面我再说什么是 好的算法 ? 在解决同一个问题的时候,我们通常会有很多种不一样的算法,区别就在于,有的算法比较笨,有的算法比较聪明,那我们怎么去衡量它们谁好谁坏呢?我们通常有下面两个指标: 空间复杂度 :根据算法写成的程序在执行时占用存储单元的长度。 时间复杂度 :根据算法写成的程序在执行时耗费时间的长度。 先举个例子说,如果让你打印十个整数,你那个程序可能瞬间就给出结果了,如果让你打印十万个整数呢?这你就得多等一会了。所以这个程序运行的时间,就跟你要处理的数据是十个还是十万个是相关的,这个 十 或 十万

十大经典排序算法(动图演示)

有些话、适合烂在心里 提交于 2019-12-04 09:07:30
十大经典排序算法(动图演示) 0、算法概述 0.1 算法分类 十种常见排序算法可以分为两大类: 比较类排序 :通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。 非比较类排序 :不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。 0.2 算法复杂度 0.3 相关概念 稳定 :如果a原本在b前面,而a=b,排序之后a仍然在b的前面。 不稳定 :如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。 时间复杂度 :对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。 空间复杂度: 是指算法在计算机 内执行时所需存储空间的度量,它也是数据规模n的函数。 1、冒泡排序(Bubble Sort) 冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。 1.1 算法描述 比较相邻的元素。如果第一个比第二个大,就交换它们两个; 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数; 针对所有的元素重复以上的步骤

NOIP2017时间复杂度(大模拟)

核能气质少年 提交于 2019-12-04 08:35:16
传送门 大模拟是真的恶心。 题解我能说啥,就是模拟啊! 然后有几个坑点(可能只是对于我的打法吧) 1.注意数字可能为两位数,在处理出数字的时候注意一下(有18分)。 2.一旦某次循环进不去,接下来嵌套的循环就都是废的,打个标记。还要记录一下是哪一次,退出去的时候把标记去掉。(大概是18分) 3.发现ERR后不要直接return,存个标记,因为后面还有读入。(这个有8分)。 然后是丑陋的代码。 #include<bits/stdc++.h> #define N 103 #define INF 2100000000 #define LL long long using namespace std; int read() { int x=0,f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f; } int T; char s[10]; char op[2],I[2],X[2],Y[2]; int fzd,L; int pre[N];//上次用的是哪个变量 int vis[30];//看这个字母有没有用过 int iss[N];//这重循环是否计入复杂度 void work() {

【学习笔记】OI模板整理

两盒软妹~` 提交于 2019-12-04 04:54:40
CSP2019前夕整理一下模板,顺便供之后使用 1. 数据结构 1.1. 虚树 描述: 给定树上的 \(k\) 个关键点,构建出一棵虚树,只有关键点和任意两个关键点的LCA会被保留,且原树上的祖先关系和虚树上祖先关系保持一致。可以证明虚树最多有 \((2k-1)\) 个点。 把所有关键点按DFS序排序,用一个栈维护动态加点连边即可。时间复杂度 \(O(k\log n)\) . 注意事项: 一定要处理好最先加入栈中的点(所有点的LCA). 代码: addedge0_(u,v) 表示在 \(u\) 和 \(v\) 之间连边,边权根据实际情况确定。 bool cmp(int x,int y) {return dfn[x]<dfn[y];} void build() { sort(ky+1,ky+kyn+1,cmp); rt = ky[1]; for(int i=2; i<=kyn; i++) rt = LCA(rt,ky[i]).first; tp = 1; stk[tp] = rt; n0++; kid[n0] = rt; isky[ky[1]] = true; for(int i=(rt==ky[1]?2:1); i<=kyn; i++) { int u = ky[i],lca = LCA(stk[tp],u).first; if(lca==stk[tp]) {tp++; stk

链表基础知识

↘锁芯ラ 提交于 2019-12-04 01:14:30
链表用途 数据需要经常性地插入移除,并且数据量不算很小的情况下,一般都用链表表示 链表插入删除效率极高,达到O(1)。对于不需要搜索但变动频繁且无法预知数量上限的数据,比如内存池、操作系统的进程管理、网络通信协议栈的trunk管理等等等等,缺了它是绝对玩不转的。 在操作系统中,链表用来分配内存,链接了一串空闲内存。分配容易,释放容易。 楼上有人说了LRU和文件系统,还有一个比较常用的应用是git。 git里面每次commit都是创建一个node,node包含了删减后的新文件,然后node指向前一个commit的node。git checkout、delete branch、merge、rebase这些基本上都是以链表操作为主。git应该算是对linked list很好的应用。不用linked list应该很难高效地实现git提供的功能。 相对于ArrayList,LinkedList插入是更快的。因为LinkedList不像ArrayList,不需要在数组装满的时候要将所有的数据重新装入一个新的数组,这是ArrayList最坏的一种情况,时间复杂度是O(n),而LinkedList中插入或删除的时间复杂度仅为O(1)。ArrayList在插入数据时还需要更新索引(除了插入数组的尾部)。 我觉得在以下场景LinkedList比ArrayList有优势: 1) 你的应用不会随机访问数据

时间复杂度(模拟)

六眼飞鱼酱① 提交于 2019-12-03 20:41:49
满分做法: 不难发现,可以用树形结构递归求解,在此说一些易错点。 1.要用双端队列储存第几个循环。 2.读到E时就队尾,如果已经空了,就是ERR。注意每次要把循环下标清零。 3.当x,y都是n,他是o1的,可以往下搜索。 #include<map> #include<queue> #include<algorithm> #include<cstdio> #include<cstring> #include<iostream> #include<deque> using namespace std; int t; int l; char fzd[10]; int num; bool flag; char b[210]; map<char,bool> mp; deque<int> q; int tot,pre[210],last[210],other[210],w[210]; void add(int x,int y) { tot++; pre[tot]=last[x]; last[x]=tot; other[tot]=y; } int dfs(int x) { int tmp=w[x],sum=0; for(int p=last[x];p;p=pre[p]) { int v=other[p]; if(w[v]==-1) continue; sum=max(sum,dfs(v)); }

为什么HashMap的Capacity必须2^n

泄露秘密 提交于 2019-12-03 19:45:23
为了元素均匀的分布在数组上,减少hash碰撞的机会。 一、hashmap数据结构 1、没有hash碰撞 hashmap初始化,或者put操作没有产生碰撞时,都是均匀分布在数组上。 2、hash碰撞 元素产生hash碰撞时,会调用equals方法比较两个元素是否相同,不相同则以链表的形式存储。 3、链表长度大于8 遍历链表寻找元素的时间复杂度是O(n),当链表长度大于8时,转换成功red black tree(红黑树), 时间复杂度O(lgn) 二、长度是2^n次方如何定位元素位置: hashMap的put操作是如何定位元素位置的,先求hash值。 static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } 1、hashcode的低位和高位(高位右移16位)做异或运算(相同是0,相异是1,任何与0做异或运算的结果都是0) 2、求hash值的过程 h=key.hashCode() h: 1111 1111 1111 1111 0000 0000 0000 1111 h>>>16(无符号右移16位,高位补0): 0000 0000 0000 0000 1111 1111 1111 1111 h^h>>>16 : 0000 0000

算法之时间复杂度

喜欢而已 提交于 2019-12-03 16:54:03
在了解时间复杂度之前,让我们来了解一下什么是算法? 算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令(我的理解是一系列解决问题的步骤),算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。不同的算法可能用不同的时间、空间或效率来完成同样的任务。 一个算法的优劣可以用空间复杂度与时间复杂度来衡量。 算法的五大特性: 输入:算法具有0个或多个输入 输出: 算法至少有1个或多个输出 有穷性: 算法在有限的步骤之后会自动结束而不会无限循环,并且每一个步骤可以在可接受的时间内完成 确定性:算法中的每一步都有确定的含义,不会出现二义性 可行性:算法的每一步都是可行的,也就是说每一步都能够执行有限的次数完成 不同的算法对执行程序的结果也许是一样的,但是执行时间和效率却有着很大的区别,下面让我们来看个例子: 问题:a + b + c = 100, a^2 + b^2 = c^2,请计算出所有符合的a, b, c结果。 import time start_time = time.time() # 注意是三重循环 for a in range(0, 1001): for b in range(0, 1001): for c in range(0, 1001): if a**2 + b**2 == c**2