时间复杂度

寻找两个有序数组的中位数

好久不见. 提交于 2020-01-16 05:44:39
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。 你可以假设 nums1 和 nums2 不会同时为空。 示例 1 : nums1 = [ 1 , 3 ] nums2 = [ 2 ] 则中位数是 2.0 示例 2 : nums1 = [ 1 , 2 ] nums2 = [ 3 , 4 ] 则中位数是 ( 2 + 3 ) / 2 = 2.5 题解( 转自 ) 解法一 简单粗暴,先将两个数组合并,两个有序数组的合并也是归并排序中的一部分。然后根据奇数,还是偶数,返回中位数。 代码 public double findMedianSortedArrays ( int [ ] nums1 , int [ ] nums2 ) { int [ ] nums ; int m = nums1 . length ; int n = nums2 . length ; nums = new int [ m + n ] ; if ( m == 0 ) { if ( n % 2 == 0 ) { return ( nums2 [ n / 2 - 1 ] + nums2 [ n / 2 ] ) / 2.0 ; } else { return nums2 [ n / 2 ] ; } } if ( n =

数据结构之哈希、哈希函数、哈希表

被刻印的时光 ゝ 提交于 2020-01-16 01:46:36
什么是哈希? 哈希,也称散列。在某种程度上,散列是与排序相反的一种操作,排序是将集合中的元素按照某种方式比如大小顺序排列在一起,而散列通过计算哈希值,打破元素之间原有的关系,使集合中的元素按照散列函数的分类进行排列。 为什么用哈希? 我们通常使用数组或者链表来存储元素,一旦存储的内容数量特别多,需要占用很大的空间,而且在查找某个元素是否存在的过程中,数组和链表都需要挨个循环比较,而通过 哈希 计算,可以大大减少比较次数。下面举个例子! 现在有 4 个数 {2,5,9,13},需要查找 13 是否存在。 1.使用数组存储,需要新建个数组 new int[]{2,5,9,13},然后需要写个循环遍历查找,这样需要遍历 4 次才能找到,时间复杂度为 O(n)。 2.而假如存储时先使用哈希函数进行计算,这里我随便用个函数: H[key] = key % 3; 四个数 {2,5,9,13} 对应的哈希值为: H[2] = 2 % 3 = 2; H[5] = 5 % 3 = 2; H[9] = 9 % 3 = 0; H[13] = 13 % 3 = 1; 然后把它们存储到对应的位置。 当要查找 13 时,只要先使用哈希函数计算它的位置,然后去那个位置查看是否存在就好了,本例中只需查找一次,时间复杂度为 O(1)。 因此可以发现,哈希 其实是随机存储的一种优化,先进行分类

王道考研数据结构笔记之算法分析

这一生的挚爱 提交于 2020-01-15 04:00:37
算法的基本概念 算法 是对特定问题求解步骤的一种描述,它是指令的有限序列。具有下列五个重要特性: 有穷性:一个算法必须在有限的步骤结束,每一步都有在又穷的时间内结束 确定性:相同的输入只能得到相同的输出 可行性:可以被执行的操作 输入:有零个或多个输入 输出:有一个或多个输出 一个好的算法应该达到一下目标: 正确性:能够正确解决问题 可读性:具有良好的可读性,帮助别人理解 健壮性:输入非法数据,能够正确处理 效率与低存储量需求:尽量少的时间和空间 算法效率的度量 1、时间复杂度 一个语句的 频度 是指该语句在算法中被重复执行的次数。算法中所有语句的频度之和记为 T(n) 。时间复杂度主要分析T(n)的数量级。算法中基本运算(最深层循环内的语句)的频度记为 f(n) ,因此时间复杂度记为: T(n)=O(f(n)) 分析一个程序的时间复杂性时,有以下两条规则: a) 加法规则 T(n)=T1(n) + T2(n) = O(f(n)) + O(g(n)) = O(max(f(n),g(n))) b)乘法规则 T(n) = T1(n) * T2(n) = O(f(n)) * O(g(n)) = O(f(n) * g(n)) 常见的时间复杂度 O(1)<O(log(n))<O(n)<O(nlog(n))<O(n * n)<O(n * n * n) 2、空间复杂度 空间复杂度**S(n)*

一步步地分析排序——优先队列和堆排序

