自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 一文带你彻底了解Redis中的网络模型

Redis的网络模型是支撑其高性能的核心架构,采用I/O多路复用与事件驱动机制的结合,通过高效的资源调度实现了高并发的连接处理能力。1. 基于epoll的I/O多路复用Redis服务端启动时通过初始化,调用创建epoll实例。随后创建服务端Socket(serverSocket),绑定端口并注册到epoll实例中,开始监听客户端连接请求。当serverSocket触发可读事件时(即客户端连接到达),系统调用accept获取客户端Socket(clientSocket),并将其注册到epoll中,同时绑定。

2025-03-17 14:00:00 892

原创 Java常见集合一条龙讲解版(结合底层原理以及面试题)

本文由浅至深讲解了Java常见集合的原理,并结合了常见Java集合的面试题进行讲解,保证你一定会有些收获。

2024-10-16 16:48:33 1032 1

原创 从源码上剖析AQS的方方面面(超详细版)

本文用CountDownLatch和ReentrantReadWriteLock对AQS的实现作为案例,由浅入深的分析AQS的原理,旨在用一文教会大家AQS。

2024-10-14 22:05:42 1074

原创 ReentrantLock公平锁具体实现(基于AQS)

本文主要讲解了基于AQS思想对于reentrantlock公平锁的底层原理以及实现。

2024-10-14 10:51:11 1201

原创 Callable接口详解(promax版)

本文旨在讲述Callable接口和包装类FutureTask类的使用,包括API介绍和场景。

2024-10-13 18:54:00 699

原创 Java并发安全容器(超级详解版)

本文旨在讲解Java并发编程中的各个并发容器,包括阻塞和非阻塞队列。每次讲解时都会带上一些例子,欢迎小伙伴们点击学习!!!

2024-10-13 17:08:37 1030

原创 MySQL索引常见面试题整理(超级无敌详细版)

MySQL常见索引题基本全部涵盖,可以直接开背。

2024-09-26 15:26:56 1276

原创 MySQL SQL基础常见面试题整理

本文收集了大部分的SQL基础的面试题,掌握了这部分,你就可以拷打面试官!!

2024-09-25 14:30:55 1300

原创 力扣516-最长回文子序列(Java详细题解)

我的算法篇最后一曲,超级细致的讲解,保证看完就会。

2024-09-23 14:13:25 1339

原创 力扣647-回文子串(Java详细题解)

回文子串全网最详细讲解,快来了解一下吧!

2024-09-23 14:09:09 960

原创 力扣72-编辑距离(Java详细题解)

编辑具体的最佳解决办法,快来看看吧。

2024-09-22 21:28:40 1127

原创 力扣583-两个字符串的删除操作(Java详细题解)

这绝对是你看过关于两个字符串的删除操作最好理解的题解,速速查收。

2024-09-22 21:27:24 1047

原创 力扣115-不同的子序列(Java详细题解)

我敢保证这绝对是你看过的最详细的一篇题解,包教包会。还不快点进来看看。

2024-09-21 21:11:21 913

原创 力扣-1035不相交的线(Java详细题解)

其实也就是说A(上面一个数组)和B(下面的数组)的最长公共子序列是[1,4],长度为2。这个公共子序列指的是相对顺序不变(即数字4在字符串A中数字1的后面,那么数字4也应该在字符串B数字1的后面),那么你会发现该题与力扣1143的代码完全类似,唯一不同的就是1143是字符串,本题是数组。抽象来说就是本数组中与另一个数组相对应的一对数都在上一对相应的数的后面。因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。最大不相交的线的连线数就是俩个数组的最长公共子序列。4.确定dp的遍历顺序。

2024-09-21 10:00:00 480

原创 力扣53-最大子序和(Java详细题解)

注意这里是以i为结尾,所以i必须是该最大连续子数组的最后一个元素,所以本题收集结果的地方可能是任意位置。本题可以从递推公式可以看出dp[i]的状态依靠于dp[i - 1],所以所有状态的起点就是dp[0]。由递推公式也可以看出dp[i]的状态依靠于dp[i - 1],所以一定是从前往后遍历的。既然我们考虑下标为i的元素是连续子数组和的一部分,那我们就要遍历数组中的每一个元素。dp[0]只有一个下标为0的元素,所以他的连续子数组和就为nums[0];dp[i] 指的就是以i为结尾的最大连续子数组和。

