时间复杂度

【Leetcode】爬楼梯

拥有回忆 提交于 2019-11-30 18:12:19
问题: 爬n阶楼梯,每次只能走1阶或者2阶,计算有多少种走法。 暴力计算+记忆化递归。 从位置 i 出发,每次走1阶或者2阶台阶,记录从位置 i 出发到目标 n 所有的走法数量,memoA[i] 。记录的数据可以重复使用,避免冗余计算。 时间复杂度:O(n)。每次计算从 i 位置出发到终点 n 的走法,共计算 n 次,即树形递归的大小为n。 空间复杂度:O(n)。使用了长度为 n 的数组。 clock_t start1, end1; class Solution { public: int climbStairs(int n) { int memo[n+1] = {0}; start1 = clock(); int result = climb_stairs(0, n, memo); end1 = clock(); cout << "cost time = " << (double)(end1 - start1) / CLOCKS_PER_SEC << endl; return result; } int climb_stairs(int i, int nums, int memoA[]) { if (i > nums) return 0; if (i == nums) return 1; if (memoA[i] > 0) return memoA[i]; memoA[i] =

数组动态扩容时间复杂度分析

痞子三分冷 提交于 2019-11-30 18:02:34
对于数组动态扩容,当在数组尾部插入元素时只需要O(1)的时间复杂度,但是当插入元素刚好达到扩容的边界时,这时需要申请一块新的内存尺寸为原来的两倍,并将原数组的元素复制到新数组中,看起来数组的追加元素的效率并不高,但是因为是两倍扩容,假设数组的初始容量为2,对于N次的追加操作来说,需要扩容的次数为logN次 所以扩容的总共复制操作为 logN ∑ 2^i i = 2 这个求和公式为等比数列,既 a1=2,q=2,Sn=2(1-2^logN)/(1-2)=2(2^logN-1)=2^(logN+1)-2 忽略乘2和减2, 渐进为2^logN,所以渐进复杂度为O(N),分摊到N次的插入操作中,时间复杂度为O(1)。 来源: https://my.oschina.net/u/3737002/blog/3113445

(java实现)顺序表-ArrayList

六月ゝ 毕业季﹏ 提交于 2019-11-30 15:47:32
什么是顺序表 顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构。 在使用顺序表存储数据前,会先申请一段连续的内存空间(即数组),然后把数组依次存入内存,中间没有一点空隙。 基本操作 每个数据结构都有集合对数据处理的方法,这能让我们更方便的使用保存在数据结构中的数据。顺序表的基本操作有:增(add),删(remove),改(set),查(find),插(insert)等。 在这里我们只详细讲解remove 和 insert 操作,其他实现可看下面的源码。 顺序表删除元素 从顺序表中删除指定元素,实现起来非常简单,只需找到目标元素,并将其后续所有元素整体前移 1 个位置即可。 后续元素整体前移一个位置,会直接将目标元素删除,可间接实现删除元素的目的。 例如:从顺序表{1,2,3,4,5}中删除元素3的过程如下 时间复杂度分析:从顺序表中删除元素,最好的情况是删除的元素刚好是最后一个元素,这时候不需要移动元素,只需要把顺序表的size-1即可,时间复杂度是O(1)。最坏的情况是删除的元素刚好是第一个元素,这个时候就需要后面的元素全部向前移动一位,同时size-1,时间复杂度是O(N)。我们分析时间复杂度的原则是分析最坏情况,这样才有意义。因此删除操作的时间复杂度为O(N)。 顺序表插入元素 向已有顺序表中插入数据元素

排序算法(第三弹)归并排序和基数(桶)排序

耗尽温柔 提交于 2019-11-30 15:08:50
归并排序 排序动图演示 整体效果: 排序细节: 排序原理: 归并排序就是递归得将原始数组递归对半分隔,直到不能再分(只剩下一个元素)后,开始从最小的数组向上归并排序 1. 向上归并排序的时候,需要一个暂存数组用来排序, 2. 将待合并的两个数组,从第一位开始比较,小的放到暂存数组,指针向后移, 3. 直到一个数组空,这时,不用判断哪个数组空了,直接将两个数组剩下的元素追加到暂存数组里, 4. 再将暂存数组排序后的元素放到原数组里,两个数组合成一个,这一趟结束。 我的代码实现: 1 package cn.ftf.mysort; 2 3 import java.util.Arrays; 4 5 public class MyMergeSort { 6 //完善参数,外部调用 7 public static int[] mergeSort(int[] arr) { 8 int [] temp=new int[arr.length]; 9 arr=mergeSort1(arr,0,arr.length-1,temp); 10 return arr; 11 } 12 //分+治 13 private static int[] mergeSort1(int[] arr,int left,int right,int[] temp) { 14 if(left<right) { 15 int mid

数据结构与算法-数组

生来就可爱ヽ(ⅴ<●) 提交于 2019-11-30 15:08:34
数组是由相同类型的元素(element)的集合所组成的数据结构,分配一块连续的内存来存储。利用元素的索引(index)可以计算出该元素对应的存储地址。(维基百科) 1. 存储结构   数组是线性表数据结构,定义数组时,系统会分配一份连续的内存空间来存储一组相同的类型的数据,如int num[n]; 2. 多维数组   数组定义为一维数组、二维数组、三维数组…n维数组,其格式可以写成int num[n][m]; 3. 查找、插入、删除时间复杂度   3.1 需要查找数组第K个数时,数组会根据下标来访问,查找的时间复杂度为O(1)   3.2 需要在数组的第K个数插入一个数Y,在有序数组的情况下,插入的时间复杂度为O(n) void ArrayAdd(int* pNum, int nCount, int nAddIndex, int nAddNum) { int nEnd = nAddIndex-1; for(int nIndex=nCount-1; nIndex>=nEnd; nIndex—) { pNum[nIndex+1] = pNum[nIndex]; } pNum[nEnd] = nAddNum; }   3.3 需要删除数组的第K个数,时间复杂度为O(n) void ArrayDelete(int* pNum, int nCount, int nDeleteIndex) {

模拟测试52

痞子三分冷 提交于 2019-11-30 14:40:50
T1:   考虑二分答案。   然后问题转化为:求平均数小于某值的区间个数。   设当前二分值为$x$,每个区间的平均数可以写成:     $\begin{array} (s[i]-s[j])/(i-j) &<& x \\ (s[i]-s[j]) &<& (i-j)*x \\ s[i]-i*x &<& s[j]-j*x \end{array}$   离散化后可以树状数组维护。   时间复杂度$O(nlog^2n)$ T2:   设$dp[i][j]$为填了前$i$列,最后一列有$j$种颜色的方案数。   然后我们发现转移系数只与转移前后第二维的大小有关。   我们设这个值为$f[i][j]$,代表第二维从$i$转移到$j$的方案数。   首先,我们需要知道用固定数量的颜色涂满一列的方案数。   设$g[i][j]$为用$j$个颜色涂满$i$个格的方案数。   然后这个可以DP,$g[0][0]=1$:     $g[i][j]=g[i-1][j-1]*(p-(j+1))+g[i-1][j]*j$   很好理解,每次尝试在后面添加一个新的颜色或继承一个已有的颜色。   这样球出来的方案数是所有颜色集合的方案数总和,对于一种颜色集合,方案数为$\frac{g[n][i]}{C_p^i}$。   $dp[i][j]$的初状态也有了,即:     $dp[1][i]=g[n][i]$  

排序算法

对着背影说爱祢 提交于 2019-11-30 13:33:34
常用的排序算法的时间复杂度和空间复杂度 (原博客) 排序法 最差时间分析 平均时间复杂度 稳定度 空间复杂度 冒泡排序 O(n 2 ) O(n 2 ) 稳定 O(1) 快速排序 O(n 2 ) O(n*log 2 n) 不稳定 O(log 2 n)~O(n) 选择排序 O(n 2 ) O(n 2 ) 不稳定 O(1) 二叉树排序 O(n 2 ) O(n*log 2 n) 不一顶 O(n) 插入排序 O(n 2 ) O(n 2 ) 稳定 O(1) 堆排序 O(n*log 2 n) O(n*log 2 n) 不稳定 O(1) 希尔排序 O O 不稳定 O(1) 1、时间复杂度 (1)时间频度 一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。 (2)时间复杂度 在刚才提到的时间频度中,n称为问题的规模,当n不断变化时,时间频度T(n)也会不断变化。但有时我们想知道它变化时呈现什么规律。为此,我们引入时间复杂度概念。 一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示

细谈Redis五大数据类型

对着背影说爱祢 提交于 2019-11-30 13:22:08
文章原创于公众号:程序猿周先森。本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号。 上一篇文章有提到,Redis中使用最频繁的有5种数据类型:String、List、Hash、Set、SortSet。上一篇文章只是单纯介绍了下这5种数据类型使用到的指令以及常用场景,本篇文章会谈谈5种数据类型的底层数据结构以及各自常用的操作命令来分别进行解析。Redis作为目前最流行的Key-Value型内存数据库,不仅数据库操作在内存中进行,并且可定期的将数据持久化到磁盘中,所以性能相对普通数据库高很多,而在Redis中,每个Value实际上都是以一个redisObject结构来表示: typedef struct redisObject{ unsigned type:4; unsigned encoding:4; void *ptr; int refCount; unsigned lru: } 我们可以看看这几个参数分别的含义: type:对象的数据类型,一般情况就是5大数据类型。 encode:redisObject对象底层编码实现,主要编码类型有简单动态字符串,链表,字典,跳跃表,整数集合及压缩列表。 *ptr:指向底层实现数据结构的指针。 refCount:计数器,当引用计数值为0将会释放对象。 lru:最后一次访问本对象的时间。 String数据类型 String 数据结构是简单的

线性DP

两盒软妹~` 提交于 2019-11-30 12:54:17
很多问题往往会给出一个序列或者一个数表,让你对其进行划分,或者选出其中的某个最优子集。这一类问题往往适合使用线性DP。 线性DP是一种非常常见的DP。它往往以状态内的其中一个维度划分阶段。接下来,我将给出几个非常重要的转移方程。 最长上升(下降)子序列LIS 已知一个序列 \(A_i\) 。现在我希望从这个序列中从左往右选出若干个元素,使得这些元素组成的子序列元素大小单调递增。求这样序列的最大长度。 我们尝试设计状态表示这个最大高度。不难发现,只要 \(A_i < A_j,i<j\) , \(A_j\) 就可以和 \(A_i\) 合并。这个过程和 \(A_i\) 以前的元素没有直接的关系。 于是我们尝试设 \(F(i)\) 为以 \(A_i\) 为结尾的,从 \(A_1 \sim A_i\) 中选出的LIS。不难发现这样一个转移关系: \[ F(i) = \max_{j < i, A_j < A_i}\{F(j)\} + 1 \] 也就是说,我们以前 \(i\) 个序列划分阶段,如果有 \(A_j < A_i, j < i\) ,那么答案就可以从 \(F(j)\) 转移到 \(F(i)\) 。 初始值 \(F(1) = 1\) 。 上面这个做法的时间复杂度为 \(O(N^2)\) ,但我们可以通过以下两种方式做到 \(O(N \log N)\) 。 树状数组维护最大值

时间复杂度和空间复杂度

ぐ巨炮叔叔 提交于 2019-11-30 10:44:01
我们所谓的时间复杂度关注的是程序运行的快慢(时间上的效率) 空间复杂度程序指的是程序运行时占用的内存/外存的空间多少。 O(N):中的N表示元素个数,O(N)表示基本操作大概执行了多少次(N次) N^2 + 2*N + 10 O(N^2) O渐进表示法,只是关注基本操作执行次数的数量级,不必算的很精确。 public static void Fun(int[] arr){ //这样的操作,无论数组的元素个数有几个 //基本操作都是执行固定次数(不一定是1次) //就可以记作 O(1) System.out.println("hehe"); System.out.println("hehe"); System.out.println("hehe"); } 如果最高阶项带系数的,也不要系数 只关注数量级,只关注大概是多少,而不关注具体的精确的次数。 实例1: // 计算func2的时间复杂度? void func2(int N) { int count = 0; for (int k = 0; k < 2 * N ; k++) { count++; } int M = 10; while ((M--) > 0) { count++; } System.out.println(count); } //O(N) 实例2: // 计算func3的时间复杂度? void func3(int N