- 博客(93)
- 收藏
- 关注
原创 【动态规划七】背包问题
1049. 最后一块石头的重量 II - 力扣(LeetCode)1.题目解析之前我们已经在博客中讲解了"最后一块石头的重量 I", 每次选两块最重的石头,而本题每次随机选两个石头进行碰撞,如果最后还剩余了一块石头,那么求最终剩余石头的最小重量,如果没有剩余石头,那么返回02.算法分析本题的难点仍然在于如何把原问题进行转化,假设给定的数组元素是[a, b, c, d, e]每次随机选两个石头进行碰撞, 可以发现最终结果无非是给原始数组元素添加上正负号,使得最终。
2024-05-24 11:45:55
709
原创 【动态规划六】两个数组的dp问题
上图是根据最后一个位置的状态划分问题得到的状态转移方程,但显然p[j]=='*'时,还需要一层for循环求解, 因此时间复杂度是O(N^3), 因此我们可以进一步优化, 将p[j]=='*'时的状态转移方程用若干个有限的状态表示。dp[i][j]: s1中 [1, i] 区间内的字符串以及 s2[1, j] 区间内的字符串,能拼接成 s3[1, i+j] 区间内的字符串。这两个字符串就是可以匹配的,让第二个字符串的'*'匹配空串,'a'匹配'a', '*'匹配"bcde", 'f'匹配'f'即可。
2024-05-20 08:35:19
1027
原创 【动态规划五】回文串问题
将dp表里面所有的值都初始化成1, 因此dp[i] += dp[i-1] 即可。如果是暴力解法,只需要先固定下标i, 然后j从i的位置开始往后一路枚举即可,下一次i++, j无需回到0号下标,因为[i, j]与[j, i]本质是同一个子串,j直接从i位置开始枚举即可, 因此我们就把状态表示定义成二维的~s[i] == s[j]时,i + 1 == j 的情况可以合并到 i + 1 > j的情况中,因为i + 1 > j 时用到的dp[i+1][j-1]本质是下三角元素,直接等于0,不影响结果的正确性。
2024-05-15 22:40:10
664
原创 用红黑树封装出map与set
map与set的底层都是红黑树,所以本篇文章就分享如何用同一颗红黑树封装出map与set上述迭代器的实现很多与list模拟实现是一样的:关键的地方在于迭代器++与迭代器--如何实现,由于map/set的遍历是中序遍历,因此迭代器++的本质就是要找二叉树中序遍历过程中当前节点的下一个节点, 而中序遍历的顺序是: 左子树 根 右子树,
2024-05-15 19:49:17
667
原创 优先级队列(堆)
1046. 最后一块石头的重量 - 力扣(LeetCode)1.题目解析每次选取最重的两块石头,两两碰撞,重量小的粉碎,重量大的石头剩余重量为原始重量-重量小的石头的重量,最终如果剩一块石头,就返回该石头的重量;如果没有剩石头,就返回02.算法分析用堆(优先级队列) 模拟即可3.算法代码public://默认大堆heap.pop();heap.pop();
2024-05-14 17:32:23
990
原创 【动态规划四】子序列问题
给定一个数组,数组每个元素是一个数对[left, right], left 是严格 < right 的,[a, b], [c, d], [e, f]要能构成数对链,要求b < c, d < e, 求能构成的最长数对链的长度。ps:开始是定义的dp[i], 但是推不出状态转移方程, 因为只知道子序列的个数,但是无法确定具体的斐波那契式的子序列,也就无法根据dp[i]前面的值推导出dp[i]~dp[i][j]:以 i 位置 以及 j 位置 为结尾的所有子序列中,最长的等差序列的长度。
2024-05-13 09:40:02
977
原创 队列 + 宽搜(BFS)
二叉树根节点从1开始编号,创建一个队列,队列中存储的是<节点指针,节点编号>, 如果算上空节点的话那么二叉树就是满的,所以如果某个节点编号是x,那么左孩子节点编号是2*x, 右孩子节点编号是2*x+1, 每一层的长度就是 最右节点编号 - 最左节点编号 + 1, 而我们可以直接用vector来模拟队列~树的层序遍历是典型要用到队列的场景,因为上一层遍历完之后,遍历下一层是从左到右,也就是要先遍历上一层最左节点的孩子,因此符合先进先出的原则,采用队列!102. 二叉树的层序遍历 - 力扣(LeetCode)
2024-05-11 17:34:00
928
原创 【动态规划三】子数组系列
f[i]:以 i 位置为结尾的所有子数组中,最后呈现 "上升" 状态下的最长的湍流子数组的长度。g[i]:以 i 位置为结尾的所有子数组中,最后呈现 "下降" 状态下的最长的湍流子数组的长度。数组中相邻元素对之间的大小关系相反,这就是湍流数组,题目要求返回数组中最长的湍流子数组的长度。将dp表里面所有的值都初始化成1, 因此dp[i] += dp[i-1] 即可。dp[i]: [0, i]区间内的字符串, 能否被字典中的单词拼接而成。dp[i] 表示 以 i 位置元素为结尾的所有子数组的最大和。
2024-05-07 09:38:31
842
1
原创 【算法系列】栈
目录leetcode题目一、删除字符串中的所有相邻重复项二、比较含退格的字符串三、基本计算器 II四、字符串解码五、验证栈序列六、有效的括号七、最小栈八、逆波兰表达式求值九、用栈实现队列十、用队列实现栈1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode)https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string/1.题目解析2.算法分析显然该题是要用栈,遍历字符串,当遍历到的元素和栈顶元素一样时,就让栈顶元素出
2024-05-05 20:31:45
381
原创 【动态规划二】简单多状态dp问题
【动态规划一】斐波拉契数列模型 && 路径问题-CSDN博客状态表示是指dp表(一维数组/二维数组)里面的值所表示的含义如何得到状态表示?1.1 题目要求1.2 经验 + 题目要求1.3 分析问题的过程中,发现重复子问题。面试题 17.16. 按摩师 - 力扣(LeetCode)给定一个数组,数组元素表示预约时间,不能选择数组相邻元素,求最长的预约时长dp[i]: 选择到 i 位置的时候,此时的最长预约时长--->i位置可以选,可以不选,进一步细化。
2024-05-04 17:31:20
897
原创 【算法系列】字符串
字符串最后一个单词的长度_牛客题霸_牛客网 (nowcoder.com)1.题目解析字符串中的单词以空格分割,求出字符串最后一个单词的长度2.算法分析直接调用string类的接口rfind, 从右向左找到第一个空格位置pos即可,用字符串总长度-pos-13.算法代码int main()string s;return 0;
2024-05-03 19:07:10
1201
1
原创 【动态规划一】斐波拉契数列模型 && 路径问题
状态表示是指dp表(一维数组/二维数组)里面的值所表示的含义如何得到状态表示?1.1 题目要求1.2 经验 + 题目要求1.3 分析问题的过程中,发现重复子问题。
2024-05-02 15:48:30
650
原创 【算法系列】哈希表
1.存储数据的容器2.需要快速查找数据时,用哈希表3.当题目中给定的字符串或者数组只包含小写字母或数据范围是0~100/1000等等时,可以用数组模拟哈希表4.当数据范围是负数到正数时,不建议用数组模拟哈希表,因为还要加一个数转化之后进行映射,建议直接使用STL容器leetcode题目一、两数之和1. 两数之和 - 力扣(LeetCode)1.题目解析给定数组与target, 返回和为target的两个元素下标2.算法分析解法一: 暴力枚举。
2024-05-01 19:29:35
729
1
原创 【算法系列】链表
如上图所示,要将cur插入到两个节点之间,那么①与②的顺序就不能颠倒,但是如果定义了一个指针变量next,就完全不用考虑链接顺序了!①②③④可以任意颠倒~
2024-04-30 21:11:36
783
1
原创 分治策略 --- 快排&&归并
此时如果nums[cur1] > nums[cur2], 说明cur1连同cur1之前的左区间元素都比nums[cur2]大, 此时如果统计了逆序对数量,cur1++之后来到下一个位置,此时nums[cur1]依旧可能 > nums[cur2], 还要统计逆序对数量,就会重复计算!ps: 由合并两个有序数组的逻辑知,哪个指针指向的元素小,就让哪个指针++, 因此[left, cur1-1]区间的所有值都比nums[cur2]小~215. 数组中的第K个最大元素 - 力扣(LeetCode)
2024-04-28 23:12:49
736
原创 【算法系列】模拟
给定一个数组,数组每个元素表示发起攻击(被攻击后会中毒)的时间,给定一个整数,表示中毒的时长,如果中毒还没有结束,就发起下次攻击,那么中毒时间被重置!2.遇到c字符,找最后一个字符(本题是k字符)在哈希表是否存在,存在则最后一个字符个数--,当前字符++, 不存在则当前字符++1.遇到r/o/a/k字符,在哈希表中找一下前驱字符,如果存在,前驱个数--, 当前字符++, 不存在,则返回-1。最后还要检查记录字符出现个数的哈希表情况,如果前n-1个字符中有个数不为0的字符,也要返回-1。
2024-04-28 13:20:09
869
原创 前缀和算法
如果题目要求的是 arr数组 [l, r] 的和, 那么我们可以间接求,用[1, r]区间的和 减去 [1, l-1]区间的和求实[l, r]区间的和, 而[1, r]区间的和是dp[r], [1, l-1]的和是 dp[l-1], 而dp数组我们已经预处理好了,因此求和只需要O(1)的时间复杂度。如果从1开始计数,求的是[1, 2]区间的和, 那么 结果就是 dp[2] - dp[0], 在预处理数组时只需要让dp[0] = 0 即可, 求出来的就是dp[2],也就是[1, 2]区间的和。
2024-04-24 23:29:49
566
原创 二分查找算法
34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)1.题目解析1.数组中存在要查找的值,返回该值的起始下标和结束下标(因为该值可能不止一个)2.不存在要查找的值,返回[-1, -1]3.数组为空,返回[-1, -1]2.算法分析2.1 暴力解法: 从前向后遍历一遍,记录起始下标和结尾下标~
2024-04-23 22:20:46
710
原创 双指针算法
目录题目类型leetcode题目:一、移动零二、复写零 三、快乐数四、 盛最多水的容器五、有效三角形的个数 六、查找总价格为目标值的两个商品七、三数之和八、四数之和 题目如果要求是根据某个标准,对数组进行划分/分块,将数组可以分为几个部分,此时就可以采用双指针算法! 双指针算法不一定非要用指针,下标也可以充当指针! 链表题目也经常会用到双指针,比如求链表的中间节点,求链表的倒数第k个节点,判断链表是否有环,求链表的入环节点,相交链表等等。。。 其他应用双指针算法的题
2024-04-20 16:19:18
773
原创 实现AVL树
注意:我们下面实现的AVL树,实现的是kv模型,也就是存储key值和对应的value值, 模拟map//三叉链//方便进行AVL树进行调平//存储键值对int _bf;//平衡因子(balance factor), _kv(kv),_bf(0){}
2024-04-14 22:12:42
622
原创 搜索二叉树
也就是以要删除的节点为根节点,找左子树的最右节点(subRight)或者右子树的最左节点(subLeft),然后将要删除的节点值和subRight或subLeft的值进行交换,于是就转化成了删除只有1个孩子的节点的问题。这里重点体会参数root给引用的妙处,当最后的root是nullptr时,同时也是父节点的左指针或右指针的别名,所以root = new Node(key) 直接就把新开辟的节点和父节点链接起来了!由于删除后要保证仍然是搜索二叉树,因此我们使用。要删除的结点是叶子节点,没有左右孩子。
2024-04-10 10:59:06
1054
原创 C++多态
子类对象拷贝给父类对象,会将子类对象中父类对象的那部分拿出来拷贝给子类对象,但不会拷贝虚表指针, 因为如果拷贝了虚表指针,父类对象中保存的虚函数表指针指向的就不是父类的虚函数表了,此时父类的指针/引用指向/引用父类对象,调用的就不是父类的虚函数了,就无法保证多态了~如上图所示,父类对象和子类对象中的虚函数指针是不同的,指向的也是两张不同的虚表,而BuyTicket()虚函数我们进行了重写,func()虚函数没有进行重写,因此两张表中BuyTicket()地址不同,而func()的地址是一样的!
2024-04-09 09:00:10
995
原创 字符串匹配算法之BF与KMP算法
如果子串中,有大量的重复元素时,next数组就可以优化,因为假设6号下标匹配失败,回退到next[6]也就是5号下标, 此时字符仍然是'a', 依旧会匹配失败,还需要继续回退!子串的第一个位置和第二个位置匹配失败时,该位置之前绝不可能用公共子串,所以next[0]和next[1]都应该是0, 但是为了方便后续代码处理,我们将next[0]置成-1。我们现在已经明白了next数组的做用和求法,但问题是上面的next数组是我们肉眼观察求得的,可是计算机并没有上帝视角,如何编程求得next数组呢?
2024-04-08 22:34:21
751
原创 C++继承
1. 继承允许你根据基类的实现来定义派生类的实现。这种通过生成派生类的复用通常被称 为白箱复用(white-box reuse)。术语“白箱”是相对可视性而言:在继承方式中,基类的 内部细节对子类可见。继承一定程度破坏了基类的封装,基类的改变,对派生类有很 大的影响。派生类和基类间的依赖关系很强,耦合度高。2. 对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象 来获得。对象组合要求被组合的对象具有良好定义的接口。
2024-04-06 18:04:43
790
1
原创 stack 与 queue 与 priority_queue 与 仿函数 与 模板进阶
【优点】1.模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生2.增强了代码的灵活性【缺陷】1.模板会导致代码膨胀问题,也会导致编译时间变长2.出现模板编译错误时,错误信息非常凌乱,不易定位错误。
2024-04-05 18:48:48
858
原创 list使用与模拟实现
/每个节点的类型T _data;:_data(x){}非const迭代器的实现之前讲解的string与vector的迭代器都是原生指针,而list的迭代器不是原生指针,主要原因是因为list的底层是双向链表,如果用原生指针++,是无法到下一个节点的;直接解引用拿到的也不是具体的数据,而是整个节点对象;而迭代器的访问与遍历方式都是类似的,都是++, 解引用,判断!=, 所以我们只需要把list的迭代器设计成类,在类中对原生指针做封装。
2024-04-02 23:46:06
1717
原创 vector模拟实现
vector是动态增长的顺序表,可以理解为动态数组;vector的用法与string基本类似,此处就不详细介绍了,具体用法可以参考网站:,本篇博客直接开始模拟实现!vector模拟实现与string不同的地方:1. 模拟实现string时采用成员变量是_str, _size, _capacity, 而STL原码实现vector采用的成员变量是 _start, _finish, _endofstorage, 本质是一样的!
2024-04-01 20:04:05
970
原创 进程控制(二) 进程等待与进程替换
这些都是程序替换的函数,都封装了execve这个系统调用!!之所以设计这么多接口是为了满足各种调用的场景!任何程序替换函数都要解决两个问题:a.必须先站到这个可执行程序b.必须告诉exec*,怎么执行file:文件名,p: PATH, 表示execlp会自动的去环境变量PATH中根据file去寻找可执行程序!v表示vector, 是数组的意思,除了可变参数接收选项之外,argv[ ]指针数组也可以存放选项!
2024-03-09 10:17:31
807
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人