自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(74)
  • 收藏
  • 关注

原创 面试冲刺 - 算法题 1

对于循环的圈数 loop = (n / 2):意思是:如果转一圈,左右都会少一条边,整个正方形的宽度减2,一共宽度是n,每次减2,就是循环n/2次。

2023-12-06 09:12:19 212

原创 代码随想录算法训练营第六十天丨 单调栈03

如果数组本身是降序的,例如 [8,6,4,2],在 8 入栈后,6 开始与8 进行比较,此时我们得到 mid(8),rigt(6),但是得不到 left。如果数组本身就是升序的,例如[2,4,6,8],那么入栈之后 都是单调递减,一直都没有走 情况三 计算结果的哪一步,所以最后输出的就是0了。那么因为本题是要找每个柱子左右两边第一个小于该柱子的柱子,所以从栈头(元素从栈头弹出)到栈底的顺序应该是从大到小的顺序!因为 将 8 弹出之后,栈里没有元素了,那么为了避免空栈取值,直接跳过了计算结果的逻辑。

2023-11-21 08:11:06 316

原创 代码随想录算法训练营第五十九天丨 单调栈02

因为一旦发现添加的柱子高度大于栈头元素了,此时就出现凹槽了,栈头元素就是凹槽底部的柱子,栈头第二个元素就是凹槽左边的柱子,而添加的元素就是凹槽右边的柱子。取栈顶元素,将栈顶元素弹出,这个就是凹槽的底部,也就是中间位置,下标记为mid,对应的高度为height[mid](就是图中的高度1)。如果当前遍历的元素(柱子)高度等于栈顶元素的高度,要跟更新栈顶元素,因为遇到相相同高度的柱子,需要使用最右边的柱子来计算宽度。遇到相同的元素,更新栈内下标,就是将栈里元素(旧下标)弹出,将新元素(新下标)加入栈中。

2023-11-20 11:55:27 180

原创 代码随想录算法训练营第五十八天丨 单调栈01

加入T[4],T[4] == T[3] (当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况),此时依然要加入栈,不用计算距离,因为我们要求的是右面第一个大于本元素的位置,而不是大于等于!我们要保持一个递增单调栈(从栈头到栈底),所以将T[0]弹出,T[1]加入,此时result数组可以记录了,result[0] = 1,即T[0]右面第一个比T[0]大的元素是T[1]。加入T[1] = 74,因为T[1] > T[0](当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况)。

2023-11-18 08:53:14 249

原创 代码随想录算法训练营第五十七天丨 动态规划part17

动规五部曲:如果大家做了很多这种子序列相关的题目,在定义dp数组的时候 很自然就会想题目求什么,我们就如何定义dp数组。绝大多数题目确实是这样,不过本题如果我们定义,dp[i] 为 下标i结尾的字符串有 dp[i]个回文串的话,我们会发现很难找到递归关系。dp[i] 和 dp[i-1] ,dp[i + 1] 看上去都没啥关系。所以我们要看回文串的性质。 如图:我们在判断字符串S是否是回文,那么如果我们知道 s[1],s[2],s[3] 这个子串是回文的,那么只需要比较 s[0]和s[4]这两个元素是否相同,

2023-11-17 08:43:01 225

原创 代码随想录算法训练营第五十五天丨 动态规划part16

那最后当然是取最小值,所以当word1[i - 1] 与 word2[j - 1]不相同的时候,递推公式:dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1});因为 dp[i][j - 1] + 1 = dp[i - 1][j - 1] + 2,所以递推公式可简化为:dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);

2023-11-16 08:37:38 122

原创 代码随想录算法训练营第五十四天丨 动态规划part15

t[j - 1]),此时相当于t要删除元素,t如果把当前元素t[j - 1]删除,那么dp[i][j] 的数值就是 看s[i - 1]与 t[j - 2]的比较结果了,即:dp[i][j] = dp[i][j - 1];其实这里 大家可以发现和。

2023-11-15 08:18:31 93

原创 代码随想录算法训练营第五十三天丨 动态规划part14