断了今生、忘了曾经 提交于 2020-01-15 03:55:00
本文框架 定义和使用场景 优先队列是一个抽象数据类型,和栈、队列类似,它们都是抽象数据类型,相当于一个Java类,有自己的属性,并对外提供API。在了解它有什么API之前,先来看看优先队列的使用场景。 优先队列适用于需要对集合不断地执行插入元素、删除最大(或最小)元素的场景。这个场景大体可以分为两类: 第一类是业务实际情况需要,比如CPU的任务调度,待执行的任务是一个集合,每启动一个新程序就是在向集合里面插入元素。当前程序执行完后,就要从集合里面取出下一个优先级最高的程序。不断地有程序被启动和被执行,就像不断地对集合执行插入、删除最大元素的操作。 第二类场景是“从N个元素里获取最大的M个元素,N很大,不能一次性全部读进内存”,比如从银行成百上千万条交易记录里面找到金额最大的10笔交易;或者从全国的手机号码里面找到使用年限最长的10个号码。对于第二类场景,问题本身并不需要不断地对集合进行插入、删除操作。如果内存没有限制的话,你可以一次性将数据全部装进集合,然后随便选择一个排序算法对集合进行降序排列,接着输出最前面的10个元素。但是由于待处理的数据量过大(相对内存而言),不能使用排序算法解决该类问题,以银行交易记录为例子,你可以用优先队列通过如下步骤解决: 创建一个容量为11的集合 向集合里插入一笔交易记录,如果插入后集合的元素达到11个,删除金额最小的一笔交易( 需要注意的是

数据结构导论之第一章(概论)

独自空忆成欢 提交于 2020-01-14 22:08:32
一、引言 数据结构(Data structure): 是计算机组织数据和存储数据的方式,是指一组相互之间存在一种或多种特定关系的数据的组织方式和它们在计算机内的存储方式,以及定义在该组数据上的一组操作。 数据结构: 数据的逻辑结构+数据的存储结构+数据的基本运算 计算机解决问题的步骤: 1、建立数学模型 2、设计求解算法 3、编程实现算法(运用各种计算机语言实现算法) 1976年瑞士计算机科学家尼克劳斯·维尔特[Niklaus Wirth]提出 :算法+数据结构=程序 二、基本概念和术语 数据(Data): 所有能被计算机处理的符号的集合。实际问题中的数据称为原始数据 数据元素(Data Element): 是数据这个集合中的一个个体即数据的基本单位。 数据项(Data Item): 数据元素常常还可分为若干个数据项,数据项是数据具有意义的最小单位;数据库中,数据项又称为字段/域,它是数据的不可分割的最小标识单位。 1、数据的逻辑结构: 数据的逻辑结构是指数据及数据的组织方式,是一种数学模型;指数据元素之间的结构关系 数据的逻辑结构(D, {R}) 可分为下列几种: D = {d1,d2, …, dn} ◆ 集合: 数据元素同“属于一个集合”。R = { }。任意两个结点之间都没有邻接关系,组织形式松散 ◆ 线性结构: R= {(d1, d2), (d2, d3), …, (dn

小甲鱼数据结构学习笔记——绪论

跟風遠走 提交于 2020-01-14 14:13:28
绪论 程序设计=数据结构+算法 数据结构就是数据元素相互间一种或多种关系的集合。 逻辑结构和物理结构 传统上,我们把数据结构分为逻辑结构和物理结构,主要研究逻辑结构,而物理结构是次要的。 逻辑结构:指数据对象中数据元素之间的相互关系。 物理结构:指数据的逻辑结构在计算机中的存储形式。 四大逻辑结构 集合结构:集合结构中数据元素之间的相互关系。 线性结构:线性结构中的数据元素之间是一对一的关系,有点像人体蜈蚣。。 树形结构:数据元素之间存在一种一对多的层次关系。 图形结构:数据元素是多对多的关系。按小甲鱼的说法就是杂交,emmmm(疑惑.jpg) 物理结构 研究物理结构就是研究如何把数据元素存储到计算机的存储器中。存储器主要针对内存而言,通常用文件结构来描述。 两种存储形式:顺序存储和链式存储 顺序存储结构:把数据元素存放在地址连续的存储单元里,其数据间的逻辑关系和物理关系是一致的。(不常用)例如数组结构。 链式存储结构:把数据元素存放在任意的存储单元里,这组存储单元可以是连续的,也可以是不连续的。 显然链式结构的数据元素存储关系并不能反映其逻辑关系,因此需要用一个指针存放数据元素的地址,这样来通过地址找到相关联数据元素的位置。 算法时间复杂度 定义 :在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级

时间复杂度_空间复杂度

ⅰ亾dé卋堺 提交于 2020-01-13 17:16:31
时间复杂度_空间复杂度 主要说明以下3点: 1.算法效率 2.时间复杂度 3.空间复杂度 一、 算法效率 算法效率分析分为两种:第一种是时间效率,第二种是空间效率。时间效率被称为时间复杂度,而空间效率被 称作空间复杂度。 时间复杂度主要衡量的是一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额 外空间。 二、 时间复杂度 算法中的基本操作的执行次数,为算法的时间复杂度。 // 请计算一下func1基本操作执行了多少次? void func1(int N){ int count = 0; for (int i = 0; i < N ; i++) { for (int j = 0; j < N ; j++) { count++; } } for (int k = 0; k < 2 * N ; k++) { count++; } int M = 10; while ((M--) > 0) { count++; } System.out.println(count); } 实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里 我们使用大O的渐进表示法。 最坏情况:任意输入规模的最大运行次数(上界) 平均情况:任意输入规模的期望运行次数 最好情况:任意输入规模的最小运行次数(下界) 例如:在一个长度为N数组中搜索一个数据x 最好情况

数据结构之二叉堆、堆排序

ぃ、小莉子 提交于 2020-01-13 13:35:11
前言 上一篇写了 数据结构之二叉搜索树、AVL自平衡树 ,这次来写堆。 堆的创造者 很久以前排序算法的时间复杂度一直是O(n^2), 当时学术界充斥着 “排序算法不可能突破O(n^2)” 的声音,直到1959年,由D.L.Shell提出了一种排序算法,希尔排序(Shell Sort),才打破了这种不可能的声音,把排序算法的时间复杂度提升到了O(n^3/2)! 当科学家们知道这种"不可能"被突破之后,又相继有了更快的排序算法,“不可能超越O(n^2)”彻底成为了历史。 在1964年,没错,是55年前! 堆排序 这种奇思妙想的,十分精彩的,排序算法诞生了!时间复杂度为O(nlogn),远甩O(n^2) 由Robert W. Floyd(罗伯特·弗洛伊德)和J.W.J. Williams(威廉姆斯)共同发明了著名的堆排序,同时也发明了“堆”这样的数据结构, Floyd在1978年获得了图灵奖!真是个狼人!!(比很人还要多一点) 有时候了解下历史,也是十分有趣的!虽然你可能会觉得并没什么卵用~ 堆是什么? 之前第一次听到 堆 这个词的时候,感觉像是一堆什么东西,完全跟树连想不到一起,后来才知道,原来 堆 也是一颗二叉树,而且是 完全二叉树 堆的性质: 堆中某个节点的值总是不大于或不小于其父节点的值; 堆总是一棵完全二叉树。 如何用数组表示堆? 我们可以把堆,存放在一个数组中

排序算法——希尔排序

社会主义新天地 提交于 2020-01-13 07:11:33
希尔排序 我对希尔排序进行学习的博客: 希尔排序–简单易懂图解 前言 可以说是一个加强版的插入排序。在插入排序中,最好的时间复杂度是 O ( N ) O(N) O ( N ) 可以说是极其舒服的线性时间复杂度,而这最好的情况,就是当数组中所有的数都是有序的时候,这是 O ( N ) O(N) O ( N ) 的复杂度。或者稍微比较好的情况,就是数组中大部分数都是有序的时候,那么,插入排序的时间复杂度,将趋近于 O ( N ) O(N) O ( N ) ,也就是线性的复杂度。而希尔排序的思想本质就是让数组中的数在尽可能少的次数内,变得有序起来,从而缩短整体时间复杂度,当然这思想没有脱离插入排序的基本做法,所以希尔排序的最坏时间复杂度,依然是 O ( N 2 ) O(N^2) O ( N 2 ) ,但在平均的情况下,希尔排序的时间复杂度将会是挺可观的。 基本做法 对数组进行分组(逻辑上的分组),然后对每个分组进行插入排序,使分组中的数变得有序,因为被分组后,每个分组中的数都不是很多,所以单次分组后的插入排序相对来说不会有过高的时间复杂度。然后经过多次分组然后执行插入排序后,数组中的数在整体上的有序程度会逐步拔高,直到最后一次对整体的插入排序,时间复杂度基本趋近于线性 O ( N ) O(N) O ( N ) 。而这个分组的依据就很关键了,在希尔排序中使用的则是与计算机紧密相关的数 2

Contest100000592 - 《算法笔记》5.5小节——数学问题->质因子分解

旧城冷巷雨未停 提交于 2020-01-13 05:13:44
常用模板 求所有质因子 fac数组中存放的就是质因子分解的结果,时间复杂度是 O ( n ) O(\sqrt n) O ( n ​ ) 。 定义如下: struct factor { int x , cnt ; // x为质因子,cnt为其个数 } fac [ 10 ] ; int prime [ maxn ] , num = 0 ; 核心代码: for ( int i = 0 ; i <= sqrt ( n ) ; ++ i ) { if ( n % prime [ i ] == 0 ) { fac [ num ] . x = prime [ i ] ; // 记录该因子 fac [ num ] . cnt = 0 ; while ( n % prime [ i ] == 0 ) // 计算出质因子prime[i]的个数 { ++ fac [ num ] . cnt ; n / = prime [ i ] ; } ++ num ; // 不同质因子个数加1 } } if ( n != 1 ) // 如果无法被根号n以内的质因子除尽 { fac [ num ] . x = n ; // 那么一定有一个大于根号n的质因子 fac [ num ++ ] . cnt = 1 ; } 最后指出,如果要求一个正整数N的因子个数,只需要对其质因子分解,得到各质因子 p i p_i p i ​