
算法的魔法世界
文章平均质量分 95
算法题精讲
手握风云-
[就读于河北科技大学]
[23级 软件工程专业]
[目标:拿到一个大厂offer]
展开
-
动态规划算法的欢乐密码(一):斐波那契数模型
当我们支付cost[i]向后走两步到达i+2位置时,再从i+2位置到达终点,花费为dp[i+2]+cost[n],所以递推公式为dp[i]=Math.min(dp[i+1],dp[i+2])+cost[i]。而题目也已经将前三个状态给了出来,dp[0]=0、dp[1]=1、dp[2]=1。接着利用之前的状态来推导dp[n]的值,根据最近的一步或者两步来划分问题:先到达dp[n]的前一个位置dp[n-1],然后支付cost[n-1]走一步,到达dp[n]花费为dp[n-1]+cost[n-1];原创 2025-04-19 20:48:26 · 1109 阅读 · 65 评论 -
巧用递归算法:破解编程难题的“秘密武器”
递归与循环一样,都是去执行相同的子问题,那么二者之间是可以相互转化的,那么我们什么时候用循环迭代效率更好,什么时候用递归效率更高。如下图所示,递归的细节展开图与二叉树的深搜极其相似。我们要想将递归转化为循环的话,就得借助栈来实现,因为当我们遍历一个子问题,我们需要保存上一个的信息方便调用方法执行右侧。但一个递归的细节展开图越复杂时,用递归就比较好解决;如果展开图只有一个分支,用循环迭代就比较方便。原创 2025-04-12 15:53:06 · 1446 阅读 · 67 评论 -
优选算法的妙思之流:分治——归并专题
如果p1所指的元素比p2所指的元素大,那么p1后面的元素就都是比p2大,就可以快速的统计出数目,然后再让p2++。找完右区域的逆序对,然后对右区域进行排序。方法2也同理,如果nums[p1]>= nums[p2],就让p1向右移动,直到nums[p1]<nums[p2],再让p2向右移动,p1同样不用回退。当我们在左右区域里面分别寻找逆序对时,如果数组长度较大,那么我们还可以再接着划分,继续按照上面的思路来找出逆序对的总数,这个部分就可以在递归中完成,所以我们在处理一左一右时也可以排个序。原创 2025-04-06 21:29:07 · 1654 阅读 · 60 评论 -
优选算法的妙思之流:分治——快排专题
接下来进行分类讨论:如果nums[i]=0,我们让nums[left+1]与nums[i]进行交换,然后i++,left++,就能保证[left+1,i-1]区间还都是1,还可能有一种极端情况,就是i=left+1,自身与自身进行交换,还是得需要left和i++,综上我们就可以写成nums[++left]与nums[i++]进行交换。第二种解法,利用大根堆,创建一个大小为k的大根堆,将数组的前k个元素丢进大根堆中,然后再将数组剩余的元素与堆顶元素比较,如果小就交换并调整堆,最后堆里面就是最小的k个数;原创 2025-04-05 00:02:43 · 1125 阅读 · 59 评论 -
优选算法的巧思之径:模拟专题
先初始化两个指针left和right,比较left和right是否相等,相等right就向右移动,当right的指向与left不相等时,right就停止,此时的left直接移动到right的位置。我们以示例1为例,先创建一个n行的矩阵,先向下填充,当x=n时,开始右上填充,当x=0时,又开始向下填充……如上图,k后面又是c,我们还需要给c记录上1,而我们要求的是所需不同青蛙的最少数目,所以我们从k里面借一个1,再去遍历最后一个"croak",最终k里面存的就是最终结果。当遍历到c时,哈希表中c加1。原创 2025-03-31 21:31:14 · 1429 阅读 · 65 评论 -
优选算法的慧根之翼:位运算专题
我们假设数组中出现三次的数字有n个,只出现一次的有1个,数组里的元素都是int类型的,我们从第0位开始遍历,让每一个数相同位数的比特位相加,那么它们的相加一共可以出现如下图4种情况。共包含6种&(按位与,有0就是0)、|(按位或有1就是1)、^(按位异或,相同为0,相异为1)、~(按位取反,0变成1,1变成0)、<<(左移)、>>(右移)。但我们需要注意的是,进位不是进到它本身这一位来,而是要进到左边这一位上来,所以我们还需要将按位与的结果左移1位,直到左移的结果为0。只需要将第x位修改为1,其他位不变。原创 2025-03-29 08:45:22 · 1390 阅读 · 34 评论 -
优选算法的睿智之林:前缀和专题(二)
我们先来回顾一下二位前缀和的计算:dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + mat[i][j]。如果我们要在预处理矩阵dp[x][y]里面里的值,我们需要在mat[x-1][y-1]的位置找,在answer[x+1][y+1]的位置填入。我们先来思考暴力枚举:利用双指针left和right,当right移动到某一个位置时,left与right构成的区间之和为k时,此时right不能停止,数组元素可能为负的,有可能后面还存在和为k的子数组。原创 2025-03-26 08:32:10 · 1191 阅读 · 38 评论 -
优选算法的睿智之林:前缀和专题(一)
A区域的和可以很好的算出来:dp[i-1][j-1],但是B、C区域的和又不好算了。我们需要求的是某段数组元素的和,那么就可以利用前缀和思想,i左侧的元素之和f(i) = f(i-1) + nums[i-1],i右侧的元素之和g(i) = g(i+1) + nums[i+1]。第一步,我们先预处理出一个前缀和数组int[] dp,dp[i]代表的是arr数组区间[1,i]的和。而数组dp中每一个元素的算法不用再从头加到尾,直接利用递推公式dp[i] = dp[i-1] + arr[i]。原创 2025-03-23 18:46:29 · 981 阅读 · 37 评论 -
优选算法的匠心之艺:二分查找专题(二)
通过上面的示例1,我们可以很明显地发现“二段性”,左边是严格大于某个值的递增区间,右边是严格小于某个值递增区间,并且数组中没有重复元素,折线表示如下图所示。从上图中我们已经可以看出,数组已经被分成两段,左边是递增的,右边是递减的,符合“二段性”,可以利用二分查找。我们注意一个细节:如果给定的数组为[0,1,2,3],数组元素与下标都是一一对应的,而缺失的数字为最后一个元素加一。在缺失的数字之前,数组元素与数组下标是一一对应的,到缺失的位置时,缺失的数字比数组元素小1。或者是递增的,或者是递减的。原创 2025-03-17 14:55:52 · 2015 阅读 · 54 评论 -
优选算法的匠心之艺:二分查找专题(一)
当x与目标值进行比较时,left可以移动到x右边,那么x的左边已经判断过了都是小于目标值,但右边还是未知的,即使left与right相遇,那这个数依然是未知的。right指针移动的时候,一直是在合法的区间,left一直想要跳出这个不合法的区间,直到两个指针相遇,无需判断,相遇的位置就是我们要找的结果。我们先来思考暴力解法:由于x是非负整数,那么x的平方根定义是小于等于x的。如果x=17,我们可以从1开始向右枚举,如果找到一个数n,n*n小于等于x,且(n+1)*(n+1)大于x,则x的平方根则为n。原创 2025-03-14 20:58:02 · 1214 阅读 · 53 评论 -
优选算法的智慧之光:滑动窗口专题(二)
只不过这次的count是统计字符的种类,因为在找字母异位词时,子串和字符串是一一对应的关系,这里字符却是大于等于的关系。我们看下图,我们从s中找出一段符合要求的子串,然后让left向后移动一步,此时会出现两种情况,要么缩小的区间还是符合要求,要么不符合要求,我们就让right向右移动,并且在这期间right是不需要回退的。我们还是先来思考一下暴力解法:先定义两个指针,我们以其中一个指针为起点,另一个指针向右移动,找到所有符合条件的子串,从里面挑出最短的长度。进窗口,把s中的字符串丢进哈希表中统计。原创 2025-03-03 23:06:35 · 6532 阅读 · 66 评论 -
优选算法的智慧之光:滑动窗口专题(一)
因为数组是具有单调性的,两个指针不用回退,就可以省去很多不必要的枚举,让子数组里的元素不停进出,维护更新子数组的和。是不需要的(如下图所示),right要么不动,要么向右移动,此时又符合同向双指针的解法,也就是可以使用滑动窗口。我们取出一段子数组,里面的水果种类kinds恰好为2,此时让left向右移动,会出现两种结果:kinds不变,right也不需要向右移动;“判断”,当子数组的和大于target时(这里不写等于,是为了防止代码书写混乱的),left指针向左移动,完成“出窗口”的操作;原创 2025-02-27 22:53:18 · 1932 阅读 · 56 评论 -
优选算法的灵动之章:双指针专题(二)
但此时还有一种特殊情况,如果复写之后最后一个元素为零,那么dest就会越界,所以我们还要单独处理一下边界,只需把倒数第二个元素直接复写成零,然后cur向前移动一位,dest向前移动两位。我们先对三元子数组进行去重,当我们left或者是right移动一位所指向的值不变,那么就继续移动,此时我们需要注意指针是否会越界。首先我们依然想到的是先排序,然后暴力枚举,利用三层for循环来判断三数之和是否为零,由于题目不要求输出的顺序和三元组的顺序,所以我们需要对三元组进行去重的操作,那么此时的时间复杂度就是。原创 2025-02-17 16:14:41 · 1284 阅读 · 46 评论 -
优选算法的灵动之章:双指针专题(一)
首先,我们得明白如何计算容器的体积,容器的底就可以用两个数组的下标相减得到,容器的高根据木桶效应是数组中最小的元素。我们先选左右边界来作为容器,此时我们记容器体积为v1,如果left指针向右移动,则容器的底一定在减小,如果遇到比左边界小的数,那么高就会减小,如果遇到比左边界大的数,那么高不变。此时我们就可以把左边界干掉,left向右移动,得到新的容器体积v2,根据上面的逻辑,我们同理可以把右边界干掉。然后通过sum与target的比较,如果sum小于target,则左指针向右移动;那么此时的时间复杂度为。原创 2025-02-03 15:14:32 · 12358 阅读 · 58 评论