- 博客(63)
- 收藏
- 关注
原创 代码随想录:回溯篇
回溯本质:用「递归+for循环」模拟多层嵌套循环,解决k层for循环无法实现的问题;startIndex控制每层遍历起始位置,避免出现[1,2]和[2,1]这类重复组合;剪枝逻辑:通过计算剩余元素数,减少无效遍历,提升效率(如n=4、k=3时,起始位置无需从3/4开始)。基础解法直观易懂,剪枝优化是面试加分项,核心是理解「树形结构+循环不变量」的回溯逻辑。与77.组合的区别:新增「和为n」的约束、集合固定为1-9(无需传n,遍历范围直接限制为9);startIndex。
2026-02-28 18:09:26
1107
原创 代码随想录:二叉树篇(下)
核心逻辑:利用BST「左小右大」的有序性,定向搜索而非遍历整棵树;递归要点:终止条件包含「找到目标节点」,递归方向由值大小决定;迭代优势:无需辅助容器(栈/队列),直接通过指针移动完成搜索,时间/空间复杂度均为OhO(h)Oh(h为树高);边界处理:未找到目标值时,递归/迭代最终都会返回nullptr。核心逻辑:利用BST「中序遍历严格递增」的特性,验证相邻节点值的大小关系;避坑要点:不能仅比较节点与其直接左右子节点(需保证左子树全小、右子树全大);
2026-02-26 19:27:12
796
原创 代码随想录:二叉树篇(中)
交换每个节点的左右子节点,遍历顺序决定处理节点的时机;推荐解法:递归前序(代码最简洁)、层序遍历(逻辑最直观);避坑点:递归中序遍历需特殊处理,否则会重复翻转节点。核心逻辑:对比左右子树的「外侧+内侧」节点是否均相等;递归关键:类后序遍历,通过返回值传递对比结果;迭代关键:用队列/栈成对存放待对比节点,非传统层序遍历。递归优先选后序遍历(代码极简,利用“根节点高度=最大深度”的特性);迭代法选层序遍历(层数直接对应深度,逻辑直观);
2026-02-23 23:50:10
639
原创 代码随想录:二叉树篇(上)
迭代法核心是queue+固定levelSize,确保每层节点被完整遍历;是层序遍历的“标准模板”,适配所有层序相关题目(如右视图、层平均值)。递归法核心是depth标记层数,通过新增层数组;本质是DFS的变形,通过深度映射层数,逻辑更抽象但代码简洁。两份代码完全独立,可直接复制使用,符合你“分开写”的要求,再次抱歉之前的整合错误!
2026-02-18 21:12:10
509
原创 代码随想录:哈希表篇
核心是利用数组实现哈希统计,适配小写字母的有限范围;长度预判是工程常用优化,可避免无效的字符统计;代码精简的核心是保留「统计-抵消-校验」的核心逻辑,剔除冗余语法。有数值范围限制时,优先用数组哈希(速度快、空间省);无范围限制时,用(通用灵活);核心逻辑:哈希标记存在性 → 遍历另一数组筛选交集 → 去重后返回。用哈希表的核心目的:快速判断「补数是否已出现」,而非暴力遍历;选择是因无需key有序,追求最高读写效率;哈希表存储「已遍历元素值-下标」,遍历中实时查询补数,找到即返回。
2026-02-16 11:04:37
1083
原创 代码随想录:链表篇
int val;虚拟头结点是核心:统一头结点和普通节点的操作逻辑,是链表设计的最优实践;_size简化索引判断:无需遍历链表验证索引有效性,时间复杂度从 O(n) 降为 O(1);内存安全不可少:析构函数和删除节点时的内存释放是工业级代码的基本要求,避免内存泄漏。双指针法是最优解:仅用3个指针完成反转,空间复杂度 O(1),是工业级首选;反转核心逻辑:先保存cur->next,再将cur->next指向pre,最后移动pre和cur;递归法本质递归模拟双指针的循环过程,逻辑完全一致;
2026-02-15 11:37:16
1036
原创 代码随想录:数组篇
二分查找的核心是明确区间定义(循环不变量),所有边界处理必须贴合该定义。主流两种区间定义对应两种写法,时间复杂度均为 O(log n),空间复杂度 O(1)。数组“移除”元素的本质是覆盖,而非真正删除;快慢双指针法是最优解(O(n) 时间,O(1) 空间),需熟练掌握;暴力解法仅作理解,实际开发中优先使用双指针法。暴力法思路简单但效率低,仅适合理解基础逻辑;双指针法利用数组“有序”的特性,将时间复杂度优化至O(n),是最优解;
2026-02-14 10:16:02
906
原创 从零复现GPT-2 124M
本课程是Andrej Karpathy「0 to Hero」系列的核心章节,目标是从零复现GPT-2 124M参数模型——从加载OpenAI预训练权重验证模型正确性,到完全随机初始化参数、基于高质量数据集从零训练,最终实现性能对标甚至超越原版GPT-2。掌握Decoder-only Transformer的完整实现(Pre-LN结构、权重共享等GPT-2关键特性)理解大模型训练的核心技术栈(混合精度、梯度累积、分布式训练、性能优化)学会从数据处理、模型初始化到评估全流程的工程实践。
2026-02-12 01:36:53
471
1
原创 GPT 分词器与位置编码常见面试题
答案无分词指不使用任何分词器(BPE/Tokenizer),直接将文本作为原始字节流输入模型,让模型自己学习切分与理解。避开分词器的多语言偏见、bug、安全隐患;真正端到端建模,无需人工规则;支持文本、音频、图像统一建模。答案码点是 Unicode 给每个字符分配的唯一数字编号,格式为 U+XXXX。例如:A → U+0041,你 → U+4F60。它是字符的逻辑编号,与存储无关。答案原始 Transformer 使用固定正弦余弦编码,而 GPT-2 将位置嵌入改为可学习参数。
2026-02-11 10:19:14
513
原创 深度学习基础5:Linear Regression with PyTorch
【代码】深度学习基础5:Linear Regression with PyTorch。
2026-01-22 15:20:37
53
原创 深度学习基础3:Stochastic Gradient Descent(SGD)
【代码】深度学习基础3:Stochastic Gradient Descent(SGD)
2026-01-22 15:18:04
59
原创 深度学习基础2:Batch Gradient Descent(BGD)
【代码】深度学习基础2:Batch Gradient Descent(BGD)
2026-01-22 15:16:54
55
原创 Linux篇:网络基础1
②TCP/IP五层(或四层)模型:(物理层、)数据链路层、网络层、传输层、应用层(像这样的网络协议栈命名为TCP/IP协议栈)。②协议分层:软件分层最典型的表现是:在结构体或类的设计上,做数据结构层面的分离/用回调函数的方式,在软件的逻辑上进行分层。b.几乎任何层的协议都要在报头中提供决定将自己的有效载荷交付给上层的哪一个协议的能力(报文的分用)。⑤交换机:划分碰撞域,防止报文在更大的局域网中扩散,有效降低数据在局域网中碰撞的概率。①协议是双方的约定,最终的表现形式就是具有特定字段的结构体对象。
2024-02-13 17:48:17
1968
原创 算法篇:贪心算法
再根据k-m的奇偶性(偶数直接忽略,奇数则挑选当前数组中最小的数,变成负数)。②从左往右,找到第一个递减的位置,从这个位置向前推,推到相同区域的最左端,使其减小1,后面的数全部修改成9。①状态表示:dp[i]表示:以i位置的信封为结尾的所有的套娃序列中,最长的套娃序列的长度。状态表示:dp[i]表示:以i的位置的元素为结尾的所有子序列中,最长递增子序列的长度。(x:标记%3=1的尽可能小的数,y:标记%3=2的尽可能小的数)存什么:所有长度为x的递增子序列中,最后一个元素的最小值。①每次处理一批相同的数。
2024-02-02 23:43:21
852
原创 算法篇:递归、搜索与回溯算法
②怎么实现:添加一个备忘录,把结果放到备忘录里面,在每次进入递归的时候向备忘录里查找一下。80%可以用前者的思考方式,但有些题用暴搜的时间成本太高了(暴搜只是为我们确定状态表示提供方向)。不是的,只有在递归的过程中,出现了大量的完全相同的问题时,才能用记忆化搜索的方式优化。②带备忘录的递归 vs 带备忘录的动态规划 vs 记忆化搜索?②从头开始的任意一个字串,左括号的数量>=右括号的数量。①所有的递归(暴搜、深搜),都能改成记忆化搜索吗?①左括号的数量=有括号的数量。
2024-02-02 23:29:46
1392
2
原创 Linux篇:线程
每个线程的库级别的tcb的起始地址叫做线程的tid,线程库维护的tid其实是在库中地址空间的一个描述结构体的虚拟地址,而LWP是管理底层轻量级进程的执行流(用户级执行流:内核LWP=1:1)。①输出型参数(输出thread id),②线程的属性(一般置为nullptr),③函数指针(让新线程执行传入的回调函数), ④创建线程成功,新线程回调线程函数的时候,需要参数(这个参数就是给线程函数传递的)。运行的时间越短,串行的比率降低,在临界区中线程也可以被调度,临界区的代码越短,线程被调度的概率也越低。
2024-01-26 14:10:46
1105
原创 算法篇:动态规划II
匹配一个,但不舍去→dp[i][j]=dp[i-1][j]→dp[i-2][j]→dp[i-3][j]......有s1[i],有s2[j]→s1[i]==s2[j]→dp[i][j]=dp[i-1][j-1]+s1[i]选i→dp[i][j][k]=dp[i-1][j-g[i]][max(0,k-p[i])] j>=g[i]综上:dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]] +w[i])→匹配一个,然后保留→p[j-1]=s[i]&&dp[i-1][j]
2024-01-10 23:18:12
1133
1
原创 算法篇:动态规划I
dp[i][j] = min(dp[i][j+1],dp[i+1][j])-d[i][j],由于最低健康点数为1,故dp[i][j]=max(1,dp[i][j])。③初始化:f[0][0]=-prices[0] g[0][0]=0 f[0][1]=f[0][2]=g[0][1]=g[0][2]=-0x3f3f3f3f。长度大于一:if(s[i-1]+1==s[i]||s[i-1]=='z'&&s[i]=='a') dp[i]=dp[i-1]设j为最后一个单词起始位置的下标(0
2024-01-09 01:57:26
1993
原创 Linux篇:信号
虚拟机在进行除零错误的时候,一段程序崩溃,对应的当前目录下会产生一个临时文件xxx.core,而默认云服务器上面的core功能是被关闭的(保证服务重启的功能一直有效,会形成code dump文件来冲击磁盘,影响服务)。b.键盘在硬件上可以给CPU发送硬件中断,每一个中断都有中断号,通过各中断单元向CPU特定针脚发送中断后,CPU会保存相应的中断号,从而完成了键盘向CPU,通知其数据已就绪的任务(显示器,网卡等设备同理)。导致节点丢失,内存泄漏。当我们的进程从内核态返回到用户态的时候,进行信号的检测与处理。
2023-12-15 12:56:22
1287
2
原创 Linux篇:进程间通信
创建共享内存/消息队列时,操作系统就要创建对应的数据结构,并将第一个字段的地址填入数组(结构体数据类型可以不一样,因为第一个字段的类型都一样)。同一个文件是内存级的,每个文件都存在自己的缓冲区,如果双方想向自己的缓冲区中写入,子进程就可以通过缓冲区读取,实现进程间通信。④当然,也可通过用户输入的key,找到每一个对应的ipc资源,通过比较第一个字段的ipc_perm中的key,确认进程是否已经被创建(新旧)。申请和释放PV操作——原子的:一件事情要么不做,要做就做完(两态的),没有“正在做”这样的概念。
2023-12-07 22:04:09
1890
原创 Linux篇:文件系统
文件的内容是有偏移量的!inode:inode结构体,包含单个文件的所有属性(inode number,文件类型,权限,引用计数,拥有者,所属组,ACM时间,int blocks[NUM]等),大小是128字节(一般而言,一个文件,一个inode)(文件文件名不在inode保存)。Group Descriptor Table(不会在每个组都存在):描述整个分组基本的使用情况:一共有多少个组,每个组的大小,每个组的inode数量,每个组的block数量,每个组的起始inode,文件系统的类型与名称等。
2023-11-26 20:05:48
2684
2
原创 Linux篇:文件管理
直接或者间接包含如下属性:在磁盘的位置,文件基本属性(权限,大小,读写位置,打开者),文件的内核缓冲区信息,struct file *next指针,引用计数count,文件描述符表,对应打开文件的缓冲区字段和维护信息。所以,只要拿着文件描述符,就可以找到对应的文件。程序替换并不影响文件访问!由此观之,文件描述符表的分配规则为:从0下标开始,寻找最小的没使用的数组位置,它的下标就是新文件的文件描述符。1、所有操作计算机的动作,都是以进程的形式进行操作的,所有访问文件的操作,最终都是由进程来访问文件的。
2023-11-25 13:11:14
1306
1
原创 Linux篇:进程控制
子进程main函数的返回值表征当前进程退出结果是否正确,此退出码将来会被父进程获取,通过该退出码决定子进程任务完成的好坏,如果执行失败,父进程则有其他策略。环境变量在不断给自己的每一个子进程下沉的时候,每一个子进程可以给自己定义put属于自己的环境变量,put后的环境变量会被后续的子进程再继承。wait调用会回收僵尸,释放内存泄露问题,wait调用,如果子进程不进行退出,Wait父进程也就不会返回,会一直等待,直到子进程退出。基本原理:新的可执行代码和数据,替换原先的代码和数据,并从零开始执行。
2023-11-08 01:20:01
277
2
原创 Linux篇:进程
3、任何一个进程,在加载到内存的时候,形成真正的进程时,操作系统要先创建描述进程(属性)的结构体对象PCB(process control block)---进程控制块(进程属性的集合)。②增加进程虚拟地址空间可以让我们访问内存的时候,增加一个转换的过程,在这个转化的过程中,可以对寻址记请求进行审查,所以一旦异常访问,直接拦截,该请求不会到达内存,保护物理内存。创建子进程PCB,填充PCB对应的内容,让子进程和父进程指向相同的代码,父子进程都是有独立的task struct,可以被CPU调度运行了。
2023-11-05 11:46:41
258
1
原创 C与C++的文件读写
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。sprintf:把格式化的数据,存放在(转换成)一个字符串。ferror-返回真,就说明是文件在读取过程中出错了,而结束。feof-返回真,就说明是文件正常读取到了结束标志而结束的。fseek:根据文件指针的位置和偏移量来定位文件指针。③格式化输入函数 fscanf(适用于所有输入流)stdout - 标准输出(屏幕)类型:FILE*rewind:让文件指针的位置回到文件的起始位置。
2023-10-21 12:35:25
172
原创 特殊类设计
一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。①构造函数私有化,在该类中声明,在类外定义一个自己类型的静态对象(不要直接定义一个该类的全局对象,因为类外面是调不了构造函数的)。1.同上将构造函数私有化,(但是不能将拷贝构造私有化,因为栈的传值返回需要调用拷贝构造)。①构造函数私有化,在该类中声明,在类外定义一个自己类型的静态对象指针并置空。2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建。
2023-10-17 20:07:09
192
2
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