而是dp[6]。在回顾一下dp[i]的定义:包括下标i之前的最大连续子序列和为dp[i]。那么我们要找最大的连续子序列,就应该找每一个i为终点的连续最大子序列。所以在递推公式的时候,可以直接选出最大的dp[i]。

2023-11-14 08:33:19 151

原创 代码随想录算法训练营第五十天丨 动态规划part13

本题最关键的是要想到dp[i]由哪些状态可以推出来,并取最大值,那么很自然就能想到递推公式:dp[i] = max(dp[i], dp[j] + 1);

2023-11-13 11:10:37 278

原创 代码随想录算法训练营第四十九天丨 动态规划part12

这次把冷冻期这道题目,讲的很透彻了,细分为四个状态,其状态转移也十分清晰,建议大家都按照四个状态来分析,如果只划分三个状态确实很容易给自己绕进去。

2023-11-12 11:20:30 399

原创 代码随想录算法训练营第四十八天丨 动态规划part11

一定是选最大的,所以 dp[i][1] = max(dp[i-1][0] - prices[i], dp[i - 1][1]);选最大的,所以 dp[i][1] = max(dp[i - 1][0] - prices[i], dp[i - 1][1]);所以dp[i][2] = max(dp[i - 1][1] + prices[i], dp[i - 1][2])那么dp[i][1]究竟选 dp[i-1][0] - prices[i],还是dp[i - 1][1]呢?此时还没有买入,怎么就卖出呢?

2023-11-12 09:15:41 114

原创 代码随想录算法训练营第四十七天丨 动态规划part10

由递推公式 dp[i][0] = max(dp[i - 1][0], -prices[i]);和 dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);同样dp[i][1]取最大的,dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);那么dp[i][0]应该选所得现金最大的,所以dp[i][0] = max(dp[i - 1][0], -prices[i]);

2023-11-10 16:08:16 211 1

原创 代码随想录算法训练营第四十六天丨 动态规划part09

打家劫舍是DP解决的经典题目,这道题也是打家劫舍入门级题目,后面我们还会变种方式来打劫的。成环之后还是难了一些的, 不少题解没有把“考虑房间”和“偷房间”说清楚。这就导致会有这样的困惑:情况三怎么就包含了情况一了呢?本文图中最后一间房不能偷啊,偷了一定不是最优结果。所以我在本文重点强调了情况一二三是“考虑”的范围,而具体房间偷与不偷交给递推公式去抉择。这样大家就不难理解情况二和情况三包含了情况一了。这道题是树形DP的入门题目.所以树形DP也没有那么神秘!

2023-11-08 12:49:14 198 1

原创 代码随想录算法训练营第四十五天丨 动态规划part08

多重背包在面试中基本不会出现,力扣上也没有对应的题目,大家对多重背包的掌握程度知道它是一种01背包,并能在01背包的基础上写出对应代码就可以了。听说背包问题很难?这篇总结篇来拯救你了。

2023-11-07 19:27:29 143

原创 代码随想录算法训练营第四十四天丨 动态规划part07

凑足总额为j - coins[i]的最少个数为dp[j - coins[i]],那么只需要加上一个钱币coins[i]即dp[j - coins[i]] + 1就是dp[j](考虑coins[i])既然递归公式是 dp[i] += dp[i - j],那么dp[0] 一定为1,dp[0]是递归中一切数值的基础所在,如果dp[0]是0的话,其他数值都是0了。本题呢,dp[i]有几种来源,dp[i - 1],dp[i - 2],dp[i - 3] 等等,即:dp[i - j]所以遍历的内循环是正序。

2023-11-06 20:09:13 176

原创 代码随想录算法训练营第四十三天丨 动态规划part06

dp[0]=1还说明了一种情况:如果正好选了coins[i]后,也就是j-coins[i] == 0的情况表示这个硬币刚好能选,此时dp[0]为1表示只选coins[i]存在这样的一种选法。因为递推公式dp[i] += dp[i - nums[j]]的缘故,dp[0]要初始化为1,这样递归其他dp[i]的时候才会有数值基础。下标非0的dp[j]初始化为0,这样累计加dp[j - coins[i]]的时候才不会影响真正的dp[j]初始化为0,这样才不会影响dp[i]累加所有的dp[i - nums[j]]。

