- 博客(72)
- 收藏
- 关注
原创 KMP算法
定义主串指针i(初始化0), 子串指针j , 不断比较主串和子串每个字符是否一致,如果一致,继续比较,如果不一样,主串指针变成1,子串指针变成0,从新开始比较。如图,匹配失败之后,保持指针i 不变,尽可能移动子串的指针到有效的匹配位置(这个意思是指,i前面两位已经匹配成功了,不需要额外进行比较了。KMP其实是对上面的暴力求解进行了改进,利用的是匹配失败之前,匹配成功的信息。比如求子串在主串中出现的起始位置,子串在主串中出现的次数等等。其实求next数组,可以看做是两个相同的字符串自己和自己比较。
2024-06-04 20:25:51
365
1
原创 【JVM】Java类加载器 和 双亲委派机制
当一个类加载器需要去加载类时,会 首先委派给其父类加载器进行加载,如果父类加载器无法加载,才由该类加载器自己去加载但是如果只为了定义自定义加载器,建议重写findClass方法,这样不会破坏双亲委派机制。@Override// 核心类库还是交给双亲委派机制进行加载// 通过类的全限定名,找到字节码文件,并转为byte数组 不写了// 类的加载就是由defineClass这个底层方法实现的。
2024-03-29 21:00:50
937
原创 LeetCode刷题--- Dijkstra 求最短路径
比如我们求从0 到其他点的最短距离,定义一个数组,第0行分别是每个节点,第一行是0到其他节点的距离,初始化为正无穷大,第三行是表示是否已经是最小距离。因为从1到2的距离是2+1,小于当前的5,因此可以刷新下表,此时得到了0到2最短距离3。思路就是上面的思路,不断的获取距离,然后和当前的距离比较,如果比他小,就更新进去。首先遍历0能够直接到达的顶点,修改如下,此时0到1的距离是最短的,可以标记为T。个人感觉,邻接矩阵适合无向图,邻接表适合有向图。然后看从2出发,能够直接到达的距离。
2024-03-27 17:50:52
419
原创 LeetCode刷题,最小路径和,从记忆化搜索到动态规划
因为机器人每次要么向下走,要么向右走所以可以转换为求grid[0][0] + 右边矩阵网格和下方矩阵网格的最小值。1、如果当前位置已经在grid右下角了,说明是最后一步了,可以取当前值跳出递归。,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。2、走到了边界,没办法继续往右或者往下走了。一个机器人每次只能向下或者向右移动一步。给定一个包含非负整数的。【递归+记忆化搜索】
2024-03-24 23:55:13
280
原创 LeetCode 刷题-322, 从递归到记忆化搜索到动态规划
上述递归调用,并不能完全通过用例,从给出来的图也可以看出,递归的过程中是有很多节点进行了重复计算的,那么可以进行优化,定义一个数组,用于存放计算过的节点数据,这样递归的过程中,如果发现已经计算过了,直接从数组中取值就可以了,不需要重复计算。拿到这个题,一开始考虑的是用贪心算法,即每次尽可能取最大的硬币,但是这种思路有个很大的问题,就是每次取最大的值,计算到后面不一定能拼出等于amount的解。本题其实也就是找路径的问题,可以看做是一个树形结构。,表示不同面额的硬币;你可以认为每种硬币的数量是无限的。
2024-03-24 22:05:43
469
原创 字符串String
这里值得注意的是,只有使用引号包含文本的方式创建的字符串对象之间使用“+”连接产生的新对象才会被加入字符串常量池中。这也很好理解,因为常量池是为了提高效率而设置的,如果每连接两个变量字符串都要在常量池中创建一份的话,那常量池的容量大小岂不是要爆了,毕竟字符串的组合可以千变万化。* 2.1、池化思想,字面量创建字符串时,字符串常量池会返回已有对象的引用,如果字符串可变,那么引用的值就会改变,常量池就无法复用了。一个变量只读时,变量的值不能被修改,但是不意味着这个值不会改变,比如一个人的年龄。
2024-03-21 15:50:02
593
1
原创 java并发编程之 volatile关键字
Java 内存模型(Java Memory Model 简称JMM)是一种抽象的概念,并不真实存在,指一组规则或规范,通过这组规范定义了程序中各个变量的访问方式。java内存模型(JMM)屏蔽掉各种硬件和操作系统的内存访问差异,以实现让java程序在各种平台下都能达到一致的并发效果。所有的共享变量都存储在主内存中(包括实例变量、类变量,静态变量,但是不包括局部变量,因为局部变量是线程私有的,不存在多线程之间的竞争)每个线程都有自己的工作内存,线程工作内存中保留了被线程使用的共享变量的副本。
2024-03-14 17:09:37
1255
原创 阻塞队列学习
队列为空的时候,获取元素的线程会等待队列变为非空。队列为满的时候,存储元素的线程会等待队列可以放入元素。添加元素的方法offer(E e):添加元素,不涉及阻塞offer(E e, long timeout, TimeUnit unit):带时间参数的offer,如果队列满了,会阻塞指定时间进行尝试添加,超时才会返回falseput(E e) : 如果没办法添加到队列中,就会一直阻塞下去取出元素的方法(取出并移除):poll() :取出元素,取不到就返回null。
2024-03-11 22:06:46
835
原创 线程池ThreadPoolExecutor,线程的一些基础知识学习
除了构造器中需要传入的7个参数外,还要重点关注一下以下属性ctl:原子类int, ThreadPoolExecutor用这样一个32位的int类型维护了两个核心属性线程池状态:高三位表示工作线程的个数:低29位表示,因此一个ThreadPoolExecutor最多运行2^29个工作线程workers:存放工作线程的集合,是一个HashSet,因此在添加工作线程到workers里面的时候,要加锁保证线程安全mainLock:一个ReentrantLock可重入锁/**
2024-03-04 20:32:14
676
原创 HashMap 源码学习-jdk1.8
这里针对MIN_TREEIFY_CAPACITY 这个值进行解释一下。java8里面,HashMap 的数据结构是数组 + (链表或者红黑树),每个数组节点下可能会存在链表和红黑树之间的转换,当同一个索引下面的节点超过8个时,首先会看当前数组长度,如果大于64,则会发生链表向红黑树的 转换,否则不会转换,而是扩容。// 默认的初始化长度 16// aka 16// 默认的最大容量 2^30// 默认的扩容因子// 链表转为树的阈值// 树转为链表的阈值// map已存节点的数量。
2024-02-22 21:35:38
1062
原创 并发编程 java锁机制
并发环境下,会存在多个线程对同一个资源进行争抢的情况,假设线程A对资源正在进行修改,此时线程B又对同一资源进行了修改,就会导致数据不一致的问题。为了解决这个问题,很多编程语言引入了锁机制。通过一种抽象的“锁”来对资源进行锁定,当一个线程持有“锁”时,其他线程必须等待 ------ 在临界资源上对线程进行一种串行化处理。java中,悲观锁的实现是基于object的 ------ 也就是说,每个对象都拥有一把锁,这个锁存放在对象头中,记录了当前对象被哪个线程所占用(持有)。
2024-02-07 20:26:06
1021
原创 ZK和redis中是否会发生脑裂问题?
简单的说,就好比一个人有两个大脑,这种情况下,就不知道应该受那个大脑控制了。在redis或者zk集群中,就是主从结构中出现了多个master。
2023-11-06 21:22:00
331
2
原创 mysql
二叉查找树的查询效率为O(logn),当树过高的时候,查找效率会下降,另外,索引文件是存在磁盘上的,文件系统从磁盘读取数据的时候,一般以页为单位进行读取,4K或者8K,如果一个页内的数据过少,会涉及到多次IO,大大降低效率。可以看到,联合索引中,a是有序的,b是无序的,但是在a等值的情况下b是有序的,这种情况下:b=2,不会走索引,a>1 and b=4;使用union时,多个相等的行会被合并,并且这个合并是比较耗时的,如果没有特别要求,尽量使用union all进行合并,过滤的时候在代码里面进行过滤。
2023-10-16 21:39:26
428
原创 使用POI实现操作Excel文件。
xls是Excel03版本,最大支持65536行、256列,poi 操作xls,使用HSSFWorkbookxlsx是Excel007版本,最大支持1048576行、16384列,poi-ooml操作xlsx,使用XSSFWorkbook。
2023-09-11 20:48:36
1089
原创 RabbitMQ学习笔记
MQ全称message queue(消息队列),本质是一个队列,FIFO先进先出,是消息传送过程中保存消息的容器,多 用于分布式系统之间进行通信。在互联网架构中,MQ是一种非常常见的上下游“逻辑解耦+物理解耦”的消息通讯服务,使用了MQ后,消息发送上游只需要依赖MQ,不需要依赖其他的服务。
2023-09-07 22:15:46
424
原创 kafka学习笔记
数据传输的事务定义有三种级别:1、最多一次,消息不回重复发送,最多被传输一次,但也有可能一次不传输2、最少一次,消息不会漏发,但是可能会被重复传输3、精确的一次(exactly one):不会漏传,但是也不会重复传输,是大家所期望的。
2023-08-28 20:12:21
1978
原创 JVM调优相关
它位于java的bin目录下,主要利用JVM内建的指令对Java应用程序的资源和性能进行实时的命令行的监控,包括了对Heap size和。--- 和第三步一样,其实就是将堆栈信息打印到文件中,便于查看。获取jvm进程中所有对象的信息 ---- 对象过多,对象又没有办法有效释放,就产生了full GC。--- 打印heap的概要信息,GC使用的算法,heap(堆)的配置及JVM堆内存的使用情况.--- 查看当前Java线程的堆栈信息 ----重点关注。---命令获取CPU占用率最高的进程的进程ID。
2023-06-29 12:01:15
168
原创 Java中优雅的判空 -- Optional
最近在做form表单导出,设计到很多需要判空的地方,一个方法里面频繁的判断is null太麻烦了,因此可以使用Java8新特性 optional。如,对象内嵌套很深,需要取出某个字段的值,按照如下方式写就可以。
2023-06-26 16:02:56
472
原创 LeetCode刷题 --- 哈希表
除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。对字符串做一个分割,然后遍历,把单词存入到map中,最后取出符合要求的单词即可。上面是用双指针解题,其实双指针的题目很容易用滑动窗口的模板来套用解题。看题意,其实就是要把字母相同顺序不同的字符串进行分组。387. 字符串中的第一个唯一字符。3. 无重复字符的最长子串。解题思路 --- 滑动窗口。136. 只出现一次的数字。解题思路 -- 哈希表。49. 字母异位词分组。解题3 --- 位运算。819. 最常见的单词。
2023-06-01 20:32:35
551
原创 数据结构 -- AVL树
平衡搜索二叉树,相对于搜索二叉树而言,AVL树又多了一个性质:左右子树的高度差不大于1.2、平衡因子,balance factor,以下简称bf,是左子树高度减去右子树的高度。检查节点是否失衡,如果失衡,就平衡,然后返回新的跟节点。5、平衡操作,发生在新增,删除时,对树进行平衡的操作。右旋方法:传入要旋转的节点,返回值是新的根节点。左右旋方法 --- 先左旋左子树,在右旋跟节点。插入的时候,要更新节点高度,并平衡树。右子树先右旋,失衡节点在左旋。左子树先左旋,失衡节点右旋。7、 节点的删除操作。
2023-05-29 20:13:08
689
原创 数据结构 --- 树
把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。循环或者递归,比较key的值,key比当前节点的key大,就往右子树找,key比当前节点的key小,就往左子树找,找不到就返回null。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。递归,但是要注意一点,如果左右子树为null的时候,就不应该计算进去。二叉搜索树满足:节点的key大于左子树的key,小于右子树的key。给树的节点定义一个key,是不可用重复的。
2023-05-27 21:13:20
805
原创 LeetCode刷题 --- 两个关联数组的排序技巧
刷题的过程中,经常会遇到一些题目中给了关联数组,即 int[] values1 ,int[] values2,解题过程中需要根据某个数组的值进行排序,但是要同时保证另外一个关联数组也按照同样规则排序。构建一个一维数组,存储数组的坐标,然后根据排序规则新数组,取值根据坐标取就OK了。给定的两个数组按照value值进行关联排序,后面按照题意解题即可。构造二元数组,然后排序,后续取值的时候,从二元数组中取值。如下:根据values的进行从大到小排序。如下:根据values的进行从大到小排序。
2023-05-24 12:02:45
138
原创 数据结构 --- 堆
题目比较难以理解,简单的说就是,给一个数组,和一个k的值,进行初始化,每次add的时候,加入一个元素,然后,把当前数据里面第K大的元素删除并返回。前面已经实现了大顶堆,其实poll方法拿出来的,就是当前最大的元素,因此排序方法可以写成下面的格式。找到堆中的最后一个非叶子节点,从当前节点往前遍历,不断的执行下沉操作。不断的往定义的列表中添加数据,取这个列表中的中位数。移除指定元素的操作,思路也是一样的,代码如下。3、堆的构造方法 --- 建立堆的操作。请注意,你需要找的是数组排序后的第。
2023-05-23 22:45:45
596
原创 数据结构 -- 队列
因为一把锁的时候,offer拿锁,poll会阻塞,因此在size++的过程中,就不可能出现size++的操作,故是线程安全的,而两把锁的时候,offer和poll互不影响,因此就可能在size++的时候出现size-- 导致线程不安全。poll:定义一个max指针,先指向最后面,然后不断往前遍历,如果前面的优先级大,那么就更新max的值,找到最大的max,删除该位置元素,然后后面数组向前移动。这个题是一个变形的二叉树层序遍历,可以用BFS求解,值得注意的是,每隔一层,输出的值顺序是相反的。
2023-05-23 14:40:14
550
原创 LeetCode刷题 --- 栈
图示,先push1,2,3,然后peek,栈1内元素转到栈2,后面只要栈2不为null,就可以执行pop和peek操作,如果为空,在吧元素从栈1转到栈2 就可以了。每次入栈的时候,判断当前元素和栈顶元素是否配对,如果配对,则弹出,如果不配对,则继续入栈。最后栈元素为空,则true,否则,为false。遇到左括号,则对应的右括号入栈,遇到右括号,则比较与栈顶元素是否一致,一致则出栈,继续,否则直接返回false。请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(
2023-05-19 21:47:20
557
原创 LeetCode刷题 --- 链表
参考上一题,定义哨兵节点,以及三个指针节点,仍然按照p和q比较,遍历,多定义的r节点,是p节点的上一个节点,pq相同的时候,q不断后移,一直移到为null或者值不同,然后将r的下一个节点指向q。去重,可以使用Map或者set ,遍历链表,如果节点的值已经在集合中存在,那么这个节点就是重复节点,可以删除,如果不存在,则将值存入集合,继续遍历。定义两个指针节点p和q,分别指向头节点,先让q节点向后移动n步,然后,在让p和q同时后移,当q指向空的时候,p恰好是倒数第n个节点的前一个节点。
2023-05-18 11:56:55
549
原创 定时任务,ScheduledExecutorService
ScheduledExecutorService可以实现任务的循环执行,可以当做一个简单的定时任务组件,因有线程池的特性,因此可以多任务之间线程并发执行,不影响主线程业务。以上一次任务执行时间为准,加上任务时间间隔作为下一次任务开始的时间。注意,如果没有try catch住,出现异常了,那么后续定时任务就无法继续执行了。注意,如果没有try catch住,出现异常了,那么后续定时任务就无法继续执行了。如果没有执行完毕,则等待上一个任务执行完,立刻执行。因此,此方法不能严格保证任务一定按照时间间隔去执行。
2023-03-23 17:22:54
1697
原创 SpringMVC 面试题
SpringMVC是一个基于Java的实现了MVC设计模式的“请求驱动型”的轻量级WEB框架,通过把model,view,controller 分离,将web层进行职责的解耦,把复杂的web应用分成逻辑清晰的几个部分,简化开发,减少出错,方便开发人员之间的配合。在系统运行过程中,可能由于运行环境,用户操作,资源不足等各方面导致系统出现异常,我们通常不希望将这些异常呈现给用户,因此可以在服务器进行特点的处理,当异常发生时,呈现给用户一个统一的,可读的异常提示界面。如果是,有什么问题,怎么解决?
2023-02-28 20:57:25
266
原创 spring面试题总结
IOC,inversion of control,控制反转,将对象的控制权转移给spring框架进行管理,由spring来控制对象的生命周期(创建,销毁)和对象之间的依赖关系。也就是说,以前创建对象的时机和主动权是由开发者把握的,如果在一个对象中使用外面的对象,就需要new去创建对象,用完后还涉及到对象的销毁,这种情况下,当前对象就会和其他的接口或者类耦合起来。
2023-02-26 17:18:47
337
原创 spring 笔记
aspect oriented programming 面向切面编程,是一种利用横切的技术,对原有的业务逻辑进行拦截,并且可以在这个拦截的横切面上添加特点的业务逻辑,实现不改变代码对原有业务的增强。JDK动态代理是通过被代理类实现的接口来创建代理对象的,因此JDK动态代理只能代理实现了接口的类的对象。CGLib动态代理,是通过创建被代理类的子类来创建代理对象的,因此即使没有实现任何接口的类也可以通过CGLib产生代理对象。spring ioc 容器组件,可以完成对象的创建,对象属性赋值,对象的管理。
2023-02-11 15:24:01
696
原创 Mybatis 笔记
本质是通过动态代理的方式,创建目标对象的代理对象,调用目标方法时(getting方法),进入拦截器方法,⽐如调⽤ a.getB().getName() ⽅法,进⼊拦截器的 invoke(...) ⽅法,发现 a.getB() 需要延迟加载时(为null时),那么就会单独发送事先保存好的查询关联 B 对象的 SQL ,把 B 查询上来,然后调⽤ a.setB(b) ⽅法,于是 a 对象 b 属性就有值了,接着完成 a.getB().getName() ⽅法的调⽤。关联对象的查询时子查询,多表连接查询则不行。
2023-01-31 19:56:59
248
原创 MySQL中的Buffer pool,以及各种buffer
buffer pool是一块内存区域,是一种“降低磁盘访问机制”,buffer pool缓存数据表和索引数据,吧磁盘上的数据加载到缓冲池,避免每次访问都进行磁盘IO,起到加速访问的作用。buffer pool也是以页为存储单位(与磁盘中数据页索引页单位一样,默认大小16K),buffer pool底层采用链表的数据结构管理page。所有数据页的读写操作都要通过buffer pool进行。
2023-01-19 15:03:27
1461
原创 MySQL 的事务
事务是一个最小的,不可在分割的工作单元,通常一个事务对应一个完整的业务,一个完整的业务需要批量的DML(insert,update,delete)语句共同联合完成。
2023-01-05 21:33:32
605
原创 LeetCode刷题 -- 一些经典的例题
ASCII:将英语中的字符表示为数字的代码。为每个字符分配一个介于 0 到 127 之间的数字。将A~Z对应位号存入相应的数据,比如记录一个字母出现了多少次 (小写字母同理)我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。常见的ASCII码大小比较:0~9
2022-12-20 17:15:57
259
原创 JVM
程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。Java虚拟机的多线程是通过线程轮流切换并分配CPU时间片的方式来实现的,因此为了保证线程切换后能够恢复到正确的执行位置,每条线程都有一个独立的程序计数器,各个线程之间的程序计数器互不影响,独立存储,是线程私有内存。如果执行的是一个Java方法,这个计数器记录的就是正则执行的虚拟机字节码指令地址,如果执行的是本地native方法,这个计数器的值则为空 undefined。
2022-12-13 20:48:31
193
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人