2024-09-20 21:06:47 432 1

原创 力扣714-买卖股票的最佳时机含手续费(Java详细题解)

当天卖出股票,那么我前一天肯定是持股的状态,所以我要把前一天持股手上的最大现金,加上我卖出这次股票的现金,同时再减去这次交易的手续费 就是我所得的最大利润了。所以dp[i] [1] = Math.max(dp[i - 1] [1],dp[i - 1] [0] + prices[i] - fee)dp[i] [1]用来表示下标为i天不持股手上的最大现金,一个是延续之前的状态,之前就已经不持股的状态了。因为手续费是完成每笔交易后支付的,那么就是在本次买卖股票中的卖股票完成的。4.确定dp的遍历顺序。

2024-09-20 17:00:00 848

原创 力扣309-买卖股票的最佳时机含冷冻期(Java详细题解)

如果i为1,第1天买入股票,那么递归公式中需要计算 dp[i - 1] [1] - prices[i] ,即 dp[0] [1] - prices[1],那么大家感受一下 dp[0] [1] (即第0天的状态二)应该初始成多少,只能初始为0。所以dp[i] [0] = Math.max(dp[i - 1] [0],Math.max(dp[i - 1] [3] - prices[i],dp[i - 1] [2] - prices[i]));dp[0] [0]下标为0天持股的最多现金就是买入当天的股票。

2024-09-20 15:00:00 776

原创 力扣188-买卖股票的最佳时机 IV(Java详细题解)

注意看dp数组的定义,dp[i] [0]的状态是不操作 dp[i] [1]才表示第一次持股,而我们的j是从0开始遍历。dp[0] [3] 表示下标为0天第二次持股 那就是第一买卖结束后 再买入股票 也是 -prices[0]第一次的dp[i-1] [0]就是相等于 0 ,也就是第一买入股票就等于 0 - 这次买入股票的现金。dp[0] [1] 表示下标为0天第一次持股 那肯定就是当天买入股票 就为 -prices[0]dp[0] [j]是递推的起始位置,所以我们要初始化dp[0] [j]。

2024-09-20 10:00:00 1722

原创 力扣1143-最长公共子序列(Java详细题解)

注意这里的子序列和力扣718. 最长重复子数组的子序列不一样,本题的子序列是可以不连续的,而最长重复子数组是需要连续的。当nums[i - 1] == nums[j - 1]时,说明此时结尾的元素相等,那么此时的最长公共子序列就等于他前一个状态加上相同元素的长度即可.因为dp[i] [0]和dp[0] [i]是将一个没有意义的字符串和另一个字符串求最长公共子序列,所以他们的长度就为0。dp[i] [j]的含义是以i - 1结尾的字符串与j - 1结尾的字符串最长公共子序列的长度。所以主要是俩大情况。

2024-09-19 21:22:53 1103

原创 力扣718-最长重复子数组(Java详细题解)

当nums[i - 1] == nums[j - 1],dp[i] [j]是由dp[i - 1] [j - 1](下标i - 2结尾的数组和j - 2为结尾的数组俩个数组的最长公共子序列长度)加上 nums[i - 1] nums[j - 1]这俩个元素相同的长度,也就是1。因为dp数组定义的就是i - 1结尾的数组和j - 1为结尾的数组俩个数组的最长公共子序列,所以只有nums[i - 1] == nums[j - 1]时,他们的dp[i] [j]才能被推出。所以要从左到右,从上到下去遍历。

2024-09-19 11:05:23 900

原创 力扣674-最长连续递增序列(Java详细题解)

当nums[i] > nums[i - 1]时,我们得把以i - 1为结尾的最长递增子序列求出再加上nums[i]的长度就为以i为结尾的最长连续递增子序列。dp[i]取不同的i都至少有一个最长连续递增的序列,所以我们就让dp数组的所有值都初始化为1。由递推公式可以推出dp[i]的状态只与dp[i - 1]有关,所以遍历顺序一定是要从前往后遍历的。所以递推公式就为dp[i] = Math.max(dp[i - 1] + 1,dp[i]);因为我们要取最大,所以还需要对dp[i]取一个最大值。