2023-11-04 09:17:06 149

原创 代码随想录算法训练营第四十二天丨 动态规划part05

本题其实就是尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小,这样就化解成01背包问题了。感觉和昨天讲解的416. 分割等和子集 (opens new window)非常像了。本题物品的重量为 stones[i],物品的价值也为 stones[i]。对应着01背包里的物品重量 weight[i]和 物品价值 value[i]。确定dp数组以及下标的含义dp[j]表示容量(这里说容量更形象,其实就是重量)为j的背包,最多可以背最大重量为dp[j]。

2023-11-03 21:33:27 191

原创 代码随想录算法训练营第四十一天丨 动态规划part04

那么如果背包容量为target, dp[target]就是装满 背包之后的重量,所以 当 dp[target] == target 的时候,背包就装满了。01背包的递推公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);所以递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);01背包中,dp[j] 表示: 容量为j的背包,所背的物品价值最大可以为dp[j]。在01背包,一维dp如何初始化,已经讲过,

2023-11-02 08:56:02 175

原创 代码随想录算法训练营第四十天丨 动态规划part03

那么从1遍历j,比较(i - j) * j和dp[i - j] * j 取最大的。从递归公式上来讲,dp[以j为头结点左子树节点数量] * dp[以j为头结点右子树节点数量] 中以j为头结点左子树节点数量为0,也需要dp[以j为头结点左子树节点数量] = 1, 否则乘法的结果就都变成0了。j的结束条件是 j < i - 1 ,其实 j < i 也是可以的,不过可以节省一步,例如让j = i - 1,的话,其实在 j = 1的时候,这一步就已经拆出来了,重复计算,所以 j < i - 1。

2023-11-01 08:20:08 122

原创 长沙某公司面经总结 - 失败版

static是静态修饰符,一般用来修饰类中的成员。方便在没有创建对象的情况下来进行调用。static关键字修饰类(只能修饰内部类)// static关键字修饰内部类System.out.println("=======静态内部类=======");System.out.println("========静态内部方法========");​// 直接通过statictest类名来访问静态内部类// 静态内部类可以和普通类一样使用结果 :=======静态内部类=======

2023-10-31 20:48:55 139

原创 代码随想录算法训练营第三十九天丨 动态规划part02

从递归公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 中可以看出,一定是从左到右一层一层遍历,这样保证推导dp[i][j]的时候,dp[i - 1][j] 和 dp[i][j - 1]一定是有数值。那么很自然,dp[i][j] = dp[i - 1][j] + dp[i][j - 1],因为dp[i][j]只有这两个方向过来。这样就可以保证推导dp[i][j]的时候,dp[i - 1][j] 和 dp[i][j - 1]一定是有数值的。下标(0, j)的初始化情况同理。

2023-10-31 08:25:12 121

原创 代码随想录算法训练营第三十八天丨 动态规划part01

简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的,在关于贪心算法,你该了解这些!中卡哥举了一个背包问题的例子。例如:有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i]。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

2023-10-30 11:35:50 147

原创 代码随想录算法训练营第三十五天丨 贪心算法part06

本题只要想清楚个例,例如98,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]减一,strNum[i]赋值9,这样这个整数就是89。就可以很自然想到对应的贪心解法了。想到了贪心,还要考虑遍历顺序,只有从后向前遍历才能重复利用上次比较的结果。最后代码实现的时候,也需要一些技巧,例如用一个flag来标记从哪里开始赋值9。

2023-10-28 08:57:37 126

原创 代码随想录算法训练营第三十四天丨 贪心算法part05

本题其实和昨天做的 ‘

2023-10-27 09:56:45 61

原创 代码随想录算法训练营第三十三天丨 贪心算法part04

