- 博客(181)
- 收藏
- 关注
原创 嵌入式软件开发 底层基础八股知识整理|复习分享
前言 本文为嵌入式方向求职通用基础知识整理,适合入门小白系统复习。内容聚焦嵌入式开发高频底层知识点,不针对特定企业面试,但覆盖求职技术考察中最常出现的原理与工程问题。嵌入式开发简单理解:使用 C 语言,在 MCU/MPU 芯片上编写程序,操控硬件外设,处理数据收发、任务调度。核心是。阅读建议:从 C 语言开始循序渐进,所有知识点都附带原理、使用场景、常见误区,方便反复回看复习。
2026-10-15 11:36:20
225
原创 C++ 常用数据结构速查:vector、stack、queue、list、树、图、哈希表等声明与核心操作
这是 GCC 编译器特有的非标准头文件,在 MSVC 或某些严格环境下可能无法使用,但在绝大多数在线笔试平台(牛客、LeetCode C++ 环境通常支持 GCC)中可正常工作。STL 没有直接提供“树”容器,但 set 和 map 底层是红黑树(平衡 BST),提供 O(log n) 的有序操作。面试中涉及“查找/计数/去重”且不要求顺序时,优先使用 unordered_map 或 unordered_set。unordered_map 平均 O(1),但最坏 O(n)(哈希冲突),且无序。
2026-10-14 23:22:52
269
原创 二叉树遍历解析:从 LeetCode 94 理解递归与迭代
遍历方式访问顺序根节点位置典型应用前序 (Pre)根 -> 左 -> 右第 1 位树的复制、目录结构展示中序 (In)左 -> 根 -> 右第 2 位BST 排序输出后序 (Post)左 -> 右 -> 根第 3 位内存释放、表达式求值。
2026-10-13 23:04:21
253
原创 LeetCode 25. K 个一组翻转链表 (迭代+分组反转法)
(注意这里的 temp 是第一次循环前保存的 1,即反转后的尾节点)。:让 prev 初始指向 groupNext(即 4),curr 初始指向当前组的头节点(即 1)。给你链表的头节点 head,每 k 个节点一组进行翻转,请你返回修改后的链表。当 curr == groupNext (即 4) 时,反转循环结束。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。:你不能只是单纯地改变节点内部的值,而是需要实际进行节点交换。此时,prev 指向了反转后的新头节点 3。
2026-10-13 22:30:31
81
原创 LeetCode 24.两两交换链表中的节点:虚拟头结点与指针
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。由于交换操作会改变链表的头节点(例如原链表 1->2 交换后头节点变为 2),为了统一处理逻辑,避免对头节点进行特殊判断,我们引入虚拟头结点(Dummy Node)。算法步骤:1.创建一个虚拟头结点 dummyHead,令 dummyHead->next = head。2.定义一个遍历指针 cur,初始指向 dummyHead。
2026-10-12 23:58:56
130
原创 从LeetCode 19. 删除链表的倒数第 N 个结点深入理解“哨兵节点”
那么 dummy 就往前跑了,最后你返回 dummy->next 时,返回的就不再是完整的链表头了。删除原本的 head 只需要统一执行:dummy->next = dummy->next->next;时,由于头节点没有“前驱节点”,我们往往不得不编写额外的 if-else 逻辑来特殊处理。初始状态:dummy(0) -> 1 -> 2 -> 3 -> 4 -> 5。:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。我们在真实链表的头节点前面,人为地加上一个虚拟节点 dummy。
2026-10-12 23:33:11
518
原创 LeetCode 21. 合并两个有序链表
最后 dummy.next 指向的就是 [1,1,2,3,4,4]。用两个指针 list1、list2 分别指向两个链表的当前节点;新链表是通过拼接给定的两个链表的所有节点组成的。这样就不需要任何关于"头节点是谁"的特殊判断,代码非常干净。每次比较 list1->val 和 list2->val,每个节点只会被访问一次,m、n 分别是两个链表的长度。最后返回 dummy.next,就是真正的头节点。只用了常数个指针变量,没有开辟额外的节点。当其中一个链表走完时,把另一个链表。,谁小就先拿谁,放到新牌堆上。
2026-10-11 23:49:34
170
原创 LeetCode 2. 两数相加:链表、指针及进位
结果链表的长度最多为 max(m,n)+1(例如 99 + 1 = 100,多出一位进位)。:O(max(m,n)),其中 m和 n分别是链表 l1 和 l2 的长度。:使用临时指针 p1 = l1, p2 = l2 进行遍历,保留 l1 和 l2 的安全引用。在栈区创建,函数结束自动销毁,无法用于构建需要返回的链表。它是一个不存储实际数据的辅助节点,其 next 指向真正的结果链表头。一旦移动,原链表的头节点就会丢失。请你将两个数相加,并以相同形式返回一个表示和的链表。的链表,表示两个非负的整数。
2026-10-11 23:39:05
265
原创 链表找环:Floyd 判圈算法(LeetCode 141 & 142 )
fast 指针进入环后,会在环内不断循环。由于 fast 每次比 slow 多走 1 步,两者的距离会不断缩小,最终必定在环内某处相遇(slow == fast),此时返回 true。在链表相关的算法题中,「判断链表是否有环」以及「寻找入环点」是两道极其经典的题目。假设从头节点到入环点的距离为 a,从入环点到快慢指针相遇点的距离为 b,从相遇点再回到入环点的距离为 c。a + b + n * (b + c) (n 为快指针在环内转的圈数,n >= 1)上,跑得快的人最终一定会从背后追上(套圈)跑得慢的人。
2026-10-10 23:52:55
443
原创 LeetCode 73. 矩阵置零:原地算法与空间优化
如果 matrix[i][j] == 0,我们将 matrix[i][0] 和 matrix[0][j] 置为 0。若 matrix[i][0] == 0 或 matrix[0][j] == 0,则令 matrix[i][j] = 0。若 matrix[i][j] == 0,则令 matrix[i][0] = 0且matrix[0][j] = 0。遍历矩阵,如果 matrix[i][j] == 0,则记录 row[i] = true 和 col[j] = true。遍历结束后,再将所有 -1 还原为 0。
2026-10-10 00:02:58
231
原创 【LeetCode 206】反转链表:双指针、头插法与递归解析(含图示)
创建一个虚拟头节点(dummy),遍历原链表,将每个节点依次“摘下来”插入到新链表的头部。由于单链表只能单向遍历,一旦我们将当前节点的 next 指针修改,就会丢失其后继节点。我们可以将过程想象为:用两个指针不断将当前节点“剥离”并指向它的前驱节点。它的核心思想是:相信递归函数能够反转剩余链表,并返回新头节点。因此,无论是哪种算法,链表反转的核心都在于“暂存后继节点”(防止断链)和“修改指向”。给你单链表的头节点 head,请你反转链表,并返回反转后的链表。输出:[5, 4, 3, 2, 1]
2026-10-09 23:42:34
405
原创 LeetCode 160 相交链表:链表结构与双指针算法
但现实是,两个链表在相交前的长度可能不同(例如 A 有 2 个独有节点,B 有 3 个独有节点)。此时 pA == pB == NULL,循环终止,返回 NULL,逻辑完美闭环。指针 pA 从 A 头出发,走完 A 后(路程 a+c),切换到 B 头继续走,直到走到相交点,总路程为 a + c + b。指针 pB 从 B 头出发,走完 B 后(路程 b+c),切换到 A 头继续走,直到走到相交点,总路程为 b + c + a。如果直接同时遍历,较长的链表指针会先到达尾部,而较短的链表指针还没走到相交点。
2026-10-09 23:25:40
175
原创 LeetCode 41. 缺失的第一个正数:从基础解法到原地哈希
给你一个未排序的整数数组 nums,请你找出其中没有出现的最小的正整数。进阶要求:请你实现时间复杂度为On并且只使用常数级别额外空间的解决方案。示例:输入:nums = [1,2,0],输出:3输入:nums = [3,4,-1,1],输出:2输入:nums = [7,8,9,11,12],输出:1。
2026-10-09 00:19:13
175
原创 前缀积与后缀积 —— LeetCode 238. 除了自身以外数组的乘积
给定一个长度为 n的整数数组 nums,要求返回一个数组 answer,其中 answer[i] 等于 nums 中除了 nums[i] 之外其余各元素的乘积。除了必须返回的 answer 数组外,我们只使用了常数个变量(R 和循环索引 i),没有开辟额外的数组空间。这完美满足了题目进阶的 O(1)空间复杂度要求。面对这些限制,传统的暴力解法(双重循环)和除法解法(需处理 0 和精度问题)均失效。[24, 12, 8, 6],与预期结果完全一致。此时 answer = [1, 1, 2, 6]
2026-10-08 23:53:45
357
原创 LeetCode 189. 轮转数组:从直观模拟到最优原地算法
算法名称时间复杂度空间复杂度辅助数组法O(N)O(N)三次翻转法O(N)O(1)环形替换法O(N)O(1)
2026-10-08 00:07:49
463
原创 LeetCode 76. 最小覆盖子串:滑动窗口算法详解
虽然代码中有一个嵌套的 while 循环,但 left 和 right 指针都只会从左到右遍历一遍 s,因此内层循环的总执行次数最多为 O(m)。在收缩的过程中,如果窗口依然满足条件,我们就记录下当前窗口的长度,并尝试寻找更短的解。:right 指针不断向右移动,扩大窗口,直到窗口内的字符能够覆盖字符串 t 的所有字符。由于字符集的大小是固定的(这里使用 128 大小的数组),因此所需的空间是常数级别的。:当窗口不再满足条件时,right 继续向右移动,寻找下一个满足条件的窗口。
2026-10-07 23:46:04
232
原创 LeetCode 239. 滑动窗口最大值与单调队列
当新元素加入时,从队尾开始,把所有小于等于新元素的旧元素统统踢出队列。当窗口滑动时,检查队首元素是否过期(滑出窗口),过期则从队首移除。当队尾元素小于等于新元素时,将其弹出,维持队列单调递减。用于比较新元素与队尾元素的大小,判断是否需要剔除队尾。,窗口从左向右滑动,返回每一步窗口中最大值组成的数组。在 C++ 中,实现单调队列的最佳容器是。当队首元素滑出窗口(过期)时,将其弹出。队列头部的元素永远是当前窗口的最大值。时间内获取窗口最大值的数据结构。比它大,且比它晚离开窗口。1 > -1,未过期。
2026-10-07 00:02:56
972
原创 LeetCode 560. 和为 K 的子数组:从暴力枚举到哈希表前缀和优化
最坏情况下,数组中的每个元素都会产生不同的前缀和,哈希表需要存储 N 个键值对。只需要遍历一次数组,哈希表的插入和查找操作平均时间复杂度为 O(1)。为了快速查询“之前出现过多少次某个前缀和”,我们可以使用哈希表 (顺序不能颠倒,否则会把自己也算进去,导致错误。解释:共有两个子数组的和为 2,分别是。只使用了常数级别的额外空间。,请你统计并返回该数组中和为。,此时我们需要哈希表里存在。这个前缀和,且次数为 1。(下标 0-1) 和。:该前缀和出现的次数。子数组是数组中元素的。数组中可能包含负数。
2026-10-06 23:47:42
193
原创 LeetCode 15. 三数之和:排序 + 双指针解法详解
通常采用内省排序(Introsort),空间复杂度为 O(logN)。外层循环遍历数组 O(N),内层双指针遍历 O(N),嵌套后为 O(N^2)。,由于数组已升序,后续数字必然大于 0,三数之和不可能为 0,直接终止循环。暴力三重循环的时间复杂度为 O(N^3),在数据量较大时会超时。,说明该数值已作为第一个数处理过,跳过当前循环,避免重复解。:左指针跳过所有重复值,右指针跳过所有重复值,最后。的策略,可以将时间复杂度优化至 O(N^2)。综合来看,主导项为 O(N^2)。:找到一组解,记录结果。
2026-10-06 23:32:29
445
原创 LeetCode 283. 移动零:从辅助数组到双指针原地算法
维度辅助数组法双指针法 (最优解)空间复杂度O(N) - 需要额外数组O(1) - 原地操作时间复杂度O(N) - 遍历3次O(N) - 遍历1次。
2026-10-06 23:24:22
194
原创 LeetCode 128. 最长连续序列 —— 从排序到哈希集合
方法时间复杂度空间复杂度是否满足题目主要缺陷排序 + 相邻比较O(n log n)O(1)❌重复元素处理错误计数数组O(n + V)O(V)❌数据范围过大,无法开数组哈希集合(正解)O(n)✅。
2026-10-06 00:32:49
315
原创 LeetCode 49. 字母异位词分组 —— 哈希表解法详解
哈希表(Hash Table)是一种通过键(Key)直接访问值(Value)的数据结构,平均查找、插入、删除的时间复杂度为O(1)。C++ 中对应的容器是,底层使用哈希桶实现。
2026-10-05 23:52:03
366
原创 LeetCode 5. 最长回文子串:从暴力匹配到中心扩展的思维演进
方法核心关键词时间复杂度空间复杂度反转匹配法反转、公共子串、索引验证O(n3)O(n)中心扩展法对称性、奇偶中心、双指针扩展O(n2)O(1)
2026-10-05 00:41:25
211
原创 回溯法详解:LeetCode 46. 全排列
路径 (Path):记录当前已经做出的选择(即当前正在生成的排列)。选择列表:当前还可以做出的选择(即数组中还未被使用的数字)。结束条件:到达决策树底层,无法再做选择的条件。
2026-10-05 00:19:29
227
原创 从LeetCode 70. 爬楼梯看动态规划:如何精准推导状态转移方程?
dp[i]到达第i阶楼梯的方法总数。定义状态:明确dp数组的含义(一维还是二维?下标代表什么?找转移方程:思考“最后一步”是怎么来的,或者“当前状态”可以由哪些“前驱状态”推导出来。这是最关键的一步,通常需要分类讨论(如选/不选、匹配/不匹配)。确定初始值dp[0]dp[1]等边界是什么?注意数组越界问题(如爬楼梯中n=1的情况)。确定遍历顺序:是从前往后,还是从后往前?是外层循环物品还是内层循环容量?确保计算dp[i]时,依赖的状态已经计算完毕。
2026-10-04 00:40:24
517
原创 从暴力标记到滑动窗口:LeetCode 567. 字符串的排列
方法核心思路复杂度是否可行暴力排序枚举所有子串排序比较❌ 超时位置标记标记位置代替字符比较❌ 逻辑错误滑动窗口 + 频率统计比较字符频次分布O(n + m)✅ 最优。
2026-10-04 00:26:04
357
原创 LeetCode 1004.最大连续1的个数III 滑动窗口及动态规划题解
定义dp[i][j]以nums[i]为结尾,且恰好使用了j次翻转机会时,能得到的最长连续 1 的长度。这里的"恰好使用 j 次"是指最多可以使用 j 次,因为翻不翻是灵活的,但为了状态统一,我们约定j表示"预算",遇到 0 就消耗一次。
2026-10-02 23:58:21
686
原创 LeetCode 59. 螺旋矩阵 II:边界收缩法详解
矩阵中共有 n平方 个位置,每个位置仅被访问和赋值一次。等)来维护边界和状态。返回的 n×n 矩阵是题目要求必须占用的空间。:在最后两个步骤(从右到左、从下到上)执行前,必须检查。为了避免陷入复杂的坐标推导和死循环,最优雅的解法是。我们需要按照顺时针“画圈”的顺序依次填充数字。,防止当 n 为奇数时最内层发生重复填充。算法仅使用了常数个整型变量(,每填完一行或一列,就收缩对应的边界。:创建 n×n 矩阵,定义四个边界。填完后,上边界下移 (填完后,右边界左移 (填完后,下边界上移 (填完后,左边界右移 (
2026-10-02 23:28:14
201
原创 【LeetCode 204. 计数质数】从暴力枚举到打表预处理
在解决本题时,算法的理论复杂度并非唯一指标,底层代码的实现细节对实际执行效率有决定性影响。在 N=5×10六次方的数据量下,计算量过大,会导致超时(TLE)。开始遍历,若当前数字为质数,则将其所有的倍数标记为合数。:时间复杂度为 O(NloglogN),空间复杂度为 O(N)。针对该题,常见的解题思路有三种,其时间复杂度与适用场景各有不同。:在埃氏筛的基础上改进,保证每个合数只会被它的最小质因数筛除。的每个数字,并逐一判断其是否为质数(试除法)。的倍数已经被更小的质数筛除过,无需重复标记。
2026-09-30 00:12:43
263
原创 【LeetCode 204. 计数质数】从暴力枚举到埃拉托斯特尼筛法
如果 x 是质数,那么 x 的倍数(2x, 3x, 4x...)一定不是质数。最直观的想法是:遍历从 2 到 n-1 的每一个数字 i,然后判断 i 是否为质数。判断质数的方法是尝试用 2 到 sqrt(i) 之间的数字去整除 i。例如 12,会被 2 标记一次(2 * 6),也会被 3 标记一次(3 * 4),存在冗余计算。在实现埃氏筛时,有一个极其重要的优化细节:内层循环从 i * i 开始,而不是 2 * i。线性筛的核心思想:保证每个合数只会被它的最小质因数筛掉。假设当前遍历到的质数是 i。
2026-09-29 00:14:11
698
原创 从暴力到单调栈 —— 以 LeetCode 1475【商品折扣后的最终价格】为例
如果当前价格是 6,右侧的价格中,10 比 6 大,不可能成为 6 的折扣,而且对于更左侧的元素来说,10 也被 6 挡住了(因为 6 更小且更靠左),所以 10 是“无用”的数据,可以直接丢弃。商店里正在进行促销活动,如果你要买第 i 件商品,那么你可以得到与 prices[j] 相等的折扣,其中 j 是满足 j > i 且 prices[j] <= prices[i] 的。最直观的想法是:对于每一个商品 i,我们都往它的右侧去扫描,找到第一个价格小于等于它的商品 j,然后计算差价。返回栈中元素的个数。
2026-09-28 23:27:10
159
原创 动态数组实战:从 LeetCode 118「杨辉三角」讲透 vector 的声明与使用
传统二维数组 int a[100][100] 需要预先分配固定内存。是最常用的动态数组容器。它解决了传统静态数组(如 int a[100])长度固定、容易越界或浪费内存的问题。:res[i] 获取的是第 i 行的引用,.resize(n, val) 将容器大小改变为 n,若变大,则多出的空间用 val 填充。:res[i][j] 代表第 i 行第 j 列的元素。二维 vector 本质是“嵌套”,外层容器的每个元素都是一个内层容器。二维 vector 可以像传统数组一样使用 [][] 进行访问。
2026-09-28 23:12:03
201
原创 LeetCode 63. 不同路径 II:从 DFS 到动态规划的深度解析
由于机器人只能向下或向右移动,到达格子 (i, j) 的路径只能来自上方 (i-1, j) 或左方 (i, j-1)。观察状态转移方程 dp[i][j] = dp[i-1][j] + dp[i][j-1],可以发现当前行的状态只依赖于。每次向右或向下走,遇到障碍物或越界则返回,到达终点则计数加一。如果 (i, j) 是障碍物(obstacleGrid[i][j] == 1),则 dp[i][j] = 0。输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
2026-09-27 22:54:47
402
原创 LeetCode 56合并区间:排序与贪心
2,6]:2 <= 3 (重叠) -> 更新 merged 末尾为 [1, max(3,6)] = [1,6]。如果区间是无序的,比如 [[8,10], [1,3], [2,6]],我们很难判断 [1,3] 和 [2,6] 是否重叠,因为它们不相邻。此时 merged = [[1,6], [8,10], [15,18]]输入:intervals = [[1,3],[2,6],[8,10],[15,18]]:表示有多少个区间。进行升序排序,数组就会变成 [[1,3], [2,6], [8,10]]。
2026-09-26 00:13:32
163
原创 LeetCode 17电话号码的字母组合:回溯算法(DFS)详解
void backtracking(参数) {if (终止条件) {存放结果;return;for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {处理节点;backtracking(路径,选择列表);// 递归回溯,撤销处理结果;
2026-09-25 23:51:15
224
原创 LeetCode 2502设计内存分配器:从朴素模拟到跳跃优化的演进之路
但在面对大规模测试用例时,朴素模拟会遭遇性能瓶颈(TLE)。下面将复盘从“朴素模拟”到“跳跃优化”的代码演进过程。操作下,版本二的复杂度接近 O(N×size)。遍历整个内存数组,遇到空闲单元(0)时,向后统计连续空闲单元的数量。的内存单元(置为 0),返回释放的单元总数。设计一个内存分配器,管理一个大小为。因此,我们可以直接跳过整个区间,让。的内存数组(初始全为 0)。的连续空闲单元,将其赋值为。),条件不成立,错误地返回了。构造函数直接初始化,替代。对于这道题,最直观的思路是。满足要求,则进行分配。
2026-09-25 23:00:48
412
原创 LeetCode125 验证回文串 —— 字符串函数与 ASCII 码解析
时间复杂度 O(n),空间复杂度 O(n)。思路直观,但不如双指针省空间。,避免负值导致越界(LeetCode 一般没问题,但工程中需注意)。字母和数字都属于"字母数字字符"(alphanumeric):无需额外分配空间,边遍历边跳过,一遍扫描即出结果。:移除非字母、非数字的字符(空格、标点、符号),判断它是否为回文串。:预处理后的字符串正读反读完全一致,则返回。只比较"字母数字"部分,其他字符直接跳过。这是最经典、最优雅的解法,时间复杂度。若传入的不是字母,原样返回,不会出错。⚠️ 这些函数参数类型是。
2026-09-25 00:03:21
168
原创 LeetCode 3525. 求出数组的 X 值 II(线段树 + 前缀性质)
这道题其实是一个“披着复杂外衣的区间统计问题”。要解决它,我们需要掌握两个核心武器:把操作转化成“区间前缀”。高效处理动态区间查询的数据结构——线段树(Segment Tree)。假设剩下的数组是。移除后缀的意思就是,你可以保留[A][A, B][A, B, C]或者。你会发现,这其实就是原数组的一个“前缀”!在区间中,有多少个前缀(其中 start≤j<n),它们的乘积取余 k 等于 x?
2026-09-24 23:30:09
438
原创 LeetCode 438. 找到字符串中所有字母异位词 —— 滑动窗口与 vector 常用操作
字母异位词:由相同字母重新排列形成的字符串,字符种类与数量相同,顺序无关。:异位词只要求字符频次相同,与顺序无关。因此维护一个长度固定为。:时间 O(n),空间 O(1)(26 个字母的定长数组)。是 1 个元素值为 26,圆括号与花括号语义不同。右移窗口:新字符入窗;直接比较两个 26 长度的计数数组。的子串,返回这些子串的起始索引。的窗口,比较窗口内字符频次与。维护当前窗口内字母次数。
2026-09-22 23:09:33
331
原创 LeetCode 11. 盛最多水的容器:从错误尝试到双指针最优解
把"高度值"映射到"位置下标",用一个辅助数组a1记录每个高度值在原数组中最后出现的位置,再对height排序,从高到低双重枚举两条边,计算面积取最大值。i >= 0;
2026-09-22 00:08:44
315
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