- 博客(45)
- 收藏
- 关注
原创 两个链表相交的复杂情况讨论
第一个问题要解决两个链表是否有环,方法是快慢指针,原理就是慢指针追上了快指针说明有环,然后通过一个变量记录两个指针所走的长度,快指针如果和慢指针相遇了说明快比慢多走了一个环的距离,只要再把慢指针放到起点再一个环的距离,当走到一个环的距离后,同时再在起点放入一个慢指针,然后这两个指针相遇的地方就是环的入环点。情况2 有环相交 要分情况讨论 交点再环外,交点在环上,如果在环外 那他们的入环点肯定相同,如果不相同则有可能在环上,怎么判断是否在环上,很简单直接让一个入环点遍历一圈看看有没有遇到另一个入环点就行。
2025-03-28 00:54:35
186
原创 最长公共子序列问题
逻辑就是如果右下角的数据和上面的数据相等,就先向上移动,如果右下角和左边数据相等 再考虑向左边移动,其他情况就向左上移动,就是我刚刚说的必须要按照先行后列 或者先列后行的顺序。就是用动态规划来实现,动态规划的一般逻辑,首先实现一个或者几个最简单的情况,然后再写出复杂情况到简单情况的转化关系,就可以得到结果了。第一个字符串的第一个字符和第二个字符串的第一个字符比的结果加上第一个字符串的第二个字符 和空白比较,第一个字符串的第一个字符和空白比加上 第一个字符串的第二个字符和第二个字符串的第一个字符。
2025-03-26 22:52:55
208
原创 最小回文串分割数
思路:递归处理从小规模开始处理 ,遇到大规模则可以先计算小的规模,然后把范围缩小,成小规模然后计算,每个规模都会有一个结果,最最优解不是单独一个规模的最优解,而是整体的最优解,先处理简单的 比如一个字符 那自然就返回0 还有两个一样的也返回0 还有只有中间和两边不一样的 也返回0 ,通过这些情况逐渐把问题分解。比较难处理是 怎么把大规模转成小规模来计算,可以这样想,先从第一个哪里切一刀,这样剩下的继续求解,或者从第二个哪里切一刀,剩下的继续求解,还有一种情况一定要考虑到就是可以不切一刀,它自身就是回文串。
2025-03-22 01:41:49
219
原创 最长公共子串问题
其实就是再最长公共子序列的基础上加了限制,必须要以某个字符结尾作为状态,因为子串必须要连续才算,不像子序列,所以值如果相等只能取左上角的值。最后最长的可能需要遍历下找到最大的值。然后通过对角线去找每一个字符。
2025-01-16 21:56:16
81
原创 最长公共子序列问题
arr[i][j] 代表0-i 和0-j 这部分的最长公共子串是多长,规律是如果左边大于0 那么右边一定是至少等于左边,如果此时对应到矩阵上的两个字符相等则在原来的基础上再加1,最后取这个矩阵右下角的值就是最大的公共子序列的值。怎么拿到那个值,就是再值发生变化是记录下此时的字符,就可以了。就是经典的动态规划问题,建立一个二维矩阵。
2025-01-16 21:45:20
102
原创 寻找二叉树中两个节点的最近公共祖先
第一确认最后一个尾巴节点是否相同,相同说明相交,然后判断这两个链表是否长度相同,如果不相同则让长的链表先走多余的步数,然后两个链表再同时出发,当发现第一个节点相等就说明找到了公共的夫节点。可以把这个二叉树反转,怎么反转就是根节点变成尾巴节点,叶子节点变成头节点,这样就变成了找两个链表的第一个交点,讲讲思路吧 不想写代码了。
2025-01-16 21:38:21
123
原创 判断两个字符串是不是旋转字符串
首先定义什么叫旋转字符串,首先要了解二叉树,用字符串变成一颗二叉树,比如abcd ,只要二叉树的中序遍历(要排除根节点)和abcd 一样就可以认为 是由这个字符串构造出来的,比如abcd 是父节点,然后它的左节点是a,右节点是bcd, bcd 的左节点是b,右节点是cd,cd的左节点是c, 右节点是d,不允许一个节点只有一个子树有值,要么都有要么都没有,在这个基础上再加上旋转,旋转就是指同一个节点的左右子树交换,这样中序遍历顺序也就跟着变了,思路:穷举出给出字符串的可能。
2025-01-12 22:12:48
130
原创 最大拿牌的得分
思路:递归算法,一个人拿左边牌,另一个人的得分 和拿右边牌 另一个人的得分作比较,只拿让对方得分最小的牌,反过来也是一样,那如果轮到对方拿牌自己也将会拿到最小的分,假设有个游戏,一列牌有不同分数,但是只能从两头拿 ,拿到最后分数最高的人获胜,假设两个人都是聪明人,求最后的最高分是多少?两个方法,分别代表A 的最大得分 B的最大得分。
2025-01-12 20:57:13
325
原创 找到二叉数的后继节点
3. 这种情况比较麻烦,这个节点处于父节点的右子树上,而且他还没有右节点,所以只能往上找,一直找到什么情况呢?就是发现处在父节点的左子树上,如果找到最上层节点也没满足,说明它就是顶级节点的右子树的中序排列中最右侧的节点。思路:就是分情况讨论,1。这个节点是有右节点,那么下一个节点就是右节点的中序排列第一个节点 2. 这个节点是父节点的左节点,那么下一个必然是父节点。假设二叉数节点中包含指向父节点的指针,求任意一个节点的后继节点,后继节点就是中序排列中后面的第一个节点,
2025-01-07 00:04:35
210
原创 给定一个表达式 和一个期望结果 求有多少种可能得到结果
思路:假设给定了bababaab, 期望是false, 那可以分成两部分来看,b a babaab 其中a 是操作符,所以为了达到这个目的 babaab 一定有一个期望值,然后开始考察babaab 这个字符串,但是规模变小了 ,当规模等于abb的时候 或者等于b 的时候 就没得选只能有一种方法了 递归结束。需要分两种情况谈论 一种是第一个数字不和第二个数字进行运算,还有一种是第一个数值先和第二个数字运算,然后再考虑其他的。分两种情况讨论 1。然后每种情况有需要根据符号的不同 分情况讨论。
2025-01-05 23:06:04
229
原创 矩阵最小路径和
简单设计一个二维数组sum[][]和原数组保持规模一样,但是含义不一样,sum[i][j] 代表原数组中周到[i][j]位置需要最少的步数和,因为是从左上到右下,所以一个位置的最小和取决于他的上面和他的左边,还就是比大小,小的记录到sum[][]位置上去,从左上角到右下角肯定有很多走法,找出路径和最小的那一条。
2025-01-05 20:29:58
88
原创 判断一个单链表是否是回文结构 要求O(N)时间复杂度 O(1)空间复杂度
没做出来 看了解析 但是思路想到了 就是只能调整链表顺序,正确答案是 把链表变成两条单链表,分别从两侧走向中间拿两个指针 分别指向两头 ,往中间走 中途有不一样的就返回false,获取链表长度 方便到时候确定从哪里开始反转。其中一个方法是反转链表。
2025-01-03 22:32:30
258
原创 设计一个算法求出时钟里 时针和分针互换位置的时间,
按道理分针走到50后 时针是不可能还在2点的位置的,有一个规律是分针走到60后 时针一定对准了某个数字,根据这个规律可以排除那些时间是不存在的。因为互换后的时间其实是有可能不存在的,比如10:10 互换后变成02:50。这个题目是我自己想出来的,输入一个时间 ,输出时针分针互换位置的时间。
2024-12-30 00:45:00
200
原创 预告:logN 时间复杂度实现斐波拉契数列类问题?
我们都知道 斐波拉契数列可以用N的时间复杂度实现,第N 项的结果,按道理也挺理想的。现在要求按照logN 时间复杂度来实现?
2024-12-23 00:01:30
106
原创 汉诺塔 问题(递归非递归方案)
递归实现逻辑,假设最简单情况,只有一个元素,那就直接从左边移动到中间,然后再从中间移动到右边,如果有两个元素,那就可以展现思路了,定义一个汉诺塔 只能从相邻的柱子移动,比如只能从左边移动到中间再移动到右边,1.先把左边柱子除开最底层的(记为A)移动到中间,3.左边最大(B)的移动到中间。4,A移动到B 上面。
2024-12-21 05:06:14
148
原创 环形链表处理约瑟夫问题(大家围成圈,固定间隔的人自sa)
聪明的办法就是 找出规律 节点数 间隔数 和最终存活节点的关系,距离当为10个节点 间隔为3 那么最终存活的是4 ,当为9个节点 存活的就是1 当为8 个节点 存活的就是7 ,规律就是前一个情况的结果+3 %当前人的总数就行,特殊情况如果取模的结果为0 比如在计算 俩个人 每隔三个人 自sa, (1+3)%2==0,那就要取最后那个数,这可以用笨办法 就是依次遍历,然后删除节点就行,但是时间复杂度为M(间隔数)*N(节点数)从一个人的情况开始往n个人的情况递推。循环了两次 第一次确认总人数。
2024-12-15 23:21:57
193
原创 完美洗牌问题
一打牌 数量是2N 个 比如12345678,定义完美洗牌 是变成51627384,定义一个算法去实现这个过程,要求空间复杂度是O(1) 也就是说不能随着数据规模变大而变大,本题的难点就是这个空间要求,一般限制了空间,就会导致算法复杂度及其高,这道题用到了两个知识点,1.公式 处于原来牌面的牌到完美洗好的牌的位置是有公式的,处于左边的牌假设他的原始位置是x,那它处于洗好牌的位置是2x+1,处于右半边的牌假设它的位置是x(这里的x 指的是从右半边第一张开始算的,而不是从0开始算),洗好牌的位置就是2x,。
2024-12-15 12:57:59
715
原创 最大异或和为零的子数组个数
思路:其实还是做选择,1.当遇到一个数它不为零,而且它之前也没有元素和它异或成零,这时要分情况,情况一 它是第一个没法异或成零的元素,那么记录它的下标,然后继续往后找,chanse2:如果当前不为零,但是可以和前面多个元素异或和为零,更新pre为-1,count+1,继续遍历。3.当遇到一个不为零,但是pre不为-1,pre到当前之间可以使得异或和等于0,同样也更新pre=-1。给你一个数组,切分它成多个子数组,使得子数组内部的元素异或和为零。2.当遇到一个元素为零,那么更新它的pre为-1,继续往后。
2024-12-01 20:31:55
250
原创 挖个新坑 一篇文章让你搞懂 KMP算法
kmp 算法的核心就是构建最长前缀后缀数组记为next[],这个数组的含义是在match中第i个字符,以它前一个字符(i-1)结尾的后缀序列和从头开始的前缀序列最大的匹配长度,假设为3 就是说以match[i-1]结尾的后缀序列 和match[0]开头的前缀序列最大匹配了3个。还有个比较复杂的就是构建next数组,最简单办法就是建立两个指针(i-2,i-1),一个从前缀的最长可能结尾index,往0走,一个代表后缀最开始的索引,当前缀指针到达0时,后缀结束指针减后缀开始指针就是最大的匹配长度,
2024-11-24 18:25:52
140
原创 看了别人写的根据redis 配置限流的文章整理下
1.设置一个有过期时间的key作为计数器比如10s 过期 ,通过get命令来得到这个key ,如果能获取到并且次数也低于阈值就能访问。2.zset 配合当前时间戳来访问,通过hrang来统计某个时间范围的数量,超出阈值拒绝。
2024-11-10 22:19:49
112
原创 简单理解jakarta.validation.Validator校验框架
这里说一句 校验成功与否是根据validate 是否返回空集合为标准,这里如果发现元数据中没有加约束信息比如注解之类的就会直接返回空集合。众所周知 Validator是用来做参数 返回值的校验,今天简单看了下他的源码,梳理下大概逻辑。一般方法一开始都是在初始化一些组件,以及收集自己需要的信息,validator 也不例外。在校验前会取出有哪些位置需要校验 ,以及校验的类型,比如上图中age 需要MAX 校验,找到一个合适的校验器,相当于每种注解都会使用不同的校验器。构建校验的上下文,相当于是整体的环境。
2024-11-10 08:17:22
329
原创 将一棵搜索二叉树转换成排序好的双向链表
思路使用二叉树的中序遍历就能实现,问题是怎么把多个中序遍历序列链接起来,我使用了一个数组存储当前便利的头节点和尾巴节点,会有4种情况,情况一左子树不为空,右子树也不为空,此时只要把左子树的尾巴链接上当前头节点,然后头节点连接上右子树头节点,情况四 左右子树都为空 直接把头节点 同时作为头和尾节点返回。情况三 右子树不为空 直接把头节点和右子树头节点链接后返回。情况二 左子树不为空 直接把左子树和头节点链接后返回。
2024-11-03 15:11:51
131
原创 二叉树先序 中序 后序 遍历(递归,非递归)版本
最后是后序遍历也是最难的其实只要理解递归的本质是是什么?中序遍历先把左子树压入栈内通过current=current.left,直到current.left=null,然后弹出来的就是最左边的节点,弹出栈打印它,把然后把他的右子树压入栈内。通过current=current.left 决定先打印头接下来就是左节点,右节点压入栈内作为最后处理对象,比较复杂的是非递归方式,如果不使用递归,其实使用栈也能达到一样的效果。递归方式比较简单基本写出一个只需要调换下位置就行贴出代码。
2024-11-03 02:36:30
228
原创 二叉树 按层打印和按zigzag 模式打印
zigzag 打印没法使用之前的办法,我是用两个linkedList 实现,一个负责保存奇数行的数据,一个保存偶数行数据,还需要一个变量来控制当前是从奇数list 取值还是偶数list取值,在第一次从list 取值的时候需要判断是否是第一次取,如果是第一次需要打印换行,从奇数行取了需要放入偶数行,取值子节点的时候一定要先取右子树然后再取左子树,这样能保证一行的数据是按照从左往右或者从右往左的顺序排列,如果先取左节点就会打乱这个顺序。考验如果按照规则遍历二叉树,接下来看zigzag 打印。
2024-11-02 10:56:28
324
原创 换钱最少货币数量
假设已经知道了最小货币数量是X ,那么这个X 可能是从15元的最小货币数加五元得到,或者18元最小货币数加2元得到,或者17元最小货币数加3元得到,至于取哪一个就看谁的数量最小,并且可能有些数额根本没法正好换开,按照上面的思路一直反推到当等于货币剩余0元的时候结束,就是最小的结果。给定一个数组,里面有不重复且为正数而且数量无限的货币,和一个数A,求最少需要几个硬币才能刚好凑够A。思路:假设要求20元 对应货币面值是 5,2,3。
2024-10-31 21:28:13
209
原创 关于mysql innoDB引擎怎么存储表数据
数据是直接存储在聚簇索引的叶子节点上,也就是说innoDB引擎下的表数据就是以主键索引的方式构成的。非聚簇索引叶子节点存的是主键值。
2024-10-29 22:23:41
113
原创 LinkedHashMap 中accessOrder属性
它代表元素在LinkedHashMap中的双向链表中的排序规则,如果为真代表按照查询顺序排序,如果为否也就是默认选项就是按照插入顺序排序,按插入顺序基本不会改变,只有按照访问顺序才会在访问后调整在双向链表中的位置,目的是把最近查询的元素放在链表尾部,利用这个特性可以用来作为缓存的LRU算法。
2024-10-29 21:47:40
132
原创 讲讲java 并发框架里面的AQS (AbstractQueuedSynchronizer)以ReentrantLock(jdk17)为例
首先它是一个抽象类,使用了模板方法,通过重写里面的tryXXX方法实现获取锁/释放锁操作,类中有一个state int 类型的字段,用volatile 修饰,用来代表当前锁被重入了多少次,如果等于0,代表无锁状态,同时有一个双向链表,用来放暂时没有抢到锁的线程,类比jdk自带的synchorized 锁只有一个同步队列 一个等待队列,ReentrantLock提供了一个同步队列(有机会获得锁)和若干个等待队列(需要被唤醒从等待队列进入同步队列才有机会获得锁)
2024-10-28 22:39:01
229
原创 几种缓存淘汰算法
就是把最近访问最少的key 剔除出去 实现上可以通过使用哈希表和双向链表,维护一个最低访问次数节点的栈,从队列的尾部开始寻找等于最低访问次数的节点,然后再插入,插入的以及缓存命中的默认放在队列的头部, 缺点:无法体现最近使用情况,比如有一个key 几个月前使用很频繁但是最近没人使用,依旧保留在内存中。而刚刚加入的缓存因为是刚加入,很可能马山就被剔除。 这个只考虑时间,只保留最近访问过的数据,之前的数据清除,可以使用一个LinkedList 实现,缓存未命中的数据查
2024-10-27 12:38:13
188
原创 缓存的三种灾难以及应对方法
大规模的缓存到期失效,导致请求打到数据库,解决办法1.设置随机过期时间2.如果是redis 宕机导致雪崩,可以使用集群实现高可用3.访问数据库接口使用熔断机制,防止过多请求来到数据库。
2024-10-27 00:05:50
178
原创 redis 主从同步原理
master 先把内存文件生成RDB 文件 发送给从节点,在生成到发送结束这段时间的命令则直接通过增量的方式发送给从节点等RBD 发送完了以后。在此期间主节点依旧可以写 从节点依旧可以读。主从节点配置在redis.conf文件中 使用replicaof 主节点ip 主节点端口号。同时记得配置主节点密码master auth XXX。
2024-10-26 23:36:57
103
原创 redis RDB 和AOF 两种备份方案优缺点对比
2.备份时候,如果数据集比较大fork子进程会很消耗CPU资源。2.自动会把日志重写,防止变得太大,重写时候不会阻塞老日志文件的插入,2.如果设置成每次操作执行一次更新,可能会比较消耗IO资源。1.因为是每隔一段时间备份,所以存在数据丢失可能。3.子进程备份的时候,不会有写操作,保证完整性。1. 每秒追加日志,或者每次操作追加日志 降低丢失数据可能性。3.aof文件就是操作指令的集合,方便自定义的恢复。2.灾备只需要传输一个文件。RDB: 优点:1.全量数据备份,隔一段时间。缺点:1.文件比较大。
2024-10-26 22:55:24
246
原创 简要说明令牌桶算法
令牌桶算法属于限流算法,通内固定间隔时间会产生固定数量的令牌,只有当桶内的令牌还没有拿完才能放行,如果已经拿完只能等下一个统计周期,或者直接拒绝请求。
2024-10-26 19:01:03
104
原创 Java 线程池简单理解
那当然就是直接return 就行。网上有不少关于线程池的文章 ,我写个简单点的,毕竟再长的文章能真正记住的就是一个模型一个概念,面试过程中能讲到点上就不太可能丢分,
2024-10-26 15:56:38
133
原创 简单阐述 关于jdk1.7 hashmap 为什么会出现并发情况下 死循环的问题
首先要知道 hashmap 是以单链表的方式存储节点,在扩容的时候也是从头节点复制到新的数组里面去,假设在老数组同一个索引下有两条数据3->7->null ,当发生并发resize 时候 一个线程执行到插入3到新数组中去了,而另外一个线程已经执行完了,也就是变成7->3->null,此时未完成的线程获得了cpu时间,开始执行7节点插入,同时获取到7的下一个是3(因为有一个线程已经改了7的next),7节点插入后,又来到3节点插入,所以就出现了循环引用。
2024-10-26 08:50:22
129
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人