数据结构
文章平均质量分 77
甜瓜瓜哥
这个作者很懒,什么都没留下…
展开
-
目前比较排序所能够达到的最优计算复杂度
3)快速排序 (Quick Sort):快速排序在平均情况下的时间复杂度是 O(nlogn),虽然在最坏情况下是 O(n方),但通过合理选择主元(例如使用三数取中法),可以在实际中通常达到O(nlogn) 的性能。非基于比较的排序算法,如基数排序(Radix Sort)和计数排序(Counting Sort),可以在特定条件下实现线性时间复杂度 O(n),但这些算法不适用于所有类型的数据,并且不是基于比较的排序方法。具体来说,任何基于比较的排序算法,在最坏情况下都需要进行至少 log(n!原创 2024-06-04 14:38:02 · 138 阅读 · 0 评论 -
分治的思想及相关问题
主让i指向小于等于主元素部分的最后一个元素,j指向大于主元素部分的最后一个元素。原创 2024-04-26 09:00:23 · 190 阅读 · 0 评论 -
递归之生成排列和整数划分
算法的复杂度由if和else两部分决定,直觉上觉得是else起决定作用。输出语句共执行了nn!代表排序的总数,而每个排序有n个输出。所以复杂度由if决定为Θ(nn!原创 2024-04-13 18:08:28 · 188 阅读 · 0 评论 -
排序之冒泡、堆、插入和希尔
桶排序适用于元素分布均匀的场景。如果元素分布不均匀,会存在大多数元素都被分发到同一个桶中,则退化成比较排序。每次都从剩余的元素中取第一个元素,将其插入到前面已经排序好的序列中,使得插入后的序列依然是排序好的序列。将两个已经排序好的数组(如数组A和数组B)进行合并,合并后的数组依然是排序好的。为了减少比较次数,可以跳着比,比如每隔4个元素比较一次。比较排序所能达到的最优复杂度为O(nlogn)将元素组织成堆结构,然后每次取堆顶元素。如4路归并算法,和2路归并比较。插入排序是一种稳定排序。原创 2024-03-31 16:35:35 · 439 阅读 · 0 评论 -
数据结构之不相交集
是不是通过基于秩的合并就总能得到最优的不相交集?不一定:如有4个节点,先合并1和2,再合并3和4,不一定是最优的。原创 2024-03-30 21:17:57 · 354 阅读 · 0 评论 -
堆的特征和构建
任何一个父节点的值都大于等于其子节点的值,但节点的左右子节点并无顺序要求,且上层节点的值不一定大于下层节点的值。堆是一颗完全二叉树,堆所对应树的节点的排列必须是从上到下,从左到右的依次排列,否则将不构成堆。在最大堆中,根节点值最大,叶子节点值较小,从根到叶子的一条路径上,节点值是从大到小排列的。时间复杂度为O(nlogn),因为插入一个元素需要logn,总共需要插入n个构建元素。从一个空堆开始,逐步插入A中的每个元素,直到A中所有元素都被转移到堆中。直接对数据进行调整,如自上而下的调整。原创 2024-03-30 20:23:27 · 447 阅读 · 0 评论 -
时间和空间复杂度
在迭代(循环)的场景下,复杂度就是计算迭代次数最高的语句。为了求解问题的实例而执行的计算步骤所需要的内存。计算执行频率最高的语句作为算法的复杂度。用大写字母O来进行表示。用大写字母T来进行表示。原创 2024-03-30 13:47:48 · 176 阅读 · 0 评论 -
Set、HashTable和HashSet的区别
Hashtable是同步的,适合在多线程环境下使用。HashSet不是同步的,如果需要在多线程环境下使用,可以使用Collections.synchronizedSet方法包装HashSet。Set接口本身不提供同步性,但可以通过Collections.synchronizedSet创建同步的Set。原创 2023-12-04 13:03:03 · 380 阅读 · 0 评论 -
如何使用LinkedList实现栈和队列结构
【代码】如何使用LinkedList实现栈和队列结构。原创 2023-12-04 12:11:19 · 199 阅读 · 0 评论 -
数据结构中常见的树
由于磁盘IO效率非常低,当我们有大量的数据时,我们无法将所有的数据一次性全部加载到内存当中,只能逐一加载磁盘页,每个磁盘页对应树中的一个节点。mysql当中默认是16k,最坏的情况下树的高度就决定磁盘的io次数。同时,对于红黑树来说,它的旋转次数通常要小于平衡二叉树,因此平衡二叉树查找快,插入和删除较慢,而红黑树则相反。二叉树的左子树的所有节点都会小于根节点,右子树的所有节点值都大于根节点。因此,b树不再是二叉树,而是一个平衡的多叉树,相同节点个数的情况下,b树最坏情况下是三次io,而平衡二叉树是4次。原创 2023-11-22 21:54:07 · 34 阅读 · 0 评论 -
说说你对一致性Hash算法的理解
一致性hash算法是一种比较特殊、在原本Hash算法上的一个改良。它会尽可能去减少因我们数据存储节点发生变化时候发生的迁移成本。原创 2023-11-22 20:46:08 · 58 阅读 · 0 评论 -
常见的树形数据结构及其在索引中的使用情况
总的来说,选择使用特定类型的树形数据结构取决于应用程序的特定需求和数据访问模式。例如,在需要高效处理大量磁盘上的数据时,B树和B+树可能是更好的选择。在内存中的高度动态场景中,红黑树或AVL树可能更适合。原创 2023-11-04 20:14:53 · 62 阅读 · 0 评论 -
数据结构与算法复习题
顺序查找是一种基本的查找技术,它按顺序逐个检查列表中的元素,直到找到匹配项或者遍历完整个列表。因此,顺序查找适用于无序列表。其他选项 B. 查找插找、C. 二分查找和D. 分块查找通常用于有序列表或特定数据结构中进行高效的查找。D. 错误,因为接口中的方法默认是public的,不能使用其他访问修饰符。A. 错误,因为在接口中只能声明常量,而且它们必须使用。在接口中下面的属性和方法的声明哪些是错误的?B. 正确,因为它声明了一个抽象方法。C. 错误,因为接口中不能有构造方法。原创 2023-11-02 23:16:43 · 286 阅读 · 0 评论 -
List、Set和Map的区别
主要的区别在于它们的有序性重复性特征。在选择使用哪种数据结构时,需要根据具体的需求来决定。例如,如果需要保持元素的顺序且允许重复,就应该选择列表。如果需要存储独一无二的元素且不关心顺序,就可以选择集合。如果需要通过键来检索值,就应该选择映射。原创 2023-10-23 17:18:38 · 52 阅读 · 0 评论 -
找前k大个数的方法
如果使用部分排序,例如堆排序,时间复杂度为O(n log k),其中n是数组的长度,k是前k大的数的个数。该算法的思想是通过随机选取一个元素作为"基准",将数组分成两部分,一部分大于基准,另一部分小于基准,然后递归地在较大或较小的部分继续寻找第k大的元素。平均情况下,快速选择算法的时间复杂度是O(n),因为它以线性时间找到第k大的元素。如果需要找出前k大的数,最简单的方法是对整个数组进行排序,然后取前k个元素。总的时间复杂度是O(n log k),其中n是数组的长度,k是要找出的前k大的数的个数。原创 2023-10-20 13:25:53 · 535 阅读 · 0 评论 -
84.柱状图中最大的矩形
如果数组本身是降序的,例如 [8,6,4,2],在 8 入栈后,6 开始与8 进行比较,此时我们得到 mid(8),rigt(6),但是得不到 left。如果数组本身就是升序的,例如[2,4,6,8],那么入栈之后 都是单调递减,一直都没有走 情况三 计算结果的哪一步,所以最后输出的就是0了。,是遥相呼应的两道题目,建议都要仔细做一做,原理上有很多相同的地方,但细节上又有差异,更可以加深对单调栈的理解!是找每个柱子左右两边第一个大于该柱子高度的柱子,而本题是找每个柱子左右两边第一个小于该柱子的柱子。原创 2023-10-06 21:52:23 · 31 阅读 · 0 评论 -
42.接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。原创 2023-10-06 17:22:09 · 44 阅读 · 0 评论 -
503.下一个更大元素II
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。将两个nums数组拼接在一起,使用单调栈计算出每一个元素的下一个最大值,最后再把结果集即result数组resize到原数组大小就可以了。resize倒是不费时间,是O(1)的操作,但扩充nums数组相当于多了一个O(n)的操作。不过,本题要循环数组了。原创 2023-10-06 16:16:59 · 37 阅读 · 0 评论 -
496.下一个更大元素 I
题目说如果不存在对应位置就输出 -1 ,所以result数组如果某位置没有被赋值,那么就应该是是-1,所以就初始化为-1。在遍历nums2的过程中,我们要判断nums2[i]是否在nums1中出现过,因为最后是要根据nums1元素的下标来更新result数组。原创 2023-10-06 15:53:55 · 34 阅读 · 0 评论 -
739. 每日温度
加入T[4],T[4] == T[3] (当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况),此时依然要加入栈,不用计算距离,因为我们要求的是右面第一个大于本元素的位置,而不是大于等于!我们要保持一个递增单调栈(从栈头到栈底),所以将T[0]弹出,T[1]加入,此时result数组可以记录了,result[0] = 1,即T[0]右面第一个比T[0]大的元素是T[1]。加入T[1] = 74,因为T[1] > T[0](当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况)。原创 2023-10-06 15:11:49 · 32 阅读 · 0 评论 -
动态规划最强总结篇!
关于动规,还有 树形DP(打家劫舍系列里有一道),数位DP,区间DP ,概率型DP,博弈型DP,状态压缩dp等等等,这些在面试中出现的概率非常低。原创 2023-10-06 13:53:56 · 32 阅读 · 0 评论 -
516.最长回文子序列
其他情况dp[i][j]初始为0就行,这样递推公式:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);如果s[i]与s[j]不相同,说明s[i]和s[j]的同时加入并不能增加[i,j]区间回文子序列的长度,那么分别加入s[i]、s[j]看看哪一个可以组成最长的回文子序列。那么dp[i][j]一定是取最大的,即:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);加入s[j]的回文子序列长度为dp[i + 1][j]。原创 2023-10-06 13:49:21 · 27 阅读 · 0 评论 -
647.回文子串
如果这矩阵是从上到下,从左到右遍历,那么会用到没有计算过的dp[i + 1][j - 1],也就是根据不确定是不是回文的区间[i+1,j-1],来判断了[i,j]是不是回文,那结果一定是不对的。我们在判断字符串S是否是回文,那么如果我们知道 s[1],s[2],s[3] 这个子串是回文的,那么只需要比较 s[0]和s[4]这两个元素是否相同,如果相同的话,这个字符串s 就是回文串。注意因为dp[i][j]的定义,所以j一定是大于等于i的,那么在填充dp[i][j]的时候一定是只填充右上半部分。原创 2023-10-06 12:51:35 · 28 阅读 · 0 评论 -
动态规划之编辑距离总结篇
那最后当然是取最小值,所以当word1[i - 1] 与 word2[j - 1]不相同的时候,递推公式:dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1});if (word1[i - 1] == word2[j - 1]) 那么说明不用任何编辑,dp[i][j] 就应该是 dp[i - 1][j - 1],即dp[i][j] = dp[i - 1][j - 1];原创 2023-10-06 11:57:48 · 76 阅读 · 0 评论 -
72. 编辑距离
72. 编辑距离原创 2023-10-06 11:45:37 · 27 阅读 · 0 评论 -
583. 两个字符串的删除操作
那最后当然是取最小值,所以当word1[i - 1] 与 word2[j - 1]不相同的时候,递推公式:dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1});因为 dp[i][j - 1] + 1 = dp[i - 1][j - 1] + 2,所以递推公式可简化为:dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);dp[0][j]的话同理。原创 2023-10-06 10:57:22 · 37 阅读 · 0 评论 -
115.不同的子序列
和 dp[i][j] = dp[i - 1][j];当s[i - 1] 与 t[j - 1]不相等时,dp[i][j]只有一部分组成,不用s[i - 1]来匹配(就是模拟在s中删除这个元素),即:dp[i - 1][j]例如: s:bagg 和 t:bag ,s[3] 和 t[2]是相同的,但是字符串s也可以不用s[3]来匹配,即用s[0]s[1]s[2]组成的bag。所以当s[i - 1] 与 t[j - 1]相等时,dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];原创 2023-10-05 21:40:10 · 28 阅读 · 0 评论 -
392.判断子序列
这道题目算是编辑距离的入门题目(毕竟这里只是涉及到减法),也是动态规划解决的经典题型。这一类题都是题目读上去感觉很复杂,模拟一下也发现很复杂,用动规分析完了也感觉很复杂,但是最终代码却很简短。在之前的题目讲解中,我们讲了1143.最长公共子序列,大家会发现 本题和 1143.最长公共子序列 的相似之处。原创 2023-10-05 21:03:07 · 151 阅读 · 0 评论 -
53. 最大子序和
而是dp[6]。在回顾一下dp[i]的定义:包括下标i之前的最大连续子序列和为dp[i]。那么我们要找最大的连续子序列,就应该找每一个i为终点的连续最大子序列。所以在递推公式的时候,可以直接选出最大的dp[i]。原创 2023-10-05 20:21:09 · 40 阅读 · 0 评论 -
1035.不相交的线
这个公共子序列指的是相对顺序不变(即数字4在字符串A中数字1的后面,那么数字4也应该在字符串B数字1的后面)现在,我们可以绘制一些连接两个数字 A[i] 和 B[j] 的直线,只要 A[i] == B[j],且我们绘制的直线不与任何其他连线(非水平线)相交。直线不能相交,这就是说明在字符串A中 找到一个与字符串B相同的子序列,且这个子序列不能改变相对顺序,只要相对顺序不改变,链接相同数字的直线就不会相交。我们在两条独立的水平线上按给定的顺序写下 A 和 B 中的整数。原创 2023-10-05 18:21:24 · 37 阅读 · 0 评论 -
1143.最长公共子序列
如果text1[i - 1] 与 text2[j - 1]不相同,那就看看text1[0, i - 2]与text2[0, j - 1]的最长公共子序列 和 text1[0, i - 1]与text2[0, j - 2]的最长公共子序列,取最大的。dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]即:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);原创 2023-10-05 17:42:39 · 34 阅读 · 0 评论 -
718. 最长重复子数组
如果定义 dp[i][j]为 以下标i为结尾的A,和以下标j 为结尾的B,那么 第一行和第一列毕竟要进行初始化,如果nums1[i] 与 nums2[0] 相同的话,对应的 dp[i][0]就要初始为1, 因为此时最长重复子数组为1。举个例子A[0]如果和B[0]相同的话,dp[1][1] = dp[0][0] + 1,只有dp[0][0]初始为0,正好符合递推公式逐步累加起来。即当A[i - 1] 和B[j - 1]相等的时候,dp[i][j] = dp[i - 1][j - 1] + 1;原创 2023-10-05 16:27:54 · 58 阅读 · 0 评论 -
674. 最长连续递增序列
本题也是动规里子序列问题的经典题目,但也可以用贪心来做,大家也会发现贪心好像更简单一点,而且空间复杂度仅是O(1)。在动规分析中,关键是要理解和动态规划:300.最长递增子序列的区别。要联动起来,才能理解递增子序列怎么求,递增连续子序列又要怎么求。概括来说:不连续递增子序列的跟前0-i 个状态有关,连续递增的子序列只跟前一个状态有关。原创 2023-10-05 15:14:20 · 49 阅读 · 0 评论 -
300.最长递增子序列
本题中,正确定义dp数组的含义十分重要。dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度为什么一定表示 “以nums[i]结尾的最长递增子序” ,因为我们在 做 递增比较的时候,如果比较 nums[j] 和 nums[i] 的大小,那么两个递增子序列一定分别以nums[j]为结尾 和 nums[i]为结尾, 要不然这个比较就没有意义了,不是尾部元素的比较那么 如何算递增呢。原创 2023-10-05 14:25:38 · 71 阅读 · 0 评论 -
714.买卖股票的最佳时机含手续费
所以:dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee);所以:dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);dp[i][0] 表示第i天持有股票所省最多现金。dp[i][1] 表示第i天不持有股票所得最多现金。再来看看如果第i天不持有股票即dp[i][1]的情况, 依然可以由两个状态推出来。如果第i天持有股票即dp[i][0], 那么可以由两个状态推出来。原创 2023-10-05 13:46:32 · 27 阅读 · 0 评论 -
309.最佳买卖股票时机含冷冻期
这次把冷冻期这道题目,讲的很透彻了,细分为四个状态,其状态转移也十分清晰,建议大家都按照四个状态来分析,如果只划分三个状态确实很容易给自己绕进去。原创 2023-10-05 13:19:25 · 34 阅读 · 0 评论 -
188.买卖股票的最佳时机IV
第二次买入依赖于第一次卖出的状态,其实相当于第0天第一次买入了,第一次卖出了,然后在买入一次(第二次买入),那么现在手头上没有现金,只要买入,现金就做相应的减少。选最大的,所以 dp[i][1] = max(dp[i - 1][0] - prices[i], dp[i - 1][1]);所以dp[i][2] = max(dp[i - 1][1] + prices[i], dp[i - 1][2])使用二维数组 dp[i][j] :第i天的状态为j,所剩下的最大现金是dp[i][j]原创 2023-10-05 12:08:42 · 81 阅读 · 0 评论 -
123.买卖股票的最佳时机III
例如 dp[i][1] ,并不是说 第i天一定买入股票,有可能 第 i-1天 就买入了,那么 dp[i][1] 延续买入股票的这个状态。一定是选最大的,所以 dp[i][1] = max(dp[i-1][0] - prices[i], dp[i - 1][1]);所以dp[i][2] = max(dp[i - 1][1] + prices[i], dp[i - 1][2])那么dp[i][1]究竟选 dp[i-1][0] - prices[i],还是dp[i - 1][1]呢?你最多可以完成 两笔 交易。原创 2023-10-04 21:08:18 · 38 阅读 · 0 评论 -
122.买卖股票的最佳时机II
那么第i天持有股票即dp[i][0],如果是第i天买入股票,所得现金就是昨天不持有股票的所得现金 减去 今天的股票价格 即:dp[i - 1][1] - prices[i]。所以买入股票的时候,可能会有之前买卖的利润即:dp[i - 1][1],所以dp[i - 1][1] - prices[i]。中,因为股票全程只能买卖一次,所以如果买入股票,那么第i天持有股票即dp[i][0]一定就是 -prices[i]。唯一不同的地方,就是推导dp[i][0]的时候,第i天买入股票的情况。原创 2023-10-04 20:27:51 · 33 阅读 · 0 评论 -
121.买卖股票的最佳时机
由递推公式 dp[i][0] = max(dp[i - 1][0], -prices[i]);和 dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);同样dp[i][1]取最大的,dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);那么dp[i][0]应该选所得现金最大的,所以dp[i][0] = max(dp[i - 1][0], -prices[i]);原创 2023-10-02 21:43:06 · 41 阅读 · 0 评论