- 博客(166)
- 问答 (1)
- 收藏
- 关注
原创 动态维护有效区间:单调栈
nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素。如果不存在下一个更大元素,那么本次查询的答案是 -1。
2025-09-07 23:42:35
228
原创 动态维护有效区间:滑动窗口
文章摘要: 本文介绍了使用滑动窗口算法解决有序数组去重问题的两种变体。第一种是删除所有重复项,保留唯一元素,通过双指针遍历数组,左指针标记唯一元素位置,右指针寻找新元素。第二种是允许元素最多出现两次,通过记录元素重复次数来控制保留数量。关键思路是:利用数组有序性,通过比较当前元素与已处理部分的特定位置(如前两位)来判断是否需要保留。文章详细演示了指针移动过程,并提供了Python代码实现,包括暴力解法和优化后的滑动窗口解法。对于进阶问题,提出了更简洁的判断条件,只需比较当前元素与有效数组倒数第二个元素即可决
2025-09-07 23:20:01
633
原创 动态规划:硬币兑换II
给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0。假设每一种面额的硬币有无限个。示例输入:amount = 5, coins = [1, 2, 5]输出:4解释:有四种方式可以凑成总金额:5=55=2+2+15=2+1+1+1。
2025-09-01 22:47:52
856
原创 动态规划:硬币兑换(续)
不固定某一面额,而是枚举所有可用面额作为 “组合的最后一枚硬币”,将原问题拆分为 “最后一枚是面额 A”“最后一枚是面额 B”“最后一枚是面额 C”…… 的多个互斥子集。每个子集的解决方案 =“剩余金额(总金额 - 该面额)的兑换方案 + 最后追加该面额”。fill:#333;color:#333;color:#333;fill:none;最后一枚为5元硬币最后一枚为2元硬币最后一枚为1元硬币最后一枚为5元最后一枚为2元最后一枚为1元最后一枚为5元最后一枚为2元最后一枚为1元。
2025-08-31 00:12:54
584
原创 动态规划:硬币兑换(有趣)
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。计算并返回可以凑成总金额所需的 最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。你可以认为每种硬币的数量是无限的。输入:coins = [1, 2, 5], amount = 11输出:3解释:11 = 5 + 5 + 1。
2025-08-27 23:05:31
717
原创 动态规划:青蛙跳台阶实践
我们按照最后一步是跳1阶还是跳2阶,将所有的方案划分成不重不漏的两个集合S(n−1)S(n-1)S(n−1)和S(n−2)S(n-2)S(n−2),两个集合方案数之和就是n阶的方案数。子集合 S(n−1)S(n-1)S(n−1)(最后一步跳 1 级):跳到第 5 级前,已先到第 4 级,对应 “跳到第 4 级的所有跳法”:子集合 S(n−2)S(n-2)S(n−2)(最后一步跳 2 级):跳到第 5 级前,已先到第 3 级,对应 “跳到第 3 级的所有跳法”:这个问题我们要求出方案数,而非具体的方案,因此有
2025-08-27 20:24:47
385
原创 动态规划:青蛙跳台阶
无论前面怎么跳,最后一步只能是 “跳 1 级” 或 “跳 2 级”,因此总跳法 =“最后一步跳 1 级的方案数”+“最后一步跳 2 级的方案数”。子集合 A(最后一步跳 1 级)1->2->3->4->5(最后 1 级:4→5)1->2->4->5(最后 1 级:4→5)1->3->4->5(最后 1 级:4→5)2->3->4->5(最后 1 级:4→5)2->4->5(最后 1 级:4→5)子集合 B(最后一步跳 2 级)1->2->3->5(最后 2 级:3→5)
2025-08-27 19:49:29
538
原创 动态规划:石子合并
含义:最后一步是将单独的a与[b,c,d,e]合并(左侧 1 堆,右侧 4 堆)。包含的所有方案的共同点:无论[b,c,d,e]内部如何合并(比如先合b&c,再合d&e等),最终都要和 a 做最后一次合并。含义:最后一步是将[a,b]的合并结果与[c,d,e]的合并结果合并(左侧 2 堆,右侧 3 堆)。[a,b]内部可以先合并(代价 a+b),[c,d,e]内部可以任意合并(比如先合 c&d 或 d&e),但最后一步必须是这两部分合并。含义:最后一步是将[a,b,c]的合并结果与。
2025-08-27 00:24:49
599
原创 动态规划:为什么暴力算法会有重复子问题
在算法中,“子问题” 不是泛指 “小一点的问题”,而是具有明确 “状态参数” 的、可独立求解的问题单元。状态参数:描述子问题核心信息的变量(比如 01 背包中的 “剩余物品范围” 和 “剩余背包容量”,斐波那契中的 “第 n 项”)。重复子问题:若两个子问题的 “所有状态参数完全相同”,则它们是重复子问题 —— 意味着这两个子问题的解完全一致,无需重复计算。枚举路径的冗余。
2025-08-26 22:09:10
871
原创 动态规划:入门思考篇
我不知道跳到第4的阶的方案是什么,也不知道跳到第3阶的方案是什么,但是按照第3阶和第4阶,我可以将跳到第5阶所有的方案分成不重合的两个集合,只要求出这两个集合的方案数,然后相加就是最后的方案数。假如我们要求全国人数,那么我们只要知道各个省的人数,然后将各个省的人数相加即可,要想知道各个省的人数,只要将这个省下面所有的市人数相加即可,同样,如果想要知道各个市的人数,只要知道下面所有县的人数即可。第一个集合的所有方案,最后一步必然经过第4阶台阶,第二个集合的所有方案,最后一步必然经过第3阶台阶。
2025-08-18 23:19:41
696
原创 双指针从简单到复杂
给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。一个简单直接的方法就是遍历数组,找到第一个为0的值,然后接着往后遍历找到第一个不为0的值,把这个非0值填充到0值的位置。核心思想就是,快指针不断遍历,找到符合条件的位置,然后将这个位置的值放的慢指针的地方(交换或覆盖),慢指针移动到下一个位置,等待被替换。相当于把所有 “有用” 的元素(不等于val的)依次 “搬运” 到数组的前面,而慢指针的位置正好对应新数组的长度。
2025-08-18 22:02:37
565
原创 Linux编译基础知识-在高版本系统中运行低版本二进制
仅指定 ld.so 路径无效的核心原因是:ld.so 的默认搜索路径是编译时固化的,它无法自动识别 sysroot 的存在,会固执地去系统默认路径找库。必须通过rpath、LD_LIBRARY_PATH或chroot等手段,为 ld.so “重写路径规则”,才能让它找到 sysroot 中匹配的旧版本 glibc 库。这本质上是解决 “编译时路径映射” 与 “运行时环境” 不匹配的问题。
2025-08-03 16:22:42
789
原创 linux编译基础知识-库文件标准路径
L指定的路径LIBRARY_PATH环境变量内置 SEARCH_DIR路径默认系统路径(/lib, /usr/lib)
2025-08-02 23:39:20
345
原创 linux编译基础知识-头文件标准路径
glibc(GNU C Library)的头文件与C++标准库头文件在Linux系统中的路径存在显著差异,主要源于其功能定位和编译器管理方式的不同。**3. 内核相关路径(开发板/嵌入式)**。- sys/mman.h:内存管理(如mmap)- sys/socket.h:套接字接口。- sys/time.h:时间操作函数。
2025-08-02 23:26:52
830
原创 linux编译基础知识-编译时路径和运行时路径
在 Linux 系统中,程序链接分为编译时链接(构建阶段)和运行时链接(执行阶段),两者路径设置相互独立。
2025-08-01 22:56:24
351
原创 linux编译基础知识-工具链
GNU(GNU’s Not Unix)是一个自由软件操作系统项目,其核心工具链和组件构成了现代Linux系统的基础;glibc(GNU C Library)则是GNU项目中C标准库的实现,为程序提供运行时支持。
2025-08-01 22:54:36
907
原创 C++ 编译链接机制的演化路径
以 完全问题驱动的方式 推导 C++ 编译链接机制的演化路径。每一步都基于前一阶段无法解决的问题,提出新的设计方案,不依赖当前 GCC 或 MSVC 的实现细节,而是像一个架构师一样,从零开始设计一个现代 C++ 系统。
2025-07-20 12:54:37
672
原创 c++重定义探究与思考
任何变量、函数、类、枚举、模板等实体在整个程序中必须有且仅有一个定义,且在不同翻译单元(Translation Unit, TU)中使用时,定义必须完全一致。违反 ODR 会导致未定义行为(UB)或链接错误。将会从简单的例子开始一直到上面那个让人困惑的问题,慢慢理解odr例如我们在同一个cpp文件中定义了int x = 1;int x = 2;执行编译的时候就会报错int x = 1;但是我们在不同的函数中定义相同的变量并不会有问题int x = 1;int x = 2;
2025-07-10 00:12:31
878
原创 gcc编译构建流程-函数未定义问题
我们有一个项目// add.h// add.cpp我们进行编译链接gcc -c main.cpp -o main.o # 编译main.cppgcc -c add.cpp -o add.o # 编译add.cppgcc main.o add.o -o main # 链接两个目标文件链接的时候就会报错,我们声明并且使用了add_v2函数,但是并没有实现链接器如何检测函数未实现?链接器扫描所有目标文件的重定位表 → 收集未解析符号 → 在符号表中匹配定义 → 若缺失则报错。
2025-06-02 15:19:29
987
原创 gcc符号表生成机制
编译阶段:每个源文件编译成目标文件,生成局部符号表。链接阶段:合并所有目标文件的段。合并符号表,进行符号解析(将未定义的符号绑定到定义的地方)。重定位:根据新的段布局修改符号引用的地址(利用重定位表)。输出可执行文件或共享库。通过这个流程,链接器确保了程序中的所有符号引用都有唯一的定义,并位于正确的地址。
2025-06-02 13:55:54
979
原创 gcc编译构建流程
上面的命令其实会报错,我们生成二进制时会将所有的目标文件.o合并成最终的可执行文件。gcc是编译c语言的,但是我们使用了std::cout这个函数,这个是c++语言的,在链接的时候gcc从c语言中找不到这个函数,所以报错。问题是为啥编译的时候(gcc -c)不会报错呢?gcc -c 的作用是生成目标文件(.o),仅执行预处理、编译和汇编,不进行链接。语法检查:GCC 检查代码的语法合法性(如括号匹配、分号缺失等)。
2025-05-25 21:35:51
902
原创 leetcode-快慢指针系列
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。仅仅是为了标识链表的实际情况。如果有环的话,那么兔子和乌龟都会进入环中。这时用「相对速度」思考,乌龟不动,兔子相对乌龟每次只走一步,这样就可以看出兔子一定会和乌龟相遇了。核心点就是当快慢指针相遇的时候,快指针的距离是慢指针的两倍。如果链表中存在环 ,则返回 true。给你一个链表的头节点 head ,判断链表中是否有环。
2025-05-23 22:41:07
495
原创 小白服务器开发-socket网络编程
它就像是一个两端分别连接着两个不同主机上进程的通信管道,屏蔽了网络通信底层的复杂细节,让程序员可以通过简单的 API(应用程序编程接口)来实现跨主机的进程间的数据传输,从而有效地解决了跨主机进程间通信的问题,满足了日益增长的网络应用需求,广泛应用于各种网络应用领域,如 web 服务器与浏览器之间的通信、即时通讯软件中的消息传递等场景。一切设置好之后,服务器就可以接客了,通过accept函数等待客户端的连接,如果有连接就返回客户端的地址,同时返回一个socket对象用来跟客户端交互。
2025-04-19 00:24:22
606
原创 条件变量,锁,共享数据的关系
条件变量、共享数据和锁之间的三方耦合关系源于多线程环境下对资源访问的同步需求。以下是关键点分析:条件变量中通常会对共享数据进行判断和处理,如果不加锁就会出现数据竞争的问题,所以并不是条件变量要跟锁一起使用,而是上锁为了保护共享数据,共享数据恰好在条件变量中,因此才会造成,条件变量,共享数据,锁的三方耦合。
2025-03-21 22:02:18
470
原创 c++多线程条件变量
只有在锁的保护下,条件变量才能正确地工作,并保证线程之间的数据可见性。如果消费者线程在检查队列是否为空的时候不使用锁保护,生产者线程可能会在消费者线程检查的中间过程插入数据,导致检查结果不准确。条件变量用于线程之间的通信和同步,当线程等待某个条件时,必须确保该条件的状态是被保护起来的。如果没有锁保护,在线程等待条件时,其他线程可能会修改条件相关的数据,导致数据不一致和竞争条件。通过互斥锁,可以确保这三步操作是原子的,即在多线程环境下,其他线程不能在步骤 2 和 3 之间修改条件相关的数据。
2025-03-16 12:36:57
404
原创 GCC头文件搜索顺序详解
在C/C++编程中,合理管理头文件的引入路径对于项目的组织至关重要。GCC编译器提供了灵活的机制来指定头文件的搜索路径,这主要通过#include "…"和#include <…>两种形式实现。本文将详细介绍这两种形式的区别以及如何使用-I参数优化头文件的搜索过程。
2025-02-20 00:19:29
1206
原创 推荐算法实践:movielens数据集
MovieLens 数据集是由明尼苏达大学的GroupLens研究小组维护的一个广泛使用的电影评分数据集,主要用于推荐系统的研究。该数据集包含用户对电影的评分、标签以及其他相关信息,是电影推荐系统开发与研究的常用数据源。
2025-02-11 22:24:36
2130
1
原创 c++面试:符号修饰
在C++中,名称修饰(Name Mangling)是一种将函数或变量的名称转换为唯一标识符的过程。它主要用于解决C++中的一些复杂特性,例如重载、类的作用域、模板等。
2025-02-08 22:44:55
997
1
原创 c++面试:类定义为什么可以放到头文件中
在C++中,定义和声明是两个不同的概念,它们各自有着明确的用途和含义。理解这两者的区别对于编写正确且高效的C++代码至关重要。声明是指向编译器告知某个变量、函数或类的存在及其类型,但并不分配实际的存储空间。声明的主要目的是让编译器知道如何解析程序中的符号引用。例如:// 声明一个名为a的整型变量,但不分配内存// 声明一个名为add的函数,但不提供实现// 前置声明,仅声明了MyClass的存在声明允许你在代码的一个部分提到某个实体,并在另一个部分提供其实现或定义。
2025-01-27 23:25:38
1363
2
原创 git基础操作
可以看到有4个区域,remote就是远程仓库,workspace则是本地可以编辑的代码分支, repository就是本地的仓库,存储者远程代码分支,也存储者本地代码分支。
2024-11-08 22:39:48
1744
原创 递归基础训练-路径总和
二叉树在递归的时候会遍历每一个节点,走完所有的路径,我们可以把之前遍历的节点信息放到path中传递下去,一直到叶子节点就拿到了所有的路径# 如果为None就直接返回,比如一个节点左孩子是None,右孩子非空return# 搜索路径就是根节点到叶子节点,直接打印路径# 可以return也可以不return,因为根节点的左右子树都是None# 继续往下执行就是左子树dfs(None),右子树dfs(None)# return。
2024-09-17 23:45:22
849
原创 这是啥设计模式-观察者模式
召回算法有很多个模型,这些模型使用的都是同一份特征数据进行训练,当训练数据有更新的时候就调用每一个算法的train方法进行训练,生成最新的模型。基本思路就是把这些模型都放到一个数组中,当数据集有更新的时候,就遍历所有的模型执行训练老实讲,我觉的这种方案已经可以了,但是有一个小问题,就是数据更新之后应该通知每个模型。
2024-08-20 22:10:38
528
原创 这是啥设计模式-单例模式
召回算法中有一个叫做I2I的召回方式,给定一个Item,返回跟这个Item相似的topK个Item,这种相似关系一般在离线就计算好了,以KV的方式存储下来我们使用的时候也加载成kv的格式就可以了。
2024-08-18 22:13:14
403
空空如也
tensorflow 数据读取,哪位帮我解释一下
2018-05-09
TA创建的收藏夹 TA关注的收藏夹
TA关注的人