
算法学习之路
文章平均质量分 77
程序=数据结构+算法
全天
被别人打败并不可怕,可怕的是被自己打败。
展开
-
动态规划——路径问题:174.地下城游戏
但是,如果当前位置的 dungeon[i][j] 是⼀个比较大的正数的话,dp[i][j] 的值可能变成 0 或者负数。因此我们求出来的 dp[i][j] 如果小于等于 0 的话,说明此时的最低初始值应该为 1。在本题中,在 dp 表最后面添加一行,并且添加⼀列后,所有的值都先初始化为INT_MAX,然后让 dp[m][n - 1] = dp[m - 1][n] = 1 即可。对于 dp[i][j] ,从 [i, j] 位置出发,下⼀步会有两种选择(为了方便理解,设 dp[i]根据最近的一步划分问题。原创 2024-05-16 23:46:06 · 943 阅读 · 0 评论 -
动态规划——路径问题:931.下降路径最小和
就行了,因此这⾥应该返回 dp 表中。原创 2024-05-08 22:38:08 · 1200 阅读 · 0 评论 -
BFS专题——FloodFill算法:200.岛屿数量
不少同学用广搜做这道题目的时候超时了。就是因为这里有一个广搜中很重要的细节:根本原因是只要加入队列就代表走过,就需要标记,而不是从队列拿出来的时候再去标记走过。:注意题目中每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。也就是说斜角是不算了, 例如示例二,是三个岛屿。如果从队列拿出节点,再去标记这个节点走过,就会发生这样的结果,会导致很多节点重复加入队列。这样,当我们,遍历完全部的矩阵的时候, ret 存的就是最终结果。很多同学可能说这有区别吗?遍历整个矩阵,每次找到。原创 2024-05-08 21:32:32 · 759 阅读 · 0 评论 -
动态规划——路径问题:LCR 166.珠宝的最高价值
根据最近的一步划分问题。dp[i][j] 表示:⾛到 [i, j] 位置处,此时珠宝的最大价值。,我们应该返回 dp[m][n] 的值。后,所有的值都为 0 即可。可以在最前⾯加上⼀个。原创 2024-05-07 20:24:23 · 606 阅读 · 1 评论 -
动态规划——路径问题:63.不同路径 ||
但是, [i - 1, j] 与 [i, j - 1] 位置都是可能有障碍的,此时从上⾯或者左边是不可能到达 [i, j] 位置的,也就是说,此时的⽅法数应该是 0。根据最近的一步划分问题。在本题中,添加⼀⾏,并且添加⼀列后,只需将 dp[1][0] 或者 dp[0][1] 的位置初始化为 1 即可。dp[i][j] 表示:⾛到 [i, j] 位置处,⼀共有多少种⽅式。,我们要返回的结果是 dp[m][n]。,那么我们就不需要计算这个位置上的。的推导,填表的顺序就是。原创 2024-05-07 10:00:52 · 1071 阅读 · 0 评论 -
动态规划——路径问题:62.不同路径
根据最近的一步,划分问题。dp[i][j] 表示:⾛到 [i, j] 位置处,⼀共有多少种⽅式。:这边注意一下不要搞错,因为到[i, j]看的是方法,到下一步不用加 1。后,只需将 dp[0][1] 的位置初始化为 1 即可。介绍,总共有两种初始化方法,本题可以在最前⾯加上⼀个。,我们要返回 dp[m][n] 的值。填每⼀⾏,在填写每⼀⾏的时候。的推导来看,填表的顺序就是。原创 2024-05-06 19:58:40 · 722 阅读 · 0 评论 -
动态规划——斐波那契数列模型:91.解码方法
解码成功:当结合的数在 [10, 26] 之间的时候,说明 [i - 1, i] 两个位置是可以解码成功的,那么此时 [0,i] 区间上的解码⽅法应该等于 [0, i - 2 ] 区间上的解码⽅法,原因同上。综上所述: dp[i]( dp[i] 默认初始化为 0 )最终的结果应该是上⾯四种情况下,解码成功的两种的累加和(因为我们关⼼的是解码⽅法,既然解码失败,就不⽤加⼊到最终结果中去),因此可以得到状态转移⽅程。dp[i] 表⽰:字符串中 [0,i] 区间上,⼀共有多少种编码⽅法。原创 2024-05-06 17:42:44 · 1145 阅读 · 0 评论 -
模块六:模拟——1419.数青蛙
当遇到 ‘r’ ‘o’ ‘a’ ‘k’ 这四个字符的时候,我们要去看看每⼀个字符对应的前驱字符,有没有⻘蛙叫出来。如果有⻘蛙叫出来,那就让这个⻘蛙接下来喊出来这个字符;如果没有,直接返回 -1;当遇到 ‘c’ 这个字符的时候,我们去看看 ‘k’ 这个字符有没有⻘蛙叫出来。如果有,就让这个⻘蛙继续去喊 ‘c’ 这个字符;如果没有的话,就重新搞⼀个⻘蛙。原创 2024-05-01 23:54:33 · 332 阅读 · 0 评论 -
模块四:前缀和——DP35 【模板】二维前缀和
类⽐于⼀维数组的形式,如果我们能处理出来从 [0, 0] 位置到 [i, j] 位置这⽚区域内所有元素的累加和,就可以在 O(1) 的时间内,搞定矩阵内任意区域内所有元素的累加和。sum[i][j] 的含义:sum[i][j] 表⽰,从 [0, 0] 位置到 [i, j] 位置这段区域内,所有元素的累加和。v. 如果把上⾯求的三个值加起来,那就是⻩ + 红 + 蓝 + 红 + 绿,发现多算了⼀部分红的⾯积,因此再单独减去红的⾯积即可;前缀和矩阵中 sum[i][j] 的含义,以及如何递推⼆维前缀和⽅程。原创 2024-04-28 22:28:58 · 863 阅读 · 0 评论 -
模块四:一维前缀和模板——DP34 【模板】前缀和
使用模拟,每次都遍历一遍数组求[l,r]区间的和,总共q次。:前缀和可以用来快速求出数组中某一连续区间的和。根据描述第一句可得数组长度应设为n + 1。为什么我们的下标要从1开始计数?原创 2024-04-27 23:40:33 · 524 阅读 · 0 评论 -
动态规划——斐波那契数列模型:746.使用最小花费爬楼梯
根据状态表⽰以及题⽬要求,需要返回 min(dp[0],dp[1]) 位置的值。用之前或之后的状态表示当前状态dp[i]的值,根据最近的一步,来划分问题。dp[i]表示以i台阶为结尾,也就是到达i台阶所需要的最小花费。dp[i]表示从i台阶开始,到达楼梯顶部所需要的花费最少是多少。根据状态表⽰以及题⽬要求,需要返回 dp[n] 位置的值。经验+题目要求,解法一中我们要用到的经验是以…根据示例来看,题目所说的楼梯顶部是数组的下一个位置。根据状态转移⽅程可得,遍历的顺序是从左往右。保证填表的时候不越界。原创 2024-04-27 19:57:21 · 655 阅读 · 1 评论 -
模块三:二分——LCR. 173.点名
这里有个细节问题是当答案为数组长度时,即只有两个数时,根据判断条件left会等于records[right],这个答案显然是错误的,所以需要处理一下。关于这道题中,时间复杂度为 O(N) 的解法有很多种,⽽且也是⽐较好想的,这⾥就不再赘述。本题只讲解⼀个最优的⼆分法和一个暴力版本,来解决这个问题。遍历一遍数组,寻找records[i]!= i的位置,返回下标i即可,循环结束还没有返回结果就是数组的长度了。因此,我们可以利⽤这个「⼆段性」,来使⽤「⼆分查找」算法。原创 2024-04-26 14:34:36 · 493 阅读 · 2 评论 -
模块三:二分——153.寻找旋转排序数组中的最小值
我们可以把数组划分成两部分,其中C点就是我们要的答案。通过图像我们可以发现, [A,B] 区间内的点都是严格⼤于 D 点的值的, C 点的值是严格⼩于 D 点的值的。但是当 [C,D] 区间只有⼀个元素的时候, C 点的值是可能等于 D 点的值的。:写这个解法的原因是因为我们最好想也最好写的解法就是暴力解法,经验不足的话都是靠暴力解法来做题的,搞懂了暴力解法之后,我们再去根据所学的算法和经验,借助画图,根据题目要求来优化我们的暴力解法,会让我们的基础比较扎实。答案放在解法二的C++代码部分解答。原创 2024-04-25 22:47:11 · 772 阅读 · 0 评论 -
模块三:二分——162.寻找峰值
根据题意,需要使用O(log N)的时间复杂度来解决,得出本道题可使用二分解决。当我们找到⼆段性的时候,就可以尝试⽤⼆分查找算法来解决问题。遍历一遍数组,寻找最大值即可。原创 2024-04-24 23:38:38 · 362 阅读 · 0 评论 -
模块三:二分——852.山脉数组的峰顶索引
遍历整个数组,寻找数组内符合这个条件的元素即可。峰顶:比左右区间都大。原创 2024-04-24 14:55:43 · 630 阅读 · 0 评论 -
模块三:二分——69.x的平方根
依次枚举 [0, x] 之间的所有数 i (这⾥没有必要研究是否枚举到 x / 2 还是 x / 2 + 1。因为我们找到结果之后直接就返回了,往后的情况就不会再判断。反⽽研究枚举区间,既耽误时间,⼜可能出错)由于 i * i 可能超过 int 的最⼤值,因此使⽤ long long 类型。因此可以使⽤⼆分查找算法。原创 2024-04-23 22:16:58 · 584 阅读 · 0 评论 -
模块三——二分:34.在排序数组中查找元素的第一个和最后一个位置
相信通过本模块的第一篇博客请⼤家⼀定不要觉得背下模板就能解决所有⼆分问题。⼆分问题最重要的就是要分析题意,然后确定要搜索的区间,根据分析问题来写出⼆分查找算法的代码。要分析题意,确定搜索区间,不要死记模板不要看左闭右开什么乱七⼋糟的题解。要分析题意,确定搜索区间,不要死记模板,不要看左闭右开什么乱七⼋糟的题解。要分析题意,确定搜索区间,不要死记模板,不要看左闭右开什么乱七⼋糟的题解。重要的事情说三遍。原创 2024-04-23 10:27:21 · 1194 阅读 · 0 评论 -
模块三——二分:704.二分查找
本系列博客是逐渐深入的过程,建议从零开始学习的友友不要跳过一些中间的博客。最恶心,细节最多,最容易写出死循环的算法。暴力解法是一次一次比较,但二分是利用了数组有序的特性,即二段性来通过比较一次来去掉多余的比较,所以暴力解法既然是正确的,那么二分也是正确的。原创 2024-04-22 21:29:17 · 1030 阅读 · 0 评论 -
BFS 专题 ——FloodFill算法:733.图像渲染
大家好啊,今天就正式开始我们的BFS专题了,觉得有用的朋友给个三连呗。中文:洪水灌溉举个例子,正数为凸起的山峰,负数为盆地,洪水冲过这片土地就会将这些具有相同性质的联通块(在本例中为盆地)灌溉。原创 2024-04-22 20:51:03 · 687 阅读 · 1 评论 -
动态规划——斐波那契数列模型:1137.第N个泰波那契数
首先我们要先确定一个状态表示。那第一次接触动态规划的同学可能就有些疑问了,什么是状态表示呢?通俗的来讲就是,我们会先定义一个dp表,这个dp表可能是一维数组或者二维数组,简单举例一下:我们做动态规划的流程就是搞一个dp表,然后把他填满,其中一个值可能就是我们的答案,状态表示指的就是dp表中的某个值它所代表的含义(感性理解)。如果我们去直接去百度动态规划的状态表示是什么的话,会出现一堆概念性的专有名词,要是没一两周根本搞不懂,而且会很痛苦,很容易放弃,所以刚开始学的时候我们有一个感性的认知就可以了。原创 2023-12-15 23:14:50 · 293 阅读 · 0 评论 -
模块二——滑动窗口:438.找到字符串中所有字母异位词
【代码】模块二——滑动窗口:438.找到字符串中所有字母异位词。原创 2023-12-14 22:59:54 · 302 阅读 · 0 评论 -
模块一:双指针——283.移动零
当nums[cur]==0时不处理,cur++,当遇到非零元素时,++dest,再交换nums[cur]和nums[dest],最后让cur++,重复以上步骤,直到cur走到n的位置。这样就保证了[0,dest]非0,[dest+1,cur-1]为0,[cur+1,n-1]为待处理区间,符合我们的性质。这道题其实可以归类到一类题里面——数组划分(数组分块),这不是官方的名字,是本人总结出来的。解决这类问题,我们第一个想到的就是双指针算法,在数组中,我们通常用数组下标来充当指针使用。原创 2023-11-19 15:01:25 · 196 阅读 · 0 评论 -
模块一:双指针——1089.复写零
在这个示例中,我们将第一个0都复写了一遍之后,将2和3都右移了一位,然后再复写了一个0,最后将4右移即完成复写,数组长度依然为8,且没有额外开空间,注意这个函数是不需要返回值的。首先我们先不管题目,再定义一个数组,让cur遍历原数组,遇到非0元素就抄下来,遇到0元素就抄两遍,抄完之后,cur++,dest++,直到cur==n完成复写。像这种在数组中操作数组元素的这类题目,我们一般也是用双指针算法来解决的,但是我们的双指针算法并不是凭空来的,而是。:这里我们需要寻找逆向复写的位置以及注意边界问题)原创 2023-12-08 08:49:15 · 84 阅读 · 0 评论 -
模块一——双指针:202.快乐数
根据上述的题⽬分析,我们可以知道,当重复执⾏x 的时候,数据会陷⼊到⼀个「循环」之中。⽽「快慢指针」有⼀个特性,就是在⼀个圆圈中,快指针总是会追上慢指针的,也就是说他们总会相遇在⼀个位置上。如果相遇位置的值是1 ,那么这个数⼀定是快乐数;由于上述两种情况只会出现⼀种,因此,只要我们能确定循环是在情况⼀中进行中,还是在情况二中进行,就能得到结果。b. 提取每⼀位的时候,⽤⼀个变量tmp 记录这⼀位的平⽅与之前提取位数的平⽅和。如何求⼀个数n每个位置上的数字的平⽅和。这⼀个操作记为x操作;原创 2023-12-10 20:39:09 · 248 阅读 · 0 评论 -
模块一——双指针:11.盛最多水的容器
设两指针left,right分别指向⽔槽板的最左端以及最右端,此时容器的宽度为right-left。由于容器的⾼度由两板中的短板决定,因此可得容积公式: v = (right-left) * min( height[left], height[right]).当我们不断重复上述过程,每次都可以舍去⼤量不必要的枚举过程,直到left 与right 相遇。期间产⽣的所有的容积⾥⾯的最⼤值,就是最终答案。由此可⻅,左边界和其余边界的组合情况都可以舍去。枚举出能构成的所有容器,找出其中容积最⼤的值。原创 2023-12-12 21:28:08 · 203 阅读 · 0 评论 -
模块一——双指针:611.有效三角形的个数
根据解法⼀中的优化思想,我们可以固定⼀个最⻓边,然后在⽐这条边⼩的有序数组中找出⼀个⼆元组,使这个⼆元组之和⼤于这个最⻓边。由于数组是有的,我们可以利⽤对撞指针来优化。此时right 位置的元素的所有情况相当于全部考虑完毕, right-- ,进⼊下⼀轮判断。三层for循环枚举出所有的三元组,并且判断是否能构成三⻆形。原创 2023-12-10 21:51:45 · 164 阅读 · 2 评论 -
模块一——双指针:LCR 179.查找总价格为目标值的两个商品
这⾥有个魔⻤细节,我们挑选第⼆个数的时候,可以不从第⼀个数开始选,因为a 前⾯的数我们都已经在之前考虑过了;因此,我们可以从a 往后的数开始列举。注意到本题是升序的数组,因此可以⽤「对撞指针」优化时间复杂度。两层for 循环列出所有两个数字的组合,判断是否等于⽬标值。原创 2023-12-13 21:02:17 · 209 阅读 · 0 评论 -
模块一——双指针:15.三数之和
本题与两数之和类似,是⾮常经典的⾯试题。与两数之和稍微不同的是,题⽬中要求找到所有不重复的三元组。但是要注意的是,这道题⾥⾯需要有去重操作~原创 2023-12-10 21:22:17 · 203 阅读 · 1 评论 -
模块一——双指针:18.四数之和
其中N是数组的长度。排序的时间复杂度是 O(NlogN),枚举四元组的时间复杂度是O(N。其中N是数组的长度。空间复杂度主要取决于排序额外使用的空间。此外排序修改了输入数组。,实际情况中不一定允许,因此也可以看成使用了一个额外的数组存储了数组。的副本并排序,空间复杂度为O(N)。),因此总时间复杂度为 O(N。原创 2023-12-13 21:41:12 · 334 阅读 · 0 评论 -
模块二——滑动窗口:209.长度最小的子数组
这边就可以判断一次是否sum>=target,是则更新记录,否则right++,进入下一个判断,我们可以发现left和right现在都是同向的且不会回退的,这就是我们要讲滑动窗口的含义。原创 2023-11-14 14:04:14 · 142 阅读 · 1 评论 -
模块二——滑动窗口:3.无重复字符的最长子串
在往后寻找⽆重复⼦串能到达的位置时,可以利⽤哈希表统计出字符出现的频次,来判断什么时候⼦串出现了重复元素。枚举从每⼀个位置开始往后,⽆重复字符的⼦串可以到达什么位置。找出其中⻓度最⼤的即可。研究的对象依旧是⼀段连续的区间,因此继续使⽤滑动窗⼝思想来优化。让滑动窗⼝满⾜:窗⼝内所有元素都是不重复的。原创 2023-12-12 22:45:53 · 219 阅读 · 0 评论 -
模块二——滑动窗口:1004.最大连续1的个数 |||
我们可以发现在暴力枚举中,我们每找到一个合法子数组都需要让right倒回到left++的位置,但这却是没有必要的,因为[left,right-1]这个区间已经是不超过k的最优子数组了,所以我们直接让right不动,让left越过一段区间,直到zero小于k。这道题直接做是很恶心的,因为你去枚举第一种情况就翻转一次,去枚举其他情况又要翻转回来,所以我们需要将直接枚举的方式等价处理为。二进制数组代表给我们的数组里面只有0和1,题目中的翻转其实我们看示例1可以得到是将0变成1的过程,这里最需要注意的就是。原创 2023-11-19 09:44:37 · 323 阅读 · 0 评论 -
模块二——滑动窗口:1658.将x减到0的最小操作数
初始化左右指针left = 0 ,right = 0 (滑动窗⼝区间表⽰为[left,right) ,左右区间是否开闭很重要,必须设定与代码⼀致),当target 0的最小操作次数并返回,否则返回-1。原创 2023-12-07 11:40:35 · 67 阅读 · 0 评论 -
模块二——滑动窗口:904.水果成篮
转化问题:寻找最长的一段只有两种水果的连续的子数组,并返回它的长度。原创 2023-12-09 13:32:44 · 116 阅读 · 1 评论