时间复杂度

40、最小的k个数

穿精又带淫゛_ 提交于 2020-01-08 09:45:47
1、题目描述: 输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。 2、思路: 这道题有三种解法,分别是排序,分治,最大堆(优先队列) 解法一:排序解法,先对输入的数组排序,排序的最快的时间复杂度为o(nlogn),然后取排序后的前k个数。总的时间复杂度为o(nlogn)。 解法二:分治方法,模仿快速排序思想,每次都取数组的第k个数,然后将比第k个数小的数放在数组的左边,比第k个数大的数放在数组的右边。然后不断的调整下去。时间复杂度为O(n)。   这个方法不适合于大数据量,因为需要改变数组的结构,并且要把数组全部加载到内存当中,若内存不够大,就不可以。 解法三:最大堆(优先队列)。首先创建一个容量为k的优先队列,传入比较器,重写其 compare 方法,以保证每次从队列中弹出的元素是最大值。这样优先队列中的元素个数小于k的时候,只需要将数组中取出来的数字直接插入到队列中即可;当优先队列的元素已满,只需要比较堆顶元素和待插入元素,若堆订元素小于待插入元素,那就舍弃,若待插入元素比堆订元素小,那就移除堆订元素,将数组元素插入其中。   这个方法的好处就是不改变数组的结构,内存占用小,适合于海量数据的处理,从最大堆中获取k个数字的最大值的时间复杂度为o(1),而删除和插入元素的操作的时间复杂度为o(logk)

链表知识总结

岁酱吖の 提交于 2020-01-08 09:34:39
一、什么是链表? 和数组一样,链表也是一种线性表。 从内存结构来看,链表的内存结构是不连续的内存空间,是将一组零散的内存块串联起来,从而进行数据存储的数据结构。 链表中的每一个内存块被称为节点Node。节点除了存储数据外,还需记录链上下一个节点的地址,即后继指针next。 二、为什么使用链表?即链表的特点 插入、删除数据效率高O(1)级别(只需更改指针指向即可),随机访问效率低O(n)级别(需要从链头至链尾进行遍历)。 和数组相比,内存空间消耗更大,因为每个存储数据的节点都需要额外的空间存储后继指针。 三、常用链表:单链表、循环链表和双向链表 1.单链表 每个节点只包含一个指针,即后继指针。 单链表有两个特殊的节点,即首节点和尾节点。为什么特殊?用首节点地址表示整条链表,尾节点的后继指针指向空地址null。 性能特点:插入和删除节点的时间复杂度为O(1),查找的时间复杂度为O(n)。 2.循环链表 除了尾节点的后继指针指向首节点的地址外均与单链表一致。 适用于存储有循环特点的数据,比如约瑟夫问题。 3.双向链表 节点除了存储数据外,还有两个指针分别指向前一个节点地址(前驱指针prev)和下一个节点地址(后继指针next)。 首节点的前驱指针prev和尾节点的后继指针均指向空地址。 性能特点: 和单链表相比,存储相同的数据,需要消耗更多的存储空间。 插入、删除操作比单链表效率更高O

链表的基本操作