2024-09-18 17:00:00 458

原创 力扣300-最长递增子序列(Java详细题解)

其实有点像力扣139的单词拆分,如果j到i这段是递增(nums[i] > nums[j])的,那么i的最长递增子序列就为dp[j] + 1。由dp数组可以看出,dp[i]是指以下标i结尾的数组最长递增子序列的长度。本题要求最长严格递增子序列的长度,所以dp[i]定义为以下标i结尾的数组最长递增子序列的长度。就为之前以j为结尾的最长递增子序列加上nuns[i]这个元素,所以就为dp[j] + 1。本题是求的递增的子序列,所以肯定是要让用nums[j] 来遍历nums[i]。4.确定dp的遍历顺序。

2024-09-18 11:47:32 737

原创 力扣123-买卖股票的最佳时机 III(Java详细题解)

所以dp[4 ] [4]已经包含了dp[4] [2]的情况。也就是说第二次卖出手里所剩的钱一定是最多的。一定是选最大的,所以 dp[i] [1] = Math.max(dp[i-1] [0] - prices[i], dp[i - 1 ] [1]);由递推公式可以看出dp[i] [1] = Math.max(dp[i-1] [0] - prices[i], dp[i - 1 ] [1]);那么dp[i] [1]究竟选 dp[i-1] [0] - prices[i],还是dp[i - 1] [1]呢?

2024-09-15 11:04:13 904

原创 力扣122.-买卖股票的最佳时机 II(Java详细题解)

我当天卖出,那我的前一天肯定是持股的状态,那我就将前一天持股手上的最大现金加上我当天卖出的股票最大现金,也就是我的最大不持股的现金(所得的利润)。但是该题可以买卖多次,那我买入股票的时候可能前面已经进行过一次买卖了,那我手上的现金就不是0了,就为上一次买卖后所得的最大现金。那我第二次再买股票的时候,我就要将上一次买卖后所得的最大现金减去当前买入股票的价格即可。我当天不持股可能我前一天也是不持股的状态,也可能是我当天卖出股票的状态。我当天持股可能我前一天也是持股的状态,也可能是我当天买入股票的状态。

2024-09-14 10:27:27 493

原创 力扣121-买卖股票的最佳时机(Java详细题解)

我当天卖出,那我的前一天肯定是持股的状态,那我就将前一天持股手上的最大现金加上我当天卖出的股票最大现金,也就是我的最大不持股的现金(所得的利润)。dp[0] [0]是表示我i下标为0持股的状态,那肯定是当天买入股票的状态,因为他前面没有状态了,所以dp[0] [0] = -prices[0]dp[0] [1]是表示我i下标为0不持股的状态,那就是我当天买当天买了,那手上的最大现金就为0了。可以看出dp[i]是由dp[i - 1]推出,所以需要前一个状态,那么我们所有状态的起始状态就是dp[0]

2024-09-13 20:00:00 666

原创 力扣337-打家劫舍 III(Java详细题解)

其实这就是我们要用后序遍历的一个好处了,后序遍历可以优先处理左右孩子节点的情况,然后将左右孩子节点的返回值返回给中间节点处理。所以每一层我们就用dp数组来表示我们的状态,dp[0] 表示不偷本节点的子树结构的最高金额,dp [1] 表示偷本节点的子树结构的最高金额。意思就是俩个相连的节点就不能偷,再深入点就是当前节点如果已经偷了,那么他的子节点是不能偷的,如果当前节点不偷,那么他的左右孩子是可以。意思就是本层的递归值中就有我孩子节点的状态,我可以用我孩子节点的状态来推出我本层节点的状态。

2024-09-13 17:00:00 1029

原创 力扣213-打家劫舍 II(Java详细题解)

核心处理逻辑代码还是打家劫舍1的代码,只不过把他做成一个函数,把首的坐标和尾前一个坐标传入即可,这样就把尾元素排除了。首考虑偷,尾考虑不偷,那我们就不把最后一个元素放入我们的dp数组。这一篇博客就到这了,如果你有什么疑问和想法可以打在评论区,或者私信我。尾考虑偷,首考虑不偷,也是如此,把尾坐标和首后一个坐标传入即可。每一个dp题目如果都用这五步分析清楚,那么这道题就能解出来了。其实1这种情况在2,3中都考虑进去了,我们就考虑2,3就好。既然首尾有约束,我们就判断首尾的情况。但我们还是要求整个环的最大金额。