局部最优可推出全局最优,找不出反例,那就试试贪心。怎么知道局部最优就可以推出全局最优呢?有数学证明么?在贪心系列开篇词。

2023-10-26 09:01:19 223 1

原创 代码随想录算法训练营第三十二天丨 贪心算法part03

如果 ratings[i] > ratings[i + 1],此时num[i](第i个小孩的糖果数量)就有两个选择了,一个是num[i + 1] + 1(从右边这个加1得到的糖果数量),一个是num[i](之前比较右孩子大于左孩子得到的糖果数量)。如果 ratings[i] > ratings[i - 1] 那么[i]的糖 一定要比[i - 1]的糖多一个,所以贪心:num[i] = num[i - 1] + 1。所以就取 num[i + 1] + 1 和 num[i] 最大的糖果数量,

2023-10-25 09:25:53 27

原创 Mysql数据库

事务 是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作 要么同时成功,要么同时失败。例如:银行转账存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式。存储引擎是基于表的,而不是基于库的,索引存储引擎也可被称为表类型。-- 查询建表语句 --- 默认存储引擎 :InnoDB​-- 查询当前数据库支持的存储引擎​-- 在创建表时,指定存储引擎create table 表名(

2023-10-24 17:29:17 167

原创 代码随想录算法训练营第三十一天丨 贪心算法part02

局部最优推出全局最优,找不出反例,试试贪心!如图:i 每次移动只能在 cover 的范围内移动,每移动一个元素,cover 得到该元素数值(新的覆盖范围)的补充,让 i 继续移动下去。而 cover 每次只取 max(该元素数值补充后的范围, cover 本身范围)。如果 cover 大于等于了终点下标,直接 return true 就可以了。

2023-10-24 09:32:25 59

原创 代码随想录算法训练营第三十天丨 贪心算法part01

贪心的本质是选择每一阶段的局部最优,从而达到全局最优。这么说有点抽象,来举一个例子:例如,有一堆钞票,你可以拿走十张,如果想达到最大的金额,你要怎么拿?指定每次拿最大的,最终结果就是拿走最大数额的钱。每次拿最大的就是局部最优,最后拿走最大数额的钱就是推出全局最优。再举一个例子如果是 有一堆盒子,你有一个背包体积为n,如何把背包尽可能装满,如果还每次选最大的盒子,就不行了。这时候就需要动态规划。动态规划的问题在下一个系列会详细讲解。

2023-10-23 13:33:58 124

原创 代码随想录算法训练营第二十九天丨 回溯算法part06

除了这些难点,

2023-10-21 09:00:29 384

原创 代码随想录算法训练营第二十八天丨 回溯算法part05

这个递增子序列比较像是取有序的子集。而且本题也要求不能有相同的递增子序列。在90.子集II (opens new window)中是通过排序,再加一个标记数组来达到去重的目的。而本题求自增子序列,是不能对原数组进行排序的,排完序的数组都是自增子序列了。所以不能使用之前的去重逻辑!本题给出的示例,还是一个有序数组 [4, 6, 7, 7],这更容易误导大家按照排序的思路去做了。为了有鲜明的对比,我用[4, 7, 6, 7]这个数组来举例,抽象为树形结构如图:本题求子序列,很明显一个元素不能重复使用,所以需要s

2023-10-20 14:45:46 150

原创 代码随想录算法训练营第二十七天丨 回溯算法part04

其实子集也是一种组合问题,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。求排列问题的时候,就要从0开始,因为集合是有序的,{1, 2} 和{2, 1}是两个集合。以上为我做题时候的相关思路,自己的语言组织能力较弱,很多都是直接抄卡哥的,有错误望指正。其实和上一题整体逻辑一样,但是要注意去重的逻辑,要分清楚树层上去重和树枝上去重的区别。startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。),同时记录分割符的数量pointNum 要 +1。

2023-10-19 09:47:19 89

原创 代码随想录算法训练营第二十五天丨 回溯算法part03

