算法与数据结构
梨粥
这个作者很懒,什么都没留下…
展开
-
时间复杂度与简单算法
常数时间的操作如果一个操作与数据量的规模无关,其操作的时间是一定的,称其为常数时间的操作。时间复杂度时间复杂度是衡量一个算法中发生了多少常数时间操作的指标,通常用O来表示。若一个算法中的常数项操作的数量为kn^m+pn^2+L,则该算法的时间复杂度为O(n^m),删去其常数项、系数与指数次数不是最高的项。如果两个算法的时间复杂度相同,还想继续比较两个算法的性能,可以生成大量实验数据...原创 2019-03-09 14:45:17 · 290 阅读 · 0 评论 -
KMP和Manacher
KMPKMP算法用来确定一个字符串是不是另一个字符串的子串,如果是返回子串所在开始位置的下标,否则返回-1。如果使用暴力方法,我们确定目标字符串是不是原字符串的子串的方法为:从源字符串下标为0的位置与目标字符串的每个字符比对,当到达目标字符串结尾时,说明目标字符串是源字符串的子串,否则从源字符串下标为1的位置继续与目标字符串比对,当源字符串的剩余字符数比目标字符串的长度小时,则说明目标字符...原创 2019-04-17 17:35:24 · 380 阅读 · 0 评论 -
并查集结构
并查集结构用于将一定量的元素合并到同一个集合,并随时查看两个元素所在的集合是否是同一个。即并查集结构必须提供isSameSet()接口与uinon()接口。实现并查集时有多种结构可以考虑,如list、hashMap等,但这些结构在合并时都需要进行集合的合并,代价比较高,最高效的做法是底层结构采用一种类似单链表的结构。实现单链表时,一个节点的值就是输入的元素的值,而节点的指针指向同一个集合的另一...原创 2019-04-14 20:34:38 · 449 阅读 · 0 评论 -
Morris遍历
Morris遍历在学习树结构的过程中,不论是递归或者非递归方式实现的遍历,都需要用到很多额外的空间结构。递归遍历使用系统栈完成遍历,非递归使用自己构建的栈或队列来完成,今天学习的Morris遍历只需要很少的额外空间,它的空间复杂读为O(1),时间复杂度仍然是O(N)就可以完成遍历。Morris遍历用到的结构在学术上称为线索二叉树,利用二叉树中原本的空指针来作为遍历时的标志,以此达到节省空间...原创 2019-04-26 18:41:41 · 135 阅读 · 0 评论 -
树形dp
题目:二叉树节点间的最大距离问题从二叉树的节点a出发, 可以向上或者向下走, 但沿途的节点只能经过一次, 到达节点b时路径上的节点个数叫作a到b的距离, 那么二叉树任何两个节点之间都有距离, 求整棵树上的最大距离。分析对于树上的任意一个节点,它的最大距离有3种可能性,分别是左子树的最大距离、右子树的最大距离、和左子树的高度加右子树的高度加1。如果该节点最大距离等于左子树的最大距离或右子树...原创 2019-04-26 20:18:02 · 471 阅读 · 0 评论 -
由暴力递归到动态规划
动态规划的实质是对暴力递归的加速,可以减少暴力递归时重复性的计算。所以在解题时可以先不考虑时间复杂度写出暴力递归,然后将其进一步修改成动态规划。机器人达到指定位置方法数【题目】 假设有排成一行的 N 个位置,记为 1~N,N 一定大于或等于 2。开始时机器人在其中的 M 位 置上(M 一定是 1~N 中的一个),机器人可以往左走或者往右走,如果机器人来到 1 位置, 那 么下一步只能往右来...原创 2019-04-23 10:39:58 · 419 阅读 · 0 评论 -
大数据题目
【题目】32位无符号整数的范围是0~4,294,967,295, 现在有一个正好包含40亿个无符号整数的文件, 所以在整个范围中必然存在没出现过的数。 可以使用最多1GB的内存, 怎么找到所有未出现过的数?对于这道题目可以使用位图。42亿的整数需要的存储空间为40亿* 4 Byte = 4 * 4 G = 16G,但如果使用位图只需要16G / 32 = 0.5G内存即可。位图如何使用呢?...原创 2019-04-27 17:44:07 · 839 阅读 · 1 评论 -
位运算相关题目
【题目】给定两个有符号32位整数a和b, 返回a和b中较大的。【要求】不用做任何比较判断。#include <iostream>using namespace std;//参数n不是1就是0//返回值是n取反后的结果int flip(int n){ return (n ^ 1);}//如果n是非负数,返回值是0//如果n是负数,返回值是1in...原创 2019-04-28 03:15:31 · 333 阅读 · 0 评论 -
跳表--SkipList
跳表是实现有序表的方式之一,但和传统的采用树结构(如红黑树、SB树等)的实现方式不同,跳表是用概率来为数据划分层数的,即使用一个随机函数来实现它自己的平衡性。一个节点所在的层数,大概是通过一种抛硬币的方式来实现的(假设硬币正面表示为1,反面表示为0),假设第一次抛出结果是0,第二次抛出结果是0,第三次抛出结果是1,那么这个节点就在第二层。即该节点抛出了几个0,该节点就在第几层。跳表的基础节点的...原创 2019-05-13 10:20:21 · 179 阅读 · 0 评论 -
C++ 中的set/multiset/map/multimap
set/multisetC++中set/multiset以rb_tree(红黑树)为底层结构,因此有元素自动排序的特性。排序的依据就是key,而set和multiset的value和key合二为一,value就是key。set/multiset提供遍历操作及iterators,按正常规则(ite++)遍历就可以得到元素的排序。因为set中的key是唯一的,所以在添加元素时,调用底层结构...原创 2019-07-18 09:09:40 · 286 阅读 · 0 评论 -
C++ 中的 hashTable
1. 什么是hashTable用来存储数据的最基本的的结构有数组和链表两种,其他结构都是在这两种基础之上的复用与衍生。当用户进行输入时,输入可能有一定的规律,更大的可能性是输入的数据具有很大的随机性,采用数组进行存储的话,索引是一个很大的问题,因为数据的类型不一定为整数;如果采用链表,查找时必须进行遍历,对性能有很大的影响。但我们希望能找到这样的结构,不仅查找时有很高的效率,而且适用于多...原创 2019-07-20 10:02:14 · 8546 阅读 · 0 评论 -
滑动窗口与单调栈结构
滑动窗口最大/小值更新结构现在有一个数组arr,有两个指针L、R。初始时L、R都指向-1,L、R都只能向右滑动,且L不能超过R。请快速求出L到R中间的最大值。创建一个双向队列,队列始终保持从大到小排列。当R向右滑动时,如果新加入窗口的数字大于双向队列头节点的数字,则从队列中弹出节点直到队列中即便添加新数字后也可以保持从大到小排列。队列中头节点的最大值就是窗口内的最大值。假设存在数组ar...原创 2019-04-25 20:04:48 · 517 阅读 · 0 评论 -
有序表
有序表特点:有序表的任意操作的时间复杂度的指标都相同,只是常数项时间不同。搜索二叉树任意节点,它的左子树的任意节点都比这个节点小,它的右子树的任意节点都比这个节点大。按照中序遍历,搜索二叉树得到的结果是顺序递增的。因为搜索二叉树本身的性质,它不存在相同的两个节点。搜索二叉树的几种常用操作查找:确定一个节点是不是在搜索二叉树上,只需要从根节点开始遍历,将输入的值与经过的节点的值进...原创 2019-04-12 21:56:28 · 357 阅读 · 0 评论 -
哈希结构
哈希函数1. 哈希函数的特点输入域无穷大,输出域有限;相同的输入定然导致相同的输出;不同的输入也可能导致相同的输出(哈希碰撞);虽然存在一定的哈希碰撞,但如果存在大量的输入数据那么哈希的输出域上的每一个点基本是均匀增长的(好的哈希函数它的增长于输入数据本身的质量无关,即使输入数据本身存在一定的规律,也应该保证每个点均匀增长)。2.哈希函数的原理数学上的疏密数3.哈希...原创 2019-04-11 23:39:17 · 204 阅读 · 0 评论 -
比较器与桶排序
比较器前面介绍的选择排序、冒泡排序、插入排序、归并排序、堆排序以及快速排序,还有选择排序的变种希尔排序、鸡尾酒排序,这些都是基于比较的排序。对于这些基于比较的排序,可以通过修改比较器,来达到比较其他非基本数据类型的比较。如下图是一个比较器的实现:如果返回一个负数,认为第一个参数应该排在前面;若返回正数,则第二个参数排在前面。所以我们经常可以看到下面的写法:这里实现的是由大到...原创 2019-03-15 08:41:31 · 205 阅读 · 0 评论 -
排序问题的总结
前面介绍了选择排序、冒泡排序、插入排序、归并排序、堆排序、快速排序和桶排序,下面对这些排序算法进行总结。实现#include <iostream>#include <stdlib.h>using namespace std;class Sort{public: //插入排序 static void insertionSort(int a...原创 2019-03-17 15:25:00 · 159 阅读 · 0 评论 -
二叉树及其扩展
二叉树的结构class Node<V>{ V value; Node left; Node right;}二叉树的遍历分别是前序、中序、后续、层序遍历。//递归实现的前序遍历 static void preOrderRecur(Node* head){ if(head == NULL) ret...原创 2019-03-25 11:07:11 · 226 阅读 · 0 评论 -
时间复杂度为O(N*logN)的排序算法
归并排序这里用递归实现了归并排序,左边排序->右边排序->让其整体有序。让其整体有序的过程中使用了排外序的方法。即构造一个新的数组,比较对i, j所指向的数字进行大小比较,如果arr[i] >arr[j],则将arr[i] 的值复制到新数组中,i + 1,j 不变。这样依次遍历,直到 i 或 j 到达临界点,跳出循环。将剩余部分直接拷贝到新数组中。根据 master ...原创 2019-03-13 20:25:19 · 996 阅读 · 0 评论 -
链表
单链表与双链表单链表的节点结构Class Node<V>{ V value; Node next;}由以上结构的节点依次连接起来所形成的链叫单链表结构。双链表的节点结构Class Node<V>{ V value; Node next; Node last;}由以上结构的节点依次连接起来所形成的链叫双链表结构。...原创 2019-03-26 20:31:15 · 243 阅读 · 0 评论 -
前缀树
题目:一个字符串类型的数组arr1,另一个字符串类型的数组arr2。arr2中有哪些字符,是arr1中 出现的?请打印。arr2中有哪些字符,是作为arr1中某个字符串前缀出现的?请打印。请打印 arr2中出现次数最大的前缀。分析:对于这种题目,就可以用到前缀树来解。如果arr1 = {a, b, c}, arr2 = {a, b , c , d, e},那么这两个字符串的前缀树如图。...原创 2019-03-30 12:27:47 · 136 阅读 · 0 评论 -
贪心算法
贪心算法的定义在某一个标准下,优先考虑最满足标准的样本,然后考虑不那么满足标准的样本,最终得到某一个答案的算法,就是贪心算法。也就是说,你得出的答案只是满足这个标准的最优解(局部最优),可能不是全局最优解。根据下面这个例子来说明贪心算法给出字符串数组strs,请找出一种排序方式,使得所有的字符串拼接后形成的字符串具有最小的字典序。字典序:按照字母 abcdef......z 排序。...原创 2019-03-31 13:27:54 · 168 阅读 · 0 评论 -
暴力递归
暴力递归是动态规划的基础。暴力递归其实就是尝试。暴力递归的过程:1. 把问题转化为规模缩小了的同类问题的子问题;2. 有明确的不需要继续递归的条件(base case);3. 有当得到子问题的结果后的决策过程;4. 不记录每一个子问题的解。例题:1. 汉诺塔问题:打印n层汉诺塔从最左边移动到最右边的全部过程。void func(int rest,int...原创 2019-04-10 19:35:03 · 800 阅读 · 0 评论 -
图
图的表达方式邻接表上图的邻接表表示为1:2,7;2:3;3:4,7;4:5;6:5,3;邻接矩阵上图的邻接矩阵表达为0, 1,0, 0, 0, 0, 10, 0,1, 0, 0, 0, 00, 0,0, 1, 0, 0, 10, 0,0, 0, 1, 0, 00, 0,0, 0 , 0,0 ,00, 0,0, 0, 1, 0,00...原创 2019-03-29 15:28:09 · 210 阅读 · 1 评论 -
C++ 中的迭代器(Iterator)与 traits
算法与迭代器在C++的STL中,我们最经常使用的只有两部分,一是容器(container),如vector、list、set、map等;二是各种算法,如swap、sort等。前者是模板类,后者是模板函数,也就是说,STL 中提供的算法对它们要操纵的数据一无所知,它所需要的一切信息都必须由Iterator取得,这样算法才能正常运行。下面是find()函数的源代码template <...原创 2019-07-22 18:10:28 · 549 阅读 · 0 评论