2024-09-13 11:46:03 519

原创 力扣198-打家劫舍(Java详细题解)

那么这里我们也只能偷一个,所以对nums[0]和nums[1]取一个最大偷就好。注意我这里是考虑,并不是一定非要偷这些房间,真正实现偷这些房间是递推公式帮我们实现的,我们只要把该情况考虑进去就可以了。从递推公式中也能知道dp[i]是由dp[i - 2]和dp[i - 1]得出。由递推公式可以知道dp[i]是由dp[i - 2]和dp[i - 1]得出。当前房子偷,前一个房间肯定是不能偷,只能从他前俩个房间开始考虑偷。dp[i - 2]就是考虑偷 i - 2之前的房间偷窃的最大金额。

2024-09-12 17:30:00 661

原创 力扣139-单词拆分(Java详细题解)

但该题因为是字符串,装入有点难,所以换一种思路,我们将背包进行拆分,将背包容量(字符串s)拆分为一个个物品(wordDict字典里的字符串),如果能拆分成功就return true,如果不能就return false。如果此时我们的dp[j] 为 true的话,那说明字符串长度为j的s是可以拆分为一个或者多个字典中出现的单词,那么我们就只用再判断[j,i]这段区域是否也能拆分为字典中出现的单词,如果能拆分那么dp[i]就为true。该题的递推公式与之前的有些不同,之前的是把每一个物品装入到我们的背包中。

2024-09-12 11:46:53 547

原创 力扣279-完全平方数(Java详细题解)

因为选择了i * i作为物品,所以我们要知道选择i * i之前的背包容量所能装的最少物品数量,然后选择了这个物品,那我们的物品数量就会加1。唯一不同的就是物品不一样,零钱兑换是把物品数量什么的都给出来了,该题的物品没给出来,需要我们自己创建。因为我初始化为最大的数值,其他的数肯定小于等于它,当我递推出一个比它小的值时,就能覆盖这个最大值,不影响我递推的值。本题是求最小值,如果我将非0下标也初始化为0,那么我初始化的0就会将我递推出来的最小值覆盖,最后得出来为0。所以我物品的排列组合是不影响我dp数组的。

2024-09-11 17:00:00 1118 1

原创 力扣322-零钱兑换(Java详细题解)

当这个物品选的时候,dp数组为dp[j - coins[i] + 1]。因为选择了i这个物品,所以我们要知道选择i之前的背包容量所能装的最少物品数量,然后选择了这个物品,那我们的物品数量就会加1。就比最多的硬币个数还多一点,这样dp数组也不可能取到这个值,也就不影响我的递推公式的值。因为我初始化为最大的数值,其他的数肯定小于等于它,当我递推出一个比它小的值时,就能覆盖这个最大值,不影响我递推的值。本题是求最小值,如果我将非0下标也初始化为0,那么我初始化的0就会将我递推出来的最小值覆盖,最后得出来为0。

2024-09-11 11:44:41 940

原创 力扣518-零钱兑换 II(Java详细题解)

此时我们是选择装入该物品,首先我们得知道装入该物品之前装满的方法数量,那么加上该物品其实并不会让该方法数量加一,已经选择了该物品,所以方法数量就是dp[j - nums[i]]。选的状态就是dp[j - nums[i]],因为此时我们选择了该物品,我们就要求在装入该物品之前的装满背包的方法种类的数量然后再放入该物品。不选的状态就是dp[j],因为没有选,背包容量不会减少。因为这个一种方法,而不是物品的数量,如果是数量,那么加入该物品肯定是要加1,但是这是一种选择方法,我已经选择了,所以就不会加1。

2024-09-10 20:00:00 802

原创 力扣474-一和零(Java详细题解)

其实x表示的是当前物品0的数量,y表示当前物品1的数量。如果没有出现差错,我们就可以不用打印,因为我是写题解,所以我就不添加核心代码以外的代码,不然代码显的有些冗余。dp[0] [0]指的就是当背包中有0个0和0个1时能装入的物品数量,所以dp[0] [0] = 0;因为选的话,就得求出加入当前物品之前的背包容量能装入的最大物品数量,再加上该物品。那么可以将这种容器抽象为背包,只不过这个背包是二维的,最大容量为m个0,n个1。我们这个背包是二维的,所以我们的dp数组也得是二维的。