题目中的无限制重复被选取,提示:1 <= candidates[i] <= 200。本题和77.组合 (opens new window),216.组合总和III (opens new window)的区别是:本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。本题搜索的过程抽象成树形结构如下:注意图中叶子节点的返回条件,因为本题没有组合数量要求,仅仅是总和的限制,所以递归没有层数的限制,只要选取的元素总和超过target,就返回!这里依然是定义两个全局变量,二维数组result存

2023-10-18 10:35:31 127

原创 代码随想录算法训练营第二十四天丨 回溯算法part02

图中可以看出遍历的深度,就是输入"23"的长度,而叶子节点就是我们要收集的结果,输出["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]。例如 k = 2,n = 4的话,就是在集合[1,2,3,4,5,6,7,8,9]中求 k(个数) = 2, n(和) = 4的组合。,无非就是多了一个限制,本题是要找到和为n的k个数的组合,而整个集合已经是固定的了[1,...,9]。首先要取startIndex指向的数字,并找到对应的字符集(手机键盘的字符集)。

2023-10-17 09:05:38 151

原创 代码随想录算法训练营第二十三天丨 回溯算法part01

回溯法也可以叫做回溯搜索法,它是一种搜索的方式。在二叉树系列中,不止一次提到了回溯,例如二叉树:以为使用了递归,其实还隐藏着回溯 (opens new window)。回溯是递归的副产品,只要有递归就会有回溯。以下讲解中,回溯函数也就是递归函数,指的都是一个函数。

2023-10-16 13:04:14 517

原创 代码随想录算法训练营第二十二天丨 二叉树part09

从图中可以看出需要重构二叉树,想想是不是本题就有点复杂了。其实不用重构那么复杂。在上图中我们发现节点0并不符合区间要求,那么将节点0的右孩子 节点2 直接赋给 节点3的左孩子就可以了(就是把节点0从二叉树中移除),如图:理解了最关键部分了我们再递归三部曲:这里我们为什么需要返回值呢?因为是要遍历整棵树,做修改,其实不需要返回值也可以,我们也可以完成修剪(其实就是从二叉树中移除节点)的操作。但是有返回值,更方便,可以通过递归函数的返回值来移除节点。这样的做法在二叉树:搜索树中的插入操作 (opens new

2023-10-15 10:03:27 386

原创 代码随想录算法训练营第二十一天丨 二叉树part08

如图,我们从根节点搜索,第一次遇到 cur节点是数值在[q, p]区间中,即 节点5,此时可以说明 q 和 p 一定分别存在于 节点 5的左子树,和右子树中。将删除节点(元素7)的左孩子放到删除节点(元素7)的右子树的最左面节点(元素8)的左孩子上,就是把5为根节点的子树移到了8的左孩子的位置。动画中的二叉搜索树中,删除元素7, 那么删除节点(元素7)的左孩子就是5,删除节点(元素7)的右子树的最左面节点是元素8。要删除的节点(元素7)的右孩子(元素9)为新的根节点。如图所示:p为节点6,q为节点9。

2023-10-13 16:22:25 166

原创 代码随想录算法训练营第二十天丨 二叉树part07

遇到在二叉搜索树上求什么最值,求差值之类的,都要思考一下二叉搜索树可是有序的,要利用好这一特点。

2023-10-12 12:58:53 85

原创 代码随想录算法训练营第天十九天丨 二叉树part06

因为是传入了两个树,那么就有两个树遍历的节点t1 和 t2,如果t1 == NULL 了,两个树合并就应该是 t2 了(如果t2也为NULL也无所谓,合并之后就是NULL)。如果 node.val > val,搜索左子树,如果node.val < val,就搜索右子树,最后如果都没有搜索到,就返回NULL。单层递归的逻辑就比较好写了,这里我们重复利用一下t1这个树,t1就是合并之后树的根节点(就是修改了原来树的结构)。递归函数的参数传入的就是根节点和要搜索的数值,返回的就是以这个搜索数值所在的节点。

2023-10-11 19:34:10 239

原创 代码随想录算法训练营第天十六天丨 二叉树part04

找到。

2023-10-10 20:42:12 108

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除