懵懂的女人 提交于 2020-01-07 17:38:37
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> package com.lifeibigdata.algorithms.linearlist; /** * Created by lifei on 16/5/26. */ import java.util.HashMap; import java.util.Stack; /** * http://blog.csdn.net/luckyxiaoqiang/article/details/7393134 轻松搞定面试中的链表题目 * http://www.cnblogs.com/jax/archive/2009/12/11/1621504.html 算法大全(1)单链表 * * 目录: * 1. 求单链表中结点的个数: getListLength * 2. 将单链表反转: reverseList(遍历),reverseListRec(递归) * 3. 查找单链表中的倒数第K个结点(k > 0): reGetKthNode * 4. 查找单链表的中间结点: getMiddleNode * 5. 从尾到头打印单链表: reversePrintListStack,reversePrintListRec(递归) * 6. 已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序:

5、空格替换

泄露秘密 提交于 2020-01-06 20:52:29
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 题目:将一个字符串中的空格替换成“%20”。 例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 两种思路:不同解题思路导致时间复杂度不同。 思路一:从前往后,遇到两次空格都增加字符串长度且每次的时间复杂度都是O(n),整体时间复杂度为:T(n) = O(n的平法),效率低。 思路二:从后往前。 测试实例: class Method{ public String replaceblank (String input) { if(input == null) { //判断是否为空,为空则直接返回null return null; } int num = 0; //定义计数器来计算空格的个数 int length = input.length(); //将字符串的长度赋给length int newlength = 0; //定义变量接受改进后的字符串长度 /*遍历循环,调用索引来判断*/ for(int i = 0; i < input.length();i++) { if(' ' == input.charAt(i)) { //调用字符串的索引和空格进行对比 num++; } } /* 增加和转换后的字符串*/ newlength = length + (num

2017 UESTC Training for Data Structures-解题报告

雨燕双飞 提交于 2020-01-05 02:52:17
题目链接:http://acm.uestc.edu.cn/#/contest/show/155 这个数据结构训练主要针对线段树,树转数组和并查集。比较适合刚入门数据结构的同学。 注意,因为后面题的代码太长了,200+行起步,所以我只贴一些主要代码(有些题没有代码,我之后会补上) 还未更新完,正在更新中 A - An easy problem A 思路:正如其名,是道大水题。裸的RMQ,数据范围略小,也不需要单点更新,所以有很多姿势能水过去 我随便搓颗线段树就A了,时间复杂度O(Q*log(N))。 代码:这题这么简单,应该不需要代码吧,除非你没学过线段树.......... B - An easy problem B 思路:这题题目虽然叫简单题,可是写起来好复杂ORZ。线段树+懒惰标记,时间复杂度O(m*log(n)),在结点上要维护6个域: 1.区间内的最长的1串的长度 2.区间内的最长的0串的长度 3.区间内以区间左端点开始的最长1串的长度 3.区间内以区间左端点开始的最长0串的长度 5.区间内以区间右端点开始的最长1串的长度 6.区间内以区间右端点开始的最长0串的长度 对于上面6个域,我们分别用 这六个变量记录。 合并区间a,b时(a与b相邻且a在b的左边)时: len1 ------ 新区间内的最长的1串的长度的来源只有3个,①a.len1 ②b.len1 ③a.r1+b

数据结构的事件复杂度和空间复杂度

爱⌒轻易说出口 提交于 2020-01-04 09:06:02
事件复杂度和空间复杂度 数据结构01 算法的时间复杂度和空间复杂度 1、算法的概念: 算法 (Algorithm),是对特定问题求解步骤的一种描述。 算法五大特征 1. 输入 2. 输出 3. 有穷性 4. 确定性 5. 可行性 解决一个问题往往有不止一种方法,算法也是如此。那么解决特定问题的多个算法之间如何衡量它们的优劣呢?有如下的指标: 2、衡量算法的指标: (1)时间复杂度:执行这个算法需要消耗多少时间。 (2)空间复杂度:这个算法需要占用多少内存空间。 同一个问题可以用不同的算法解决,而一个算法的优劣将影响到算法乃至程序的效率。算法分析的目的在于为特定的问题选择合适算法。一个算法的评价主要从时间复杂度和空间复杂度来考虑。 算法在时间的高效性和空间的高效性之间通常是矛盾的。所以一般只会取一个平衡点。通常我们假设程序运行在足够大的内存空间中,所以研究更多的是算法的时间复杂度。 3、算法的时间复杂度   (1)语句频度T(n): 一个算法执行所花费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。而且一个算法花费的时间与算法中的基本操作语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度,记为T(n)。 关键要知道执行次数 ==

Leetcode141. 环形链表

梦想的初衷 提交于 2020-01-03 09:53:31
Leetcode141. 环形链表 题目: 给定一个链表,判断链表中是否有环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 示例 1: 输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。 题解: 方案一:hash表 我们遍历所有结点并在哈希表中存储每个结点的引用(或内存地址)。如果当前结点为空结点 null(即已检测到链表尾部的下一个结点),那么我们已经遍历完整个链表,并且该链表不是环形链表。如果当前结点的引用已经存在于哈希表中,那么返回 true(即该链表为环形链表)。 时间复杂度: O ( n ) O(n) O ( n ) ,对于含有 n n n 个元素的链表,我们访问每个元素最多一次。添加一个结点到哈希表中只需要花费 O ( 1 ) O(1) O ( 1 ) 的时间。 空间复杂度: O ( n ) O(n) O ( n ) ,空间取决于添加到哈希表中的元素数目,最多可以添加 n n n 个元素。 方案二:双指针 通过使用具有不同速度的快、慢两个指针遍历链表,空间复杂度可以被降低至 O ( 1 ) O(1) O ( 1 ) 。慢指针每次移动一步,而快指针每次移动两步。

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

心不动则不痛 提交于 2020-01-03 05:15:25
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 算法描述 比较相邻的元素。如果第一个比第二个大,就交换它们两个; 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数; 针对所有的元素重复以上的步骤,除了最后一个;

HashMap、lru、散列表

北战南征 提交于 2020-01-01 10:21:05
HashMap HashMap的数据结构:HashMap实际上是一个数组和链表(“链表散列”)的数据结构。底层就是一个数组结构,数组中的每一项又是一个链表。 hashCode是一个对象的标识,Java中对象的hashCode是一个int类型值。通过hashCode来算出指定数组的索引可以快速定位到要找的对象在数组中的位置,之后再遍历链表找到对应值,理想情况下时间复杂度为O(1),并且不同对象可以拥有相同的hashCode(hash碰撞)。发生碰撞后会把相同hashcode的对象放到同一个链表里,但是在数组大小不变的情况下,存放键值对越多,查找的时间效率也会降低 扩容可以解决该问题,而负载因子决定了什么时候扩容,负载因子是已存键值对的数量和总的数组长度的比值。默认情况下负载因子为0.75,我们可在初始化HashMap的时候自己修改。阀值 = 当前数组长度✖负载因子 hashmap中默认负载因子为0.75,长度默认是16,默认情况下第一次扩容判断阀值是16 ✖ 0.75 = 12;所以第一次存键值对的时候,在存到第13个键值对时就需要扩容了,变成16X2=32。 put流程 对key hash,二次hash,hash扰乱函数,减少hash碰撞 int hash(Object key) { int h = key.hashCode(); return (h ^ (h >>> 16)) &

python实现各种常用算法之排序算法(11)

ぐ巨炮叔叔 提交于 2020-01-01 02:46:45
python实现排序算法(三) 堆排序 堆排序(Heapsort)的基本思想:是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。 算法原理 堆排序基本思想是: 将初始待排序关键字序列(R1,R2…Rn)构建成大顶堆,此堆为初始的无序区。 将堆顶元素 R[1]与最后一个元素 R[n]交换,此时得到新的无序区(R1,R2,…Rn-1)和新的有序区(Rn),且满足 R[1,2…n-1]<=R[n]。 由于交换后新的堆顶 R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,…Rn-1)调整为新堆,然后再次将 R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2…Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为 n-1,则整个排序过程完成。 复杂度分析 最坏复杂度: 时间复杂度为 O(nlogn) 最好复杂度:时间复杂度在 O(nlogn) 平均复杂度: 时间复杂度为 O(nlogn) 算法实现 import random def heap_sort ( sequence ) : def heap_adjust ( parent ) : #左孩子 child = 2 * parent + 1 #孩子的索引值小于堆的长度 while child <