2024-09-10 17:00:00 857

原创 力扣494-目标和(Java详细题解)

此时我们是选择装入该物品,首先我们得知道装入该物品之前装满的方法数量,那么加上该物品其实并不会让该方法数量加一,已经选择了该物品,所以方法数量就是dp[j - nums[i]]。选的状态就是dp[j - nums[i]],因为此时我们选择了该物品,我们就要求在装入该物品之前的装满背包的方法种类的数量然后再放入该物品。不选的状态就是dp[j],因为没有选,背包容量不会减少。因为这个一种方法,而不是物品的数量,如果是数量,那么加入该物品肯定是要加1,但是这是一种选择方法,我已经选择了,所以就不会加1。

2024-09-10 11:11:45 2172

原创 力扣1049-最后一块石头的重量II(Java详细题解)

分析到这,看过我力扣416-分割等和子集那篇题解的会发现,这道题跟那道题很像。都是分为俩个不同的部分,求某一个部分,另一个部分也就确定下来了。比如这一堆石头重量为i,另一堆石头不就为sum(重量总和) - i。其实不仅思路都很像,代码也只是最后处理背包价值的逻辑有些不同。没看过的也没关系,我会重新再讲一遍。分成俩个石头堆后,如果我们确定了一个石头堆的重量和,另一半的就可以确定下来了。所以我们分析其中的一个石头堆就可以。

2024-09-06 11:44:43 1383

原创 力扣416-分割等和子集(Java详细题解)

01背包是有n个物品,每个物品有其对应的价值和重量,给你一个容量为m的背包,让你求该背包所能放下物品的最大价值。其实这个子集的元素和就可以当做01背包的背包容量,元素本身可以当做他的价值和重量,即他的价值和重量都一致。如果一个子集的元素和等于整个数组的元素和的一半,那么这个子集就可以确定下来,整个数组就可以分为俩个子集。分成俩个子集后,如果我们确定了一个子集的元素和为整个数组和的一半,另一半的就可以确定下来了。由此可见,如果一个数组他的元素和为偶数的话,就可以使俩个子集的元素和相等。

2024-09-06 11:43:42 1039

原创 力扣96-不同的二叉搜索树(Java详细题解)

当只有一个节点时,他的根节点只有为1一种情况,他的左右节点都为dp[0]所以dp[1] = dp[0] * dp[0] = 1。j是指当j为根节点的情况。dp[i - j]就是他的右子树的情况,他的右子树肯定比j大,因为是用j来遍历i,所以他的右子树的节点就是[i - j]了。所以dp[3] = dp[2] * dp[0] + dp[1] * dp[1] + dp[0] * dp[2]。dp[3],就是 元素1为头结点搜索树的数量 + 元素2为头结点搜索树的数量 + 元素3为头结点搜索树的数量。

2024-09-05 17:00:00 2149

原创 力扣343-整数拆分(Java详细题解)

然后我们是要得到dp[i] 的最大值 所以我们的递推公式就是dp[i] = Math.maxa(dp[i],Math.max((j * (i - j),j * dp[i - j]))。我们先看看dp数组,dp[i] = Math.maxa(dp[i],Math.max((j * (i - j),j * dp[i - j]))。dp[i]是需要dp[i - j]的状态,即需要他前面的状态,所以遍历顺序一定是从前向后遍历,现有dp[i - j]再有dp[i]。dp[i]就是指将i拆分后获得的最大乘积。

2024-09-05 10:24:33 1091

原创 力扣63-不同路径 II(Java详细题解)

而且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]就是指到达第i行j列的不同的路径。即dp[i] [0] 和 dp[0] [i]的路径数。

2024-09-04 21:50:06 760

原创 力扣62-不同路径(Java详细题解)

而且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]就是指到达第i行j列的不同的路径。即dp[i] [0] 和 dp[0] [i]的路径数。

2024-09-04 17:30:00 475

空空如也

空空如也

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

TA关注的人

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