- 博客(234)
- 收藏
- 关注
原创 判断两个长方形是否重叠
判断两个长方形是否有重叠,主要涉及到对两个长方形的边界进行比较。假设我们有两个长方形,分别定义为 rect1 和 rect2。每个长方形可以用其左下角和右上角的坐标来表示。如果上述条件之一成立,则两个长方形不重叠。rect1 的右边界在 rect2 的左边界的左侧。rect1 的左边界在 rect2 的右边界的右侧。rect1 的上边界在 rect2 的下边界的下方。rect1 的下边界在 rect2 的上边界的上方。2. C++实现代码。
2024-08-17 09:43:28
181
原创 利用向量叉乘计算点到直线距离
那么向量AB与向量AP的叉乘的模就是以ABP三点形成的平行四边形面积,这样求P到AB距离,就可以用向量叉乘模长除以底边AB长度即可。如果说一条线段的两个端点坐标分别是。主要利用到向量叉乘的意义。
2024-08-17 09:06:43
141
原创 C++归并排序
1. merge 函数: 这个函数负责将两个有序的子数组合并成一个有序的数组。它使用两个临时数组 leftArr 和 rightArr 来存储左半部分和右半部分的数据,然后将它们合并到原数组中。归并排序(Merge Sort)是一种基于分治法的排序算法。它将数组分成两个子数组,分别对它们进行排序,然后将已排序的子数组合并成一个有序数组。2. mergeSort 函数: 这是归并排序的核心递归函数。它将数组分成两半,分别进行排序,然后调用 merge 函数将它们合并。
2024-08-16 08:22:23
203
原创 543. 二叉树的直径
假设我们知道对于该节点的左儿子向下遍历经过最多的节点数 L (即以左儿子为根的子树的深度) 和其右儿子向下遍历经过最多的节点数 R (即以右儿子为根的子树的深度),那么以该节点为起点的路径经过节点数的最大值即为 L+R+1。如图我们可以知道路径 [9, 4, 2, 5, 7, 8] 可以被看作以 2 为起点,从其左儿子向下遍历的路径 [2, 4, 9] 和从其右儿子向下遍历的路径 [2, 5, 7, 8] 拼接得到。3 ,取路径 [4,2,1,3] 或 [5,2,1,3] 的长度。由它们之间边数表示。
2024-08-06 09:33:29
253
原创 21. 合并两个有序链表
然后,我们重复以下过程,直到 l1 或者 l2 指向了 null :如果 l1 当前节点的值小于等于 l2 ,我们就把 l1 当前的节点接在 prev 节点的后面同时将 l1 指针往后移一位。由于输入的两个链表都是有序的,所以不管哪个链表是非空的,它包含的所有元素都比前面已经合并链表中的所有元素都要大。当 l1 和 l2 都不是空链表时,判断 l1 和 l2 哪一个链表的头节点的值更小,将较小值的节点添加到结果里,当一个节点被添加到结果里之后,将对应链表中的节点向后移一位。将两个升序链表合并为一个新的。
2024-08-03 14:45:47
131
原创 234. 回文链表
我们可以将链表的后半部分反转(修改链表结构),然后将前半部分和后半部分进行比较。我们也可以使用快慢指针在一次遍历中找到:慢指针一次走一步,快指针一次走两步,快慢指针同时出发。当快指针移动到链表的末尾时,慢指针恰好到链表的中间。在并发环境下,函数运行时需要锁定其他线程或进程对链表的访问,因为在函数执行过程中链表会被修改。步骤三比较两个部分的值,当后半部分到达末尾则比较完成,可以忽略计数情况中的中间节点。执行步骤一,我们可以计算链表节点的数量,然后遍历链表找到前半部分的尾节点。找到前半部分链表的尾节点。
2024-08-03 13:44:45
408
原创 287. 寻找重复数
同样的,我们从下标为 0 出发,根据 f(n) 计算出一个值,以这个值为新的下标,再用这个函数计算,以此类推产生一个类似链表一样的序列。如果数组中有重复的数,以数组 [1,3,4,2,2] 为例,我们将数组下标 n 和数 nums[n] 建立一个映射关系 f(n),如果数组中没有重复的数,以数组 [1,3,4,2]为例,我们将数组下标 n 和数 nums[n] 建立一个映射关系 f(n),从理论上讲,数组中如果有重复的数,那么就会产生多对一的映射,这样,形成的链表就一定会有环路了,你设计的解决方案必须。
2024-08-03 09:30:28
300
原创 32. 最长有效括号
我们考虑如果倒数第二个 ‘)’ 是一个有效子字符串的一部分(记作 subs),对于最后一个 ‘)’ ,如果它是一个更长子字符串的一部分,那么它一定有一个对应的 ‘(’ ,且它的位置在倒数第二个 ‘)’ 所在的有效子字符串的前面(也就是 subs的前面)。第二种情况同理,需要把有效子串 “(subs)” 之前的有效子串的长度也加上,也就是再加上 dp[i−dp[i−1]−2],如果i−dp[i−1]−2比0小,说明遇到了刚才的情况,已经到数组边界了,就没有之前的有效子串了,因此要用0+2。
2024-08-03 08:45:16
216
原创 295. 数据流的中位数
当累计添加的数的数量为奇数时,queMin 中的数的数量比 queMax 多一个,此时中位数为 queMin 的队头。当累计添加的数的数量为偶数时,两个优先队列中的数的数量相同,此时中位数为它们的队头的平均值。新的中位数将小于等于原来的中位数,因此我们可能需要将 queMin 中最大的数移动到 queMax 中。新的中位数将大于等于原来的中位数,因此我们可能需要将 queMax 中最小的数移动到 queMin 中。特别地,当累计添加的数的数量为 0 时,我们将 num 添加到 queMin 中。
2024-08-03 08:12:31
280
原创 C++快速排序
(5)向右走,从数组的左边位置向右找,一直找到比 pivot 大的数,这是 i=j,第一轮排序结束,返回 i 的位置,mid=i。(2)向左走,从数组的右边位置向左找,一直找到小于等于 pivot 的数,找到R[j]=12,R[i]与R[j]交换,i++。(4)向左走,从数组的右边位置向左找,一直找到小于等于 pivot 的数,找到R[j]=18,R[i]与R[j]交换,i++。同时选取首元素为基准元素。下面我将以序列(30,24,5,58,18,36,12,42,39)为例,进行图解。
2024-08-02 21:59:50
239
原创 394. 字符串解码
本题中可能出现括号嵌套的情况,比如 2[a2[bc]],这种情况下我们可以先转化成 2[abcbc],在转化成 abcbcabcbc。如果当前的字符为右括号,开始出栈,一直到左括号出栈,出栈序列反转后拼接成一个字符串,此时取出栈顶的数字(此时栈顶一定是数字),就是这个字符串应该出现的次数,我们根据这个次数和字符串构造出新的字符串并进栈。重复如上操作,最终将栈中的元素按照从栈底到栈顶的顺序拼接起来,就得到了答案。此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数。,表示其中方括号内部的。
2024-08-02 20:37:40
135
原创 155. 最小栈
对于栈来说,如果一个元素 a 在入栈时,栈里有其它的元素 b, c, d,那么无论这个栈在之后经历了什么操作,只要 a 在栈中,b, c, d 就一定在栈中,因为在 a 被弹出之前,b, c, d 不会被弹出。因此,在操作过程中的任意一个时刻,只要栈顶的元素是 a,那么我们就可以确定栈里面现在的元素一定是 a, b, c, d。当一个元素要入栈时,我们取当前辅助栈的栈顶存储的最小值,与当前元素比较得出最小值,将这个最小值插入辅助栈中;在任意一个时刻,栈内元素的最小值就存储在辅助栈的栈顶元素中。
2024-08-02 18:28:04
381
原创 51. N 皇后
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。研究的是如何将n个皇后放置在n×n的棋盘上,并且使皇后彼此之间不能相互攻击。给你一个整数n,返回所有不同的的解决方案。每一种解法包含一个不同的的棋子放置方案,该方案中'Q'和'.'分别代表了皇后和空位。n = 4如上图所示,4 皇后问题存在两个不同的解法。
2024-08-02 17:38:12
257
原创 79. 单词搜索
里面具体搜索就是利用for循环4个方向,用当前传入的xy节点进行扩展,扩展的新节点如果没访问过并且这个点和word当前索引下的字母一样,则添加到路径,标记为访问过,进行dfs,同时进行回溯,在把路径点退出,点变成未访问过,这是由于如果dfs搜索失败了,没有找到匹配点,那么回溯之后,这条路径上往后失败的点全要恢复原样,不影响下次搜索。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。你可以使用搜索剪枝的技术来优化解决方案,使其在。
2024-07-31 21:31:26
412
原创 208. 实现 Trie (前缀树)
创建一个新的子节点,记录在 children 数组的对应位置上,然后沿着指针移动到子节点,继续搜索下一个字符。若搜索到了前缀的末尾,就说明字典树中存在该前缀。此外,若前缀末尾对应节点的 isEnd 为真,则说明字典树中存在该字符串。重复以上步骤,直到处理字符串的最后一个字符,然后将当前节点标记为字符串的结尾。重复以上步骤,直到返回空指针或搜索完前缀的最后一个字符。沿着指针移动到子节点,继续处理下一个字符。沿着指针移动到子节点,继续搜索下一个字符。布尔字段 isEnd,表示该节点是否为字符串的结尾。
2024-07-29 17:33:58
330
原创 207. 课程表
使用DFS进行搜索遍历,要先将本题输入进行处理,先构建二维数组把图弄出来,这个二维数组里面的第一组元素代表0号课程节点可以到达的节点,意味着第一组元素的课程的先导课程是0,第二个元素就是1为祖先,1号课程可以到的下一个节点课程,以此类推,把这个二维数组的大小设为课程数。由于我们只需要判断是否存在一种拓扑排序,而栈的作用仅仅是存放最终的拓扑排序结果,因此我们可以只记录每个节点的状态,而省去对应的栈,建立一个visited数组,大小和节点数目一样,0代表未搜索,1代表搜索中,2代表此轮结束回溯,搜索完成。
2024-07-29 15:59:51
520
原创 124. 二叉树中的最大路径和
对于二叉树中的一个节点,该节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值,如果子节点的最大贡献值为正,则计入该节点的最大路径和,否则不计入该节点的最大路径和。首先,考虑实现一个简化的函数 maxGain(node),该函数计算二叉树中的一个节点的最大贡献值,具体而言,就是在以该节点为根节点的子树中寻找以该节点为起点的一条路径,使得该路径上的节点值之和最大。非空节点的最大贡献值等于节点值与其子节点中的最大贡献值之和(对于叶节点而言,最大贡献值等于节点值)。空节点的最大贡献值等于 0。
2024-07-29 14:38:19
235
原创 146. LRU 缓存
上述各项操作中,访问哈希表的时间复杂度为 O(1),在双向链表的头部添加节点、在双向链表的尾部删除节点的复杂度也为 O(1)。而将一个节点移到双向链表的头部,可以分成「删除该节点」和「在双向链表的头部添加节点」两步操作,都可以在 O(1) 时间内完成。这样以来,我们首先使用哈希表进行定位,找出缓存项在双向链表中的位置,随后将其移动到双向链表的头部,即可在 O(1) 的时间内完成 get 或者 put 操作。通过哈希表定位到该节点在双向链表中的位置,并将其移动到双向链表的头部,最后返回该节点的值。
2024-07-29 13:34:32
584
原创 23. 合并 K 个升序链表
注意这里的描述,tail 不是下一个插入的位置,aPtr 和 bPtr 所指向的元素处于待合并的状态,也就是说它们还没有合并入最终的链表。首先我们需要一个变量 head 来保存合并之后链表的头部,你可以把 head 设置为一个虚拟的头(也就是 head 的 val 属性不保存任何值),这是为了方便代码的书写,在整个链表合并完之后,返回它的下一位置即可。本题可以用一个变量result来维护以及合并的链表,第 i 次循环把第 i 个链表和 result 合并,答案保存到 result 中。
2024-07-29 11:35:21
388
原创 138. 随机链表的复制
当遍历到结尾之后,这层递归便跳出,这时该为新节点的random去赋值,由于刚才利用next指针已经将新老节点都对应起来了,因此新节点的random就可以通过map查询到了。因此先用next指针进行递归遍历,走完全程后,接下来回到每层时开始为random赋值,然后返回新节点,就这样一层一层往上返回,最后返回的新节点就是新的链表头节点。要建立原链表节点和新链表节点之间的关系,用哈希表记录每一个节点对应新节点的创建情况,具体地就是用map[old]=new。节点组成,其中每个新节点的值都设为其对应的原节点的值。
2024-07-28 21:31:38
240
原创 25. K 个一组翻转链表
2.将反转后的字段链表与下一段接上,在每段反转之前,保留好尾节点的下一个节点,这样在反转之后,新链表的尾节点有指向的地方,这样便接上了,前驱节点便是反转后链表的尾节点,之所以弄前驱节点,则是为了让每次大循环遍历链表时,能够建立出尾节点,新建的尾节点就是上一个循环得到的前驱节点。1. 建立子函数,输入是一段链表的头结点和尾结点,将其反转,返回新的头指针,尾指针。你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。的整数倍,那么请将最后剩余的节点保持原有顺序。个节点一组进行翻转,请你返回修改后的链表。
2024-07-25 22:03:18
316
原创 41. 缺失的第一个正数
2.记录1-N里的数据是否在数组中,因此遍历数组,如果当前值<=N,那么就把当前值-1作为索引值,把这个索引对应的数组值变成负数,这个负号就代表了标记。对于一个长度为 N 的数组,其中没有出现的最小正整数只能在 [1,N+1] 中。这是因为如果 [1,N] 都出现了,那么答案是 N+1,否则答案是 [1,N] 中没有出现的最小正整数。3. 在遍历完成之后,如果数组中的每一个数都是负数,那么答案是 N+1,否则答案是第一个正数的位置加 1。,请你找出其中没有出现的最小的正整数。最小的正数 1 没有出现。
2024-07-25 21:01:41
154
原创 31. 下一个排列
就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。如果在步骤 1 找不到顺序对,说明当前序列已经是一个降序序列,即最大的序列,我们直接跳过步骤 2 执行步骤 3,即可得到最小的升序序列。是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的。该方法支持序列中存在重复元素,且在 C++ 的标准库函数 next_permutation 中被采用。
2024-03-25 17:41:00
451
原创 75. 颜色分类
对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。必须在不使用库内置的 sort 函数的情况下解决这个问题。给定一个包含红色、白色和蓝色、共。分别表示红色、白色和蓝色。
2024-03-14 18:55:10
359
原创 994. 腐烂的橘子
将预处理阶段找到的腐烂橘子向四个方向开始腐烂,需要记录队列的初始长度,当长度减少到0时算一轮感染。再进行次轮感染,直到队列为空。题目中说每分钟,腐烂的橘子周围四个方向的新鲜橘子会腐烂,且初始时存在多个腐烂橘子,所以很容易想到BFS。左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个方向上。直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0。把初始时的腐烂橘子加入队列,并计算新鲜橘子的个数。的新鲜橘子都会腐烂。
2024-03-14 17:59:15
371
原创 114. 二叉树展开为链表
具体做法就是,先找到根节点左子树最右边节点,然后把该节点的右子树添加成原来根节点的右子树,然后把根节点的右子树替换成现在根节点的左子树,再把根节点的左子树置为空,接下来将根节点往下移动,也就是root=root->right,直到遍历完。实际上左子树的最右边的结点在先序遍历中一定是当前结点的左子树中最后一个遍历到的,也就是排在当前结点右子树所有节点的前面,对于每一个结点都做相同的操作,直到遍历完。额外空间)展开这棵树吗?你可以使用原地算法(
2024-03-14 16:26:47
383
原创 153. 寻找旋转排序数组中的最小值
我们考虑数组中的最后一个元素 x:在最小值右侧的元素(不包括最后一个元素本身),它们的值一定都严格小于 x;在二分查找的每一步中,左边界为 low,右边界为 high,区间的中点为 pivot,最小值就在该区间内。如下图所示,这说明 nums[pivot]是最小值右侧的元素,因此我们可以忽略二分查找区间的右半部分。如下图所示,这说明 nums[pivot]是最小值左侧的元素,因此我们可以忽略二分查找区间的左半部分。原数组为 [0,1,2,4,5,6,7] ,旋转 3 次得到输入数组。
2024-03-14 15:41:15
376
原创 169. 多数元素
突破点 就是众数出现的次数大于其他数据的所有数量,因此可以用一个count去记录数据次数,可以从头开始,例如遍历第一个数,count为1,把第一个数就记成众数,如果接下来和这个数相等,将count累加,众数不改变,遇到和当前众数不相等的数,则把count减一,如果count变成0,说明当前记的众数不是最终答案,需要进行改变,将众数变成当前的值,count重新记录为1,以此类推,直到将数组遍历结束,最终得到众数。你可以假设数组是非空的,并且给定的数组总是存在多数元素。,返回其中的多数元素。
2024-03-13 20:15:41
347
原创 136. 只出现一次的数字
假设数组中有 2m+1个数,其中有 m个数各出现两次,一个数出现一次。令 a1、a2、am为出现两次的 m 个数,am+1为出现一次的数。,除了某个元素只出现一次以外,其余每个元素均出现两次。异或运算满足交换律和结合律,即 a⊕b⊕a=b⊕a⊕a=b⊕(a⊕a)=b⊕0=b。任何数和 000 做异或运算,结果仍然是原来的数,即 a⊕0=a。因此,数组中的全部元素的异或运算结果即为数组中只出现一次的数字。任何数和其自身做异或运算,结果是 000,即 a⊕a=0。对于这道题,可使用异或运算 ⊕。
2024-03-13 19:54:30
336
原创 230. 二叉搜索树中第K小的元素
利用中序遍历,二叉搜索树的中序遍历是按照键增加的顺序进行的。于是,我们可以通过中序遍历找到第 k 个最小元素。具体地,我们使用迭代方法,这样可以在找到答案后停止,不需要遍历整棵树。如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第。,请你设计一个算法查找其中第。个最小元素(从 1 开始计数)。给定一个二叉搜索树的根节点。小的值,你将如何优化算法?
2024-03-08 22:56:13
387
原创 11. 盛最多水的容器
首先将左指针放在最开始,右指针放在数组末尾,计算面积,高度取两个的最小值。然后往下移动指针,一定是让高度小的指针移动,因为小高度才决定面积,你把大高度往后移,面积只会比原来更小。图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。轴共同构成的容器可以容纳最多的水。找出其中的两条线,使得它们与。返回容器可以储存的最大水量。
2024-03-08 20:02:39
355
原创 240. 搜索二维矩阵 II
如果matrix[x,y]>target,由于每一列的元素都是升序排列的,那么在当前的搜索矩阵中,所有位于第 y 列的元素都是严格大于 target 的,因此我们可以将它们全部忽略,即将 y 减少 1;如果 matrix[x,y]<target,由于每一行的元素都是升序排列的,那么在当前的搜索矩阵中,所有位于第 x行的元素都是严格小于 target 的,因此我们可以将它们全部忽略,即将 x 增加 1。在搜索的过程中,如果我们超出了矩阵的边界,那么说明矩阵中不存在 target。编写一个高效的算法来搜索。
2024-03-08 15:03:08
298
原创 73. 矩阵置零
具体地,我们首先遍历该数组一次,如果某个元素为 0,那么就将该元素所在的行和列所对应标记数组的位置置为 true。最后我们再次遍历该数组,用标记数组更新原数组即可。我们可以用两个标记数组分别记录每一行和每一列是否有零出现。,则将其所在行和列的所有元素都设为。的矩阵,如果一个元素为。
2024-03-08 12:06:25
343
原创 238. 除自身以外数组的乘积
初始化 answer 数组,对于给定索引 i,answer[i] 代表的是 i 左侧所有数字的乘积。同理,对于数组 R,R[length-1] 应为 1。我们不必将所有数字的乘积除以给定索引处的数字得到相应的答案,而是利用索引左侧所有数字的乘积和右侧所有数字的乘积(即前缀与后缀)相乘得到答案。对于给定索引 i,L[i] 代表的是 i 左侧所有数字的乘积,R[i] 代表的是 i 右侧所有数字的乘积。当 R 和 L 数组填充完成,我们只需要在输入数组上迭代,且索引 i 处的值为:L[i] * R[i]。
2024-03-08 11:14:59
366
原创 189. 轮转数组
先将整个数组翻转,然后把前k个翻转,再把剩下的翻转即可,但要注意这里的k不是题目中的k,k要进行处理,取nums.size的余数,因为k一旦比数组长度长,直接进行reverse翻转会出现异常,例如。向右轮转 1 步: [99,-1,-100,3]向右轮转 2 步: [3,99,-1,-100],将数组中的元素向右轮转。
2024-03-07 22:56:06
297
原创 5. 最长回文子串
上文的所有讨论是建立在子串长度大于 2的前提之上的,我们还需要考虑动态规划中的边界条件,即子串的长度为 1 或 2。根据这个思路,我们就可以完成动态规划了,最终的答案即为所有 P(i,j)=true中 j−i+1(即子串长度)的最大值。注意:在状态转移方程中,我们是从长度较短的字符串向长度较长的字符串进行转移的,因此一定要注意动态规划的循环顺序。根据这样的思路,我们就可以用动态规划的方法解决本题。也就是说,只有 s[i+1:j−1]是回文串,并且 s的第 i 和 j个字母相同时,s[i:j]才会是回文串。
2024-03-04 18:07:03
333
原创 64. 最小路径和
请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。因为路径 1→3→1→1→1 的总和最小。每次只能向下或者向右移动一步。给定一个包含非负整数的。
2024-03-04 08:23:42
354
原创 152. 乘积最大子数组
具体地讲,如果 a={5,6,−3,4,−3}那么此时 fmax对应的序列是 {5,30,−3,4,−3}按照前面的算法我们可以得到答案为 30,即前两个数的乘积,而实际上答案应该是全体数字的乘积。它代表第 i个元素结尾的乘积最大子数组的乘积 fmax(i),可以考虑把 ai加入第 i−1个元素结尾的乘积最大或最小的子数组的乘积中,二者加上 ai ,三者取大,就是第 i 个元素结尾的乘积最大子数组的乘积。的值既不是 −3,也不是 4×(−3),而是 5×6×(−3)×4×(−3)。
2024-02-28 22:52:36
305
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人