
数据结构
嘉然在新加坡加班
这个作者很懒,什么都没留下…
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
剑指offer——斐波那契数列_python
1.递归是一种比较常见的方法:# -*- coding:utf-8 -*-class Solution: def Fibonacci(self,n): # write code here if n<=2: return 1 else: return self.Fibonacci(n-1)+self.Fibonacci(n-2)2.递归时间复杂度比较高,可采用转移方程来降低时间复杂度和空间原创 2021-12-24 15:54:53 · 401 阅读 · 0 评论 -
LeetCode208——字典树
class TrieNode {public:TrieNode* childNode[26];bool isVal;TrieNode(): isVal(false) {for (int i = 0; i < 26; ++i) {childNode[i] = nullptr;}}};class Trie {TrieNode* root;public:Trie(): root(new TrieNode()) {}// 向字典树插入一个词void insert(string w原创 2020-09-17 21:40:32 · 162 阅读 · 0 评论 -
剑指offer19——顺时针打印指针
void print(int lx, int ly, int rx, int ry, vector<vector<int>> &matrix, vector<int> &ret) { for (int j=ly; j<=ry; ++j) ret.push_back(matrix[lx][j]); for (int i=lx+1; i<=rx; ++i) ret.push_back(matrix[i][ry].原创 2020-09-17 21:20:13 · 131 阅读 · 0 评论 -
剑指offer52——正则表达式
bool isMatch(string s, string p) { if(p.empty()) return s.empty(); if(p[1] == '*'){ return isMatch(s, p.substr(2)) || (!s.empty() && (s[0] == p[0] || p[0] == '.')) && isMatch(s.substr(1), p); } els.原创 2020-09-17 18:45:48 · 112 阅读 · 0 评论 -
剑指offer25——复杂链表的复制
通过哈希表来进行复杂链表的复制。map的key值是原有链表,value是复制后的链表。RandomListNode* Clone(RandomListNode* pHead) { if(pHead==NULL ) return pHead ; unordered_map <RandomListNode *,RandomListNode *>mp; RandomListNode *t=pHead ; while(t!=NULL ) {原创 2020-09-17 16:15:42 · 152 阅读 · 0 评论 -
剑指offer61——序列化二叉树
string serialize(TreeNode* root) { if(root==NULL)return "[]"; ostringstream ostr; queue<TreeNode*>q; TreeNode*temp; q.push(root); int curNum=1; while(!q.empty()){原创 2020-09-16 21:59:54 · 151 阅读 · 0 评论 -
leecode142题题解
原题给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。说明:不允许修改给定的链表。解题思路两个关键点:该链路是否为环路,如果是的话,环路起始点在哪里?1.判断是否有环路。用一个指针遍历结点,如果能走到头即没有回路(注...原创 2020-03-19 16:59:28 · 195 阅读 · 0 评论 -
剑指offer—用两个栈实现一个队列
用两个先进后出的结构来实现一个先进先出的结构 ,相当于负负得正的意思。数据先进入栈1,后进的先出,对于栈2来讲就是先进的,要后出,所以两个栈加起来就实现了后进后出,先进先出。class Solution{public: void push(int node) { stack1 .push (node); } int pop() { i...原创 2020-04-08 22:22:19 · 153 阅读 · 0 评论 -
剑指offer—二进制中1的个数
这道题要判断一个int类型数据的二进制中1的个数。看到二进制就会联想到位运算符:异或、与、取反、或、左移和右移。判断1的个数,就会想到与1相与。1实际上是0000…1的简写,所以输入n与1相与实际上就是在判断最后1位是否为1。是结果为1,否结果为0.每次判断完之后,n向后移动一位,继续判断下一位。对于正数可以采用以下代码int NumberOf1(int n) { i...原创 2020-04-07 11:45:47 · 151 阅读 · 0 评论 -
剑指offer-递归问题集合(使用迭代的方法对递归问题进行优化)
剑指offer中跳台阶,变态跳台阶以及矩形覆盖均是递归类型。递归问题的核心在于找出转移关系,也就是当前项和前一项或是前两项的关系。本文着重点在使用迭代的方法实现递归。虽然这几道题都没有限定时间复杂度,使用递归均可通过,但是使用迭代的方法可以对其进行优化。以矩形覆盖为例:使用递归的方法:int rectCover(int number) { int sum,first=1,se...原创 2020-04-06 20:18:55 · 227 阅读 · 0 评论 -
剑指offer-斐波那契数列的解法
对于剑指offer中斐波那契数列问题原创 2020-04-05 20:42:43 · 186 阅读 · 0 评论 -
strcmp函数的实现
实现思路:从两个字符串第一个字符开始相减,若不相等即意味着已经比出了大小,!temp为0,while循环停止,返回temp值即可。若相等,即temp=0,那么str1和str2都加1,继续比较后面的字符,直到str1和str2不相等或字符串遍历结束。注:用*(unsigned char*)str1而不是用*str1。这是因为传入的参数为有符号数,有符号字符值的范围是-128 ~ 127,无符号字符值的范围是0~255,而字符串的ASCII没有负值,若不转化为无符号数这回在减法实现时出现错误。例如 st原创 2020-08-28 18:56:14 · 642 阅读 · 0 评论 -
剑指offer—约瑟夫环
f(n,m) = y意味着你从index=0开始数,数y+1个数,然后就停,停谁身上谁就是结果。f(n-1,m)=x意味着有n-1个数的时候从index=0开始数,数x+1个数就找到这结果了。那么f(n,m) 和f(n-1,m)的关系是什么呢?有n个数的时候,我们划掉了下标为(m-1)%n的数字。接下来要去掉的数字即为(m-1)%n +x+1,考虑到边界[(m-1)%n+x+1]%n,则f(n,m)=[(m-1)%n+x+1]%n,化简即为f(n,m) =(m+x)%n。 int john(int原创 2020-08-24 20:33:24 · 142 阅读 · 0 评论 -
剑指offer—用单调栈解决滑动窗口最大值问题
用双端队列来存储窗口数据,在存储的时候通过比较把最大值放在队首,每次将队首数据放入结果数组。1.每次放入数据时,将该数据与队列末尾的元素数据相比较,小的出队,这样就保证了单调递减的队列;2.判断队首元素是否出队。因为存储的是下标,所以通过比较下标即可知道是否出队。因为每次只移动1,所以只会有1个元素出队,用if即可不需要用while循环3.如果元素下标已经达到窗口值,即可记录最大值。 vector<int> maxSlidingWindow(vector<int>&原创 2020-08-24 17:06:16 · 183 阅读 · 0 评论 -
剑指offer——数组中只出现一次的数
题目:一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。本题采用位运算的思路:将整个数组全员进行异或运算,所有出现两次的元素都异或为0,所以最后得到的结果是两个只出现一次的数字的异或结果。关键问题就在于,如何将这两个数分离出来。办法是通过找到div=temp&(-temp)最低异或位,最低异或位就代表着两个数从哪里开始不同,这样通过对div和全数组异或就可以区分出最低异或位为0和1的两个数,也就是原创 2020-08-21 17:16:59 · 163 阅读 · 0 评论 -
剑指offer——二叉搜索树的第K大节点
题目:给定一棵二叉搜索树,请找出其中第k大的节点。二叉搜索树的中序遍历结果即为递增排序的数组,用sort从大到小排序后第k-1个元素即为所求元素。void preorder(vector<int> &temp,TreeNode *p) { if(p!=NULL ) { preorder(temp,p->left ); temp.push_back (p->val ); preorder(temp,p->right); }原创 2020-08-21 15:43:50 · 111 阅读 · 0 评论 -
剑指offer35——数组中的逆数对
题目:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。一种直观的思路是通过暴力破解的方法,时间复杂度为O(N*N)。除此以外,我们还可以借鉴归并排序的思想来求解逆数对。归并排序在合并数组的时候回比较前后两个数组元素的大小,在这个时候就可以得到每个元素的逆序对second-mid,时间复杂度为O(NLogN)。 int reversePairs(vector<int>& nums) { vector&原创 2020-08-20 15:43:01 · 234 阅读 · 0 评论 -
数组和链表的区别
数组数组是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素。数组的插入数据和删除数据效率低,插入数据时,这个位置后面的数据在内存中都要向后移。删除数据时,这个数据后面的数据都要往前移动。但数组的随机读取效率很高。因为数组是连续的,知道每一个数据的内存地址,可以直接找到给地址的数据。如果应用需要快速访问数据,很少或不插入和删除元素,就应该用数组。数组需要预留空间,在使用前要先申请占内存的大小,可能会浪费内存空间。并且数组不利于扩展,数组定义的空间不够时要重新定义数组。数原创 2020-08-18 16:57:12 · 149 阅读 · 0 评论 -
最大堆和最小堆
堆是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于(或不小于)其左子节点和右子节点的值。最大堆和最小堆是二叉堆的两种形式。最大堆:根结点的键值是所有堆结点键值中最大者。最小堆:根结点的键值是所有堆结点键值中最小者。...原创 2020-08-18 16:50:37 · 150 阅读 · 0 评论 -
map和unordered_map
map对于map,其底层是基于红黑树实现的,优点如下:1.有序性,这是map结构最大的优点,其元素的有序性在很多应用中都会简化很多的操作2.map的查找、删除、增加等一系列操作时间复杂度稳定,都为logn缺点:查找、删除、增加等操作平均时间复杂度较慢,与n相关unordered_map对于unordered_map来说,其底层是一个哈希表,优点如下:查找、删除、添加的速度快,时间复杂度为常数级O©缺点如下:因为unordered_map内部基于哈希表,以(key,value)对的形式存储,原创 2020-08-18 16:14:10 · 182 阅读 · 0 评论 -
哈希表
静态查找表以及动态查找表其查找的过程都无法避免同查找表中的数据进行比较,查找算法的效率很大程度取决于同表中数据的查找次数。哈希地址只是表示在查找表中的存储位置,而不是实际的物理存储位置。f()是一个函数,通过这个函数可以快速求出该关键字对应的的数据的哈希地址,称之为“哈希函数”。在构建哈希表时,最重要的是哈希函数的设计。例如设计电话簿案例中的哈希函数为:每个名字的姓的首字母的 ASCII 值即为对应的电话号码的存储位置。这时会发现,张三和赵六两个关键字的姓的首字母都是 Z ,最终求出的电话号码的存储位置原创 2020-08-18 16:02:13 · 299 阅读 · 0 评论 -
B+树
B+树是B树的变种,比B树有着更高的查找效率B+树的特性:1.有k个子树的中间节点包含k个元素,每个元素不保存数据,只用来索引,所有数据都保存在叶子结点;2.所有的叶子结点中包含了全部关键字的信息,及指向含这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。3.所有的非终端结点(非叶子结点)可以看成是索引部分,结点中仅含有其子树(根结点)中的最大(或最小)关键字。B+树中含有两个头指针,一个指向整棵树的根结点,另一个指向关键字最小的叶子结点。同时所有的叶子结点依据其关键字的大小自小原创 2020-08-17 22:06:41 · 286 阅读 · 0 评论 -
B-树
B-树(即B树,平衡多路查找树)需要满足以下特性(m阶)1.每个节点至多有m颗子树;2.除根节点外,每个分支至少有m/2颗子树;3.根节点至少有两颗子树;4.所有的叶子节点都在同一层上,叶子结点可以看做外部节点,不包含任何信息。5.有j个孩子的非叶子结点恰好有j-1个关键码。...原创 2020-08-17 21:52:30 · 100 阅读 · 0 评论 -
红黑树
红黑树(R-B TREE,全称:Red-Black Tree),本身是一棵二叉查找树,在其基础上附加了两个要求:1.树中的每个结点增加了一个用于存储颜色的标志域;2.树中没有一条路径比其他任何路径长出两倍,整棵树要接近于“平衡”的状态。这里所指的路径,指的是从任何一个结点开始,一直到其子孙的叶子结点的长度;接近于平衡:红黑树并不是平衡二叉树,只是由于对各路径的长度之差有限制,所以近似于平衡的状态。红黑树对于结点的颜色设置不是任意的,需满足以下性质的二叉查找树才是红黑树:1.树中的每个结点颜色不是红原创 2020-08-17 16:12:41 · 216 阅读 · 0 评论 -
二叉查找树转化为平衡二叉树
为了排除动态查找表中不同的数据排列方式对算法性能的影响,需要考虑在不会破坏二叉排序树本身结构的前提下,将二叉排序树转化为平衡二叉树。当二叉排序树的平衡性被打破时,就如同扁担的两头出现了一头重一头轻的现象,此时只需要改变扁担的支撑点(树的树根),就能使其重新归为平衡。使用二叉排序树实现动态查找操作的过程,实际上就是从二叉排序树的根结点到查找元素结点的过程,所以时间复杂度同被查找元素所在的树的深度(层次数)有关。为了弥补二叉排序树构造时产生影响算法效率的因素,需要对二叉排序树做“平衡化”处理,使其成为一棵原创 2020-08-17 15:51:18 · 768 阅读 · 0 评论 -
平衡二叉树
动态查找表的另外一种实现方式——平衡二叉树。平衡二叉树,又称为 AVL 树。实际上就是遵循以下两个特点的二叉树:每棵子树中的左子树和右子树的深度差不能超过 1;二叉树中每棵子树都要求是平衡二叉树;平衡因子:每个结点都有其各自的平衡因子,表示的就是其左子树深度同右子树深度的差。平衡二叉树中各结点平衡因子的取值只可能是:0、1 和 -1。...原创 2020-08-17 15:38:16 · 171 阅读 · 0 评论 -
二叉查找树
动态查找表中做查找操作时,若查找成功可以对其进行删除;如果查找失败,即表中无该关键字,可以将该关键字插入到表中。二叉查找树就是动态查找表。二叉排序树要么是空二叉树,要么具有如下特点:1.二叉排序树中,如果其根结点有左子树,那么左子树上所有结点的值都小于根结点的值;2.二叉排序树中,如果其根结点有右子树,那么右子树上所有结点的值都大小根结点的值;3.二叉排序树的左右子树也要求都是二叉排序树;...原创 2020-08-17 15:30:29 · 130 阅读 · 0 评论 -
跟谁学提前批笔试题
题目:写一个随机程序,使得1,2,3,4的出现概率为1/8,5,6的概率为1/4。思路:通过rand函数生成1到8的随机数,如果该随机数在1到4,直接输出,;如果是5和6,则输出5;如果是7和8,则输出6。程序如下:int roll_loaded_dice(){ srand((unsigned )time(NULL)); int res=0; int j=rand()%8+1; switch(j) { case 1: res= 1; bre原创 2020-07-20 10:54:09 · 390 阅读 · 0 评论 -
十大排序算法比较
稳定性:如果a原本在b前面,而a=b,排序之后a仍然在b的前面则为稳定,排序之后 a 可能会出现在 b 的后面即为不稳定。不稳定的排序算法:快速排序,希尔排序,归并排序和堆排序。时间复杂度如下:图来源于https://zhuanlan.zhihu.com/p/73714165...原创 2020-06-26 16:51:29 · 2621 阅读 · 0 评论 -
归并排序
归并排序和快速排序都是采用了分治的思想。不同的是,快排每次将数字依据大小放在键值两侧,而归并排序则是将数字分成许多小块,每块排序,然后再把块逐步合并起来。1.分块很简单,通过递归即可;2.合并的时候需要一个临时数组来存储合并数据。合并的时候左右是两个排好序的数组,现在要把它们组合起来。关键点就在于判断每一次放入临时数组的是左侧还是右侧的数据。如果左侧比右侧小,而且此时两个数组都没越界,左侧读入。如果左侧越界,那么右侧读入。如果右侧越界,那么左侧读入。综合起来,读入左侧数据的条件即为右侧越界或者左原创 2020-06-26 16:39:47 · 135 阅读 · 0 评论 -
选择排序
选择排序是对冒泡排序的改进,冒泡排序是每个元素与后面一个逐个相比,然后依据大小交换位置,把最大或者最小元素放在最后,然后开始第二轮遍历。原创 2020-06-26 15:47:34 · 94 阅读 · 0 评论 -
插入排序
插入排序是将每一个元素都与前面的元素比较,小的放在前面。如果是一个已经排好序的数组插入元素,这种算法最合适,因为此时时间复杂度为O(n),其他数都不进行遍历,只对插入元素进行遍历比较。void insertion_sort(vector<int> &num){ int len=num.size(); for(int i=0;i<len;++i) for(int j=i;j>0&&num[j]<num[j-1];--j) {原创 2020-06-25 16:40:35 · 87 阅读 · 0 评论 -
快速排序
快速排序是采用分治的思想,设置一个键值,大于它的放在右边,小于它的放在左边,然后对左右两个数组进行递归,重复同样的操作。1.确定键值,这里选的是num[first];2.通过while循环找到数组右边大于键值的元 素,然后把这个元素赋给num[first];3.通过while循环找到数组左边小于键值的元素,然后把这个元素赋给num[last];4.一直进行下去,直到数组左右元素分割完毕,然后把key值赋给 num[first];分割完毕时左右指针都指向的键值位置,所以要把key值赋给 num[fir原创 2020-06-25 16:17:44 · 107 阅读 · 0 评论 -
二叉搜索树的后序遍历序列
题目要求:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。二叉搜索树即为每个节点的值大于其左子树所有的值,小于右节点所有的值。因此,我们可以通过比较数组前半段、后半段和最后一位元素的大小来判断。每次循环结束后,len减1,左子树必然是小于末尾元素的,对于右子树来讲,末尾元素先是右子树的根节点,必然先小后大,然后是右子节点,这是最大的,左边一直小,最后是左子节点,左子节点也要比左子树所有元素大。所有不管怎么样,都是前原创 2020-06-23 21:29:27 · 163 阅读 · 0 评论 -
剑指offer—把字符串转换为整数
题目要求:将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。这道题的难点在于溢出判断,但令人遗憾的是溢出的算例似乎取消了,不进行溢出判断依然能通过调试。本文的解决方案未进行溢出判断。这道题比较简单,先看第一个元素是正负号还是数字,确定标志位。然后如果后面的一直是数字,那就用一直加起来。这里采用了位运算来代替乘法,可以加快速度。向左移动一位是乘2,移三位是乘8,合起来就是乘10。另外注意字符中的0到9和数字0到9的差别。int StrToIn原创 2020-06-23 16:48:04 · 96 阅读 · 0 评论 -
哈希表中线性探测再散列法和等概率平均查找长度
将关键字序列(7、8、30、11、18、9、14)散列存储到散列表中。散列表的存储空间是一个下标从0开始的一维数组,散列函数为: H(key) = (keyx3) MOD 7,处理冲突采用线性探测再散列法,要求装填(载)因子为0.7。(1) 请画出所构造的散列表。(2) 分别计算等概率情况下查找成功和查找不成功的平均查找长度。Ans:(1).首先明确一个概念装载因子,装载因子是指所有关键子填充哈希表后饱和的程度,它等于 关键字总数/哈希表的长度。 根据题意,我们可以确定哈希表的长度为 L转载 2020-06-22 10:41:35 · 2208 阅读 · 2 评论 -
剑指offer35—矩阵中的路径
题目要求:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。寻找路径,即要对某些元素的上下左右四个方向进行遍历,每个遍历相互独立,互不干扰。这就需要回溯的方法了。1.首先需要找到递归起点,起点即为数组元素和字符串第一个元素相同的位置。因为是在循环遍历,所以即便该点不符合也没关系,循环会继续寻找下一个起点。2.其次。需要一个标记数组 vec原创 2020-06-21 17:13:44 · 113 阅读 · 0 评论 -
剑指offer—字符串的排列
题目要求:输入一个字符串,打印出该字符串中字符的所有排列。你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。可以通过决策树来解决这个问题,决策列表提供可选择字符,分支代表不同的选择,子节点代表选择结果。而树的实现则是循环加递归。for(int i=level;i<s.size ();++i){swap(s[i],s[level]);dfs(in,s,level+1);swap(s[level],s[i]);在这个循环里,i代表的就是选择列表,swap代表的就是当前节点做出的选择,原创 2020-06-21 14:51:42 · 114 阅读 · 0 评论 -
剑指offer—滑动窗口的最大值
题目要求:给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。这道题类似于包含最小函数的栈,要建立从大到小的双端队列。每个窗口的最大值即为队首元素。所以问题的关键点在于:1.保证队列元素的排序;2.队首元素什么什么出栈;3.什么时候到达窗口大小1.怎么保证队列的从大到小排序while(!temp.empty ()&&num[temp.back ()]<num[i])temp.pop_back ();temp.push_back (i);每次将要入队的原创 2020-06-20 17:11:10 · 120 阅读 · 0 评论 -
剑指offer—剪绳子
题目要求:给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。这道题其实是一个数学问题,所以我们需要知道两个数学知识。1.当每一段绳子相同的时候,乘积最大;2.从1可得,想知道分成多少段最大其实就是求每一段多长。这个可以通过表达式的求导得到,每一段长为3的时原创 2020-06-17 20:55:31 · 128 阅读 · 0 评论