Date: Thu, 22 May 2025 18:26:21 +0800
Subject: [PATCH 76/80] update
---
.../Solution.java" | 35 ++++++++++++++++++-
1 file changed, 34 insertions(+), 1 deletion(-)
diff --git "a/src/\345\212\250\346\200\201\350\247\204\345\210\222/q1143_\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227/Solution.java" "b/src/\345\212\250\346\200\201\350\247\204\345\210\222/q1143_\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227/Solution.java"
index 8225a50..9f55848 100644
--- "a/src/\345\212\250\346\200\201\350\247\204\345\210\222/q1143_\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227/Solution.java"
+++ "b/src/\345\212\250\346\200\201\350\247\204\345\210\222/q1143_\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227/Solution.java"
@@ -2,7 +2,7 @@
/**
* 动态规划 dp[i + 1][j + 1] = Math.max(dp[i+1][j], dp[i][j+1]) o(m*n)
- *
+ *
* 若题目为最长公共子串,则在c1,c2不相等时不做处理(赋值0),在遍历过程中记录最大值即可
*/
public class Solution {
@@ -25,4 +25,37 @@ public int longestCommonSubsequence(String text1, String text2) {
}
return dp[m][n];
}
+
+ /**
+ * 最长公共字串
+ *
+ * @param str1
+ * @param str2
+ * @return
+ */
+ public static String longestCommonSubstring(String str1, String str2) {
+ int m = str1.length();
+ int n = str2.length();
+ int[][] dp = new int[m + 1][n + 1];
+ int maxLength = 0;
+ int endIndex = -1;
+
+ for (int i = 1; i <= m; i++) {
+ for (int j = 1; j <= n; j++) {
+ if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
+ dp[i][j] = dp[i - 1][j - 1] + 1;
+ if (dp[i][j] > maxLength) {
+ maxLength = dp[i][j];
+ endIndex = i - 1;
+ }
+ } else {
+ dp[i][j] = 0;
+ }
+ }
+ }
+ if (maxLength == 0) {
+ return "";
+ }
+ return str1.substring(endIndex - maxLength + 1, endIndex + 1);
+ }
}
From 73cf06a9d0cfaa942f160e7b6219863c994259b8 Mon Sep 17 00:00:00 2001
From: "guangxin.yuan"
Date: Mon, 26 May 2025 15:30:28 +0800
Subject: [PATCH 77/80] update
---
src/Solution.java | 81 -----------------------------------------------
1 file changed, 81 deletions(-)
delete mode 100644 src/Solution.java
diff --git a/src/Solution.java b/src/Solution.java
deleted file mode 100644
index ce72957..0000000
--- a/src/Solution.java
+++ /dev/null
@@ -1,81 +0,0 @@
-public class Solution {
-
- // 找到旋转数组的最小值位置
- private static int findMinIndex(int[] nums) {
- int left = 0;
- int right = nums.length - 1;
-
- while (left < right) {
- int mid = left + (right - left) / 2;
- if (nums[mid] > nums[right]) {
- left = mid + 1;
- } else {
- right = mid;
- }
- }
- return left; // 最小值的位置
- }
-
- // 快速选择算法(类似快速排序的分区操作)
- private static int quickSelect(int[] nums, int start, int end, int k) {
- if (start == end) {
- return nums[start];
- }
-
- int pivot = partition(nums, start, end);
-
- if (pivot == k) {
- return nums[pivot];
- } else if (pivot > k) {
- return quickSelect(nums, start, pivot - 1, k);
- } else {
- return quickSelect(nums, pivot + 1, end, k);
- }
- }
-
- // 快速排序的分区操作
- private static int partition(int[] nums, int start, int end) {
- int pivot = nums[end];
- int i = start - 1;
-
- for (int j = start; j < end; j++) {
- if (nums[j] >= pivot) { // 从大到小排序
- i++;
- swap(nums, i, j);
- }
- }
-
- swap(nums, i + 1, end);
- return i + 1;
- }
-
- // 交换数组中的两个元素
- private static void swap(int[] nums, int i, int j) {
- int temp = nums[i];
- nums[i] = nums[j];
- nums[j] = temp;
- }
-
- // 主函数:在旋转数组中找到第 k 大的数字
- public static int findKthLargest(int[] nums, int k) {
- int minIndex = findMinIndex(nums); // 找到最小值的位置
- int n = nums.length;
-
- // 将数组分为两部分,分别查找第 k 大的数字
- if (k <= n - minIndex) {
- // 第 k 大的数字在后半部分
- return quickSelect(nums, minIndex, n - 1, k - 1);
- } else {
- // 第 k 大的数字在前半部分
- return quickSelect(nums, 0, minIndex - 1, k - (n - minIndex) - 1);
- }
- }
-
- public static void main(String[] args) {
- int[] nums = {4, 5, 6, 7, 0, 1, 2};
- int k = 3;
-
- int result = findKthLargest(nums, k);
- System.out.println("第 " + k + " 大的数字是: " + result);
- }
-}
\ No newline at end of file
From a4ebe6c685b740b897df2f09d8bc2b3ae766fa0b Mon Sep 17 00:00:00 2001
From: "guangxin.yuan"
Date: Fri, 30 May 2025 12:42:13 +0800
Subject: [PATCH 78/80] update
---
Rocket.md | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/Rocket.md b/Rocket.md
index add3805..914de88 100644
--- a/Rocket.md
+++ b/Rocket.md
@@ -279,7 +279,7 @@ SQL的执行顺序:from---where--group by---having---select---order by
* undoLog 也就是我们常说的回滚日志文件 主要用于事务中执行失败,进行回滚,以及MVCC中对于数据历史版本的查看。由引擎层的InnoDB引擎实现,是逻辑日志,记录数据修改被修改前的值,比如"把id='B' 修改为id = 'B2' ,那么undo日志就会用来存放id ='B'的记录”。当一条数据需要更新前,会先把修改前的记录存储在undolog中,如果这个修改出现异常,,则会使用undo日志来实现回滚操作,保证事务的一致性。当事务提交之后,undo log并不能立马被删除,而是会被放到待清理链表中,待判断没有事物用到该版本的信息时才可以清理相应undolog。它保存了事务发生之前的数据的一个版本,用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读。
* redoLog 是重做日志文件是记录数据修改之后的值,用于持久化到磁盘中。redo log包括两部分:一是内存中的日志缓冲(redo log buffer),该部分日志是易失性的;二是磁盘上的重做日志文件(redo log file),该部分日志是持久的。由引擎层的InnoDB引擎实现,是物理日志,记录的是物理数据页修改的信息,比如“某个数据页上内容发生了哪些改动”。当一条数据需要更新时,InnoDB会先将数据更新,然后记录redoLog 在内存中,然后找个时间将redoLog的操作执行到磁盘上的文件上。不管是否提交成功我都记录,你要是回滚了,那我连回滚的修改也记录。它确保了事务的持久性。每个InnoDB存储引擎至少有1个重做日志文件组(group),每个文件组下至少有2个重做日志文件,如默认的ib_logfile0和ib_logfile1。为了得到更高的可靠性,用户可以设置多个的镜像日志组(mirrored log groups),将不同的文件组放在不同的磁盘上,以此提高重做日志的高可用性。在日志组中每个重做日志文件的大小一致,并以循环写入的方式运行。InnoDB存储引擎先写重做日志文件1,当达到文件的最后时,会切换至重做日志文件2,再当重做日志文件2也被写满时,会再切换到重做日志文件1中。
-* MVCC多版本并发控制是MySQL中基于乐观锁理论实现隔离级别的方式,用于读已提交和可重复读取隔离级别的实现。在MySQL中,会在表中每一条数据后面添加两个字段:最近修改该行数据的事务ID,指向该行(undolog表中)回滚段的指针。Read View判断行的可见性,创建一个新事务时,copy一份当前系统中的活跃事务列表。意思是,当前不应该被本事务看到的其他事务id列表。已提交读隔离级别下的事务在每次查询的开始都会生成一个独立的ReadView,而可重复读隔离级别则在第一次读的时候生成一个ReadView,之后的读都复用之前的ReadView。
+* MVCC多版本并发控制是MySQL中基于乐观锁理论实现隔离级别的方式,用于读已提交和可重复读取隔离级别的实现。在MySQL中,会在表中每一条数据后面添加两个字段:最近修改该行数据的事务ID,指向该行(undolog表中)回滚段的指针。Read View判断行的可见性,创建一个新事务时,copy一份当前系统中的活跃事务列表。意思是,当前不应该被本事务看到的其他事务id列表。已提交读隔离级别下的事务在每次查询的开始都会生成一个独立的ReadView,而可重复读隔离级别则在第一次读的时候生成一个ReadView,之后的读都复用之前的ReadView。MVCC的可以实现不同的隔离级别,这取决于是否针对同一个事物生成一个还是多个ReadView。
### binlog和redolog的区别
@@ -859,6 +859,11 @@ Spring使用了三级缓存解决了循环依赖的问题。在populateBean()给
6. NEVER:无事务执行,如果当前有事务则抛出Exception。
7. NESTED:嵌套事务,如果当前事务存在,那么在嵌套的事务中执行。如果当前事务不存在,则表现跟REQUIRED一样。
+### Spring中的@Conditional注解
+1. @Conditional 注解是一个非常强大的功能,用于根据特定条件动态决定是否创建某个Bean。它允许开发者在运行时根据不同的环境、配置或其他因素来灵活地控制Bean的实例化过程。
+2. 它的核心作用是基于条件判断来决定是否加载对应的Bean。如果条件成立,则创建并注册该Bean;如果条件不成立,则跳过该Bean的创建。
+3. @Conditional 注解需要配合一个或多个条件类(实现了 Condition 接口的类)一起使用。条件类需要实现 Condition 接口的 matches 方法,该方法返回一个布尔值,用于判断条件是否满足。
+
### Spring中Bean的生命周期
1. 实例化 Instantiation
From e372fd07b37138e2f00a7302981bb6b50cf04056 Mon Sep 17 00:00:00 2001
From: "guangxin.yuan"
Date: Thu, 5 Jun 2025 21:45:27 +0800
Subject: [PATCH 79/80] update
---
Rocket.md | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/Rocket.md b/Rocket.md
index 914de88..f8cd7a7 100644
--- a/Rocket.md
+++ b/Rocket.md
@@ -89,7 +89,10 @@ quicklist 的设计,其实是结合了链表和 ziplist 各自的优势。简
listpack 也叫紧凑列表,它的特点就是用一块连续的内存空间来紧凑地保存数据,同时为了节省内存空间,listpack 列表项使用了多种编码方式,来表示不同长度的数据,这些数据包括整数和字符串。在 listpack 中,因为每个列表项只记录自己的长度,而不会像 ziplist 中的列表项那样,会记录前一项的长度。所以,当我们在 listpack 中新增或修改元素时,实际上只会涉及每个列表项自己的操作,而不会影响后续列表项的长度变化,这就避免了连锁更新。
-###
+### Redis的跳表和Mysql的B+树结构
+1. B+树是多叉平衡搜索树,只需要3层左右就能存放2kw左右的数据,同样情况下跳表则需要24层左右,假设层高对应磁盘IO,那么B+树的读性能会比跳表要好,因此mysql选了B+树做索引。
+2. redis的读写全在内存里进行操作,不涉及磁盘IO,同时跳表实现简单,相比B+树、AVL树、少了旋转树结构的开销,因此redis使用跳表来实现ZSET,而不是树结构。
+3. 存储引擎RocksDB内部使用了跳表,对比使用B+树的innodb,虽然写性能更好,但读性能属实差了些。在读多写少的场景下,B+树依旧是最佳选择。
### Redis 的数据过期策略
@@ -324,6 +327,7 @@ MySQL为了保证ACID中的一致性和持久性,使用了WAL(Write-Ahead Logg
* 平衡二叉树:通过旋转解决了平衡的问题,但是旋转操作效率太低。
* 红黑树:通过舍弃严格的平衡和引入红黑节点,解决了 AVL旋转效率过低的问题,但是在磁盘等场景下,树仍然太高,IO次数太多。
* B+树:在B树的基础上,将非叶节点改造为不存储数据纯索引节点,进一步降低了树的高度;此外将叶节点使用指针连接成链表,范围查询更加高效。
+* B+树是由多个页组成的多层级结构,每个页16Kb,对于主键索引来说,最末级的叶子结点放行数据,非叶子结点放的则是索引信息(主键id和页号),用于加速查询。
### B+树的叶子节点都可以存哪些东西
From 30f3afaa3fc5aa9ce357f6569488c7fa785e56e5 Mon Sep 17 00:00:00 2001
From: "guangxin.yuan"
Date: Sat, 7 Jun 2025 18:03:51 +0800
Subject: [PATCH 80/80] update
---
Rocket.md | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/Rocket.md b/Rocket.md
index f8cd7a7..5785a8e 100644
--- a/Rocket.md
+++ b/Rocket.md
@@ -480,7 +480,11 @@ JVM引入动态年龄计算,主要基于如下两点考虑:
在执行垃圾收集算法时,Java应用程序的其他所有除了垃圾收集收集器线程之外的线程都被挂起。此时,系统只能允许GC线程进行运行,其他线程则会全部暂停,等待GC线程执行完毕后才能再次运行。这些工作都是由虚拟机在后台自动发起和自动完成的,是在用户不可见的情况下把用户正常工作的线程全部停下来,这对于很多的应用程序,尤其是那些对于实时性要求很高的程序来说是难以接受的。
-但不是说GC必须STW,你也可以选择降低运行速度但是可以并发执行的收集算法,这取决于你的业务。
+### 如果不STW可能会出现的问题
+
+1. 数据一致性问题: 如果不STW,应用程序线程和垃圾回收线程同时运行,可能会导致数据不一致。例如,在垃圾回收线程正在标记对象时,应用程序线程可能对对象的引用关系进行了修改。比如原本一个对象A引用对象B,垃圾回收线程在标记过程中认为对象B是可回收的,但应用程序线程在垃圾回收线程标记完成后,又重新创建了一个引用指向对象B,这就导致了垃圾回收器错误地回收了对象B,而应用程序线程还在使用它,从而引发错误。
+2. 内存泄漏风险增加: 如果垃圾回收线程不能准确地识别存活对象,可能会导致一些本应该被回收的对象没有被回收或者不该被回收的对象会被错误的垃圾回收。例如,当应用程序线程在垃圾回收过程中动态地创建和销毁对象时,垃圾回收线程如果没有暂停应用程序线程,可能会遗漏一些已经没有引用的对象。这些对象会一直占用内存,随着时间的推移,可能导致内存泄漏,最终使Java虚拟机的堆内存耗尽,引发OutOfMemoryError错误。
+3. 垃圾回收效率降低: 在并发环境中,垃圾回收线程和应用程序线程的交互会变得更加复杂。垃圾回收线程需要处理应用程序线程对对象的动态修改,这会增加垃圾回收的复杂性和开销。例如,垃圾回收线程需要不断检查应用程序线程对对象引用的修改,以确保垃圾回收的准确性。这种并发操作可能会导致垃圾回收的效率降低,使得垃圾回收时间变长,虽然没有STW,但可能会以更频繁的垃圾回收或者更长的垃圾回收周期来弥补,从而影响应用程序的整体性能。
### 垃圾回收算法
@@ -926,6 +930,12 @@ Kafka最初考虑的问题是,customer应该从brokes拉取消息还是brokers
3. 当两者相等,则所有broker都启用,吞吐达到瓶颈。
4. 继续增加,则broker会不均衡,有点会分到更多的partition,顺序IO退化成随机IO。
+### Kafka的rebalance机制
+
+1. 消费者的再平衡是指分区的所属权从一个消费者转移到另一消费者的行为,它为消费组具备高可用性和伸缩性提供保障, 使我们可以既方便又安全地删除消费组内的消费者或往消费组内添加消费者。不过在再平衡发生期间, 消费组内的消费者是无法读取消息的。
+2. 再平衡会在以下情况下被触发:消费者加入或离开消费者组,消费者心跳超时或会话过期,分区数量变化,消费者处理超时。
+3. 再平衡的影响:传统再平衡会使所有消费者在再平衡期间会停止消费,直到新的分区分配完成。增量式再平衡可以让部分消费者可以继续消费未被重新分配的分区,减少停顿时间。
+
### Kafka中partition数量和消费者数量设置
消费者的数量不应该比分区数多,因为多出来的消费者是空闲的,没有任何帮助