From dfc04283827ec5fe73e847f779b2be938166cf74 Mon Sep 17 00:00:00 2001 From: dunwu Date: Sat, 27 Jan 2024 23:05:50 +0800 Subject: [PATCH 01/21] =?UTF-8?q?feat:=20=E6=95=B4=E7=90=86=E5=9B=BE?= =?UTF-8?q?=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +-- docs/.vuepress/config.js | 2 +- ...02\345\272\246\345\210\206\346\236\220.md" | 6 ++-- ...04\345\222\214\351\223\276\350\241\250.md" | 32 +++++++++---------- ...10\345\222\214\351\230\237\345\210\227.md" | 14 ++++---- ...50\347\232\204\346\216\222\345\272\217.md" | 20 ++++++------ ...14\344\272\214\345\217\211\346\240\221.md" | 28 ++++++++-------- .../02.\346\240\221/02.\345\240\206.md" | 2 +- .../02.\346\240\221/03.B+\346\240\221.md" | 4 +-- .../02.\346\240\221/04.LSM\346\240\221.md" | 6 ++-- ...5.\345\255\227\345\205\270\346\240\221.md" | 18 +++++------ ...6.\347\272\242\351\273\221\346\240\221.md" | 14 ++++---- ...3.\345\223\210\345\270\214\350\241\250.md" | 6 ++-- .../04.\350\267\263\350\241\250.md" | 12 +++---- .../05.\345\233\276.md" | 4 +-- docs/README.md | 2 +- 16 files changed, 87 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index b4e1ecc..365fc6e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- logo + logo

@@ -35,7 +35,7 @@ ## 📖 内容 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200702071922.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200702071922.png) - 综合 - [数据结构和算法指南](docs/01.数据结构和算法/00.综合/01.数据结构和算法指南.md) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 48ad816..f18b41b 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -26,7 +26,7 @@ module.exports = { themeConfig: { nav: [], sidebarDepth: 2, // 侧边栏显示深度,默认1,最大2(显示到h3标题) - logo: 'https://raw.githubusercontent.com/dunwu/images/dev/common/dunwu-logo.png', // 导航栏logo + logo: 'https://raw.githubusercontent.com/dunwu/images/master/common/dunwu-logo.png', // 导航栏logo repo: 'dunwu/algorithm-tutorial', // 导航栏右侧生成Github链接 searchMaxSuggestions: 10, // 搜索结果显示最大数 lastUpdated: '上次更新', // 更新的时间,及前缀文字 string | boolean (取值为git提交时间) diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/00.\347\273\274\345\220\210/02.\345\244\215\346\235\202\345\272\246\345\210\206\346\236\220.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/00.\347\273\274\345\220\210/02.\345\244\215\346\235\202\345\272\246\345\210\206\346\236\220.md" index 87431ae..8ff51fc 100644 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/00.\347\273\274\345\220\210/02.\345\244\215\346\235\202\345\272\246\345\210\206\346\236\220.md" +++ "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/00.\347\273\274\345\220\210/02.\345\244\215\346\235\202\345\272\246\345\210\206\346\236\220.md" @@ -86,7 +86,7 @@ T(n) = (M-1)(N-1) = O(M*N) ≈ O(N^2) 【示例】递归函数的时间复杂度是多少?思考一下斐波那契数列 `f(n) = f(n-1) + f(n-2)` 的时间复杂度是多少? -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320110642.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320110642.png) ``` T(n) = O(2^N) @@ -114,7 +114,7 @@ T(n) = O(2^N) 在数据量比较小的时候,复杂度量级差异并不明显;但是,随着数据规模大小的变化,差异会逐渐突出。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320160627.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320160627.png) `O(1)` 复杂度示例: @@ -164,7 +164,7 @@ for (int i = 1; i <= Math.pow(2, max); i++) { ## 常见数据结构的复杂度 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200702071922.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200702071922.png) ## 参考资料 diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/01.\346\225\260\347\273\204\345\222\214\351\223\276\350\241\250.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/01.\346\225\260\347\273\204\345\222\214\351\223\276\350\241\250.md" index 7b9ca4a..343b216 100644 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/01.\346\225\260\347\273\204\345\222\214\351\223\276\350\241\250.md" +++ "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/01.\346\225\260\347\273\204\345\222\214\351\223\276\350\241\250.md" @@ -25,17 +25,17 @@ permalink: /pages/5a9bff/ 数组元素的访问是以行或列索引的单一下标表示。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320115836.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320115836.png) 在上面的例子中,数组 a 中有 5 个元素。`也就是说`,a 的长度是 6 。我们可以使用 a[0] 来表示数组中的第一个元素。因此,a[0] = A 。类似地,a[1] = B,a[2] = C,依此类推。 ### 数组的插入 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320115848.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320115848.png) ### 数组的删除 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320115859.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320115859.png) ### 数组的特性 @@ -55,7 +55,7 @@ permalink: /pages/5a9bff/ 下图是由 M 个行向量,N 个列向量组成的二维数组. -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320152607.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320152607.png) ## 链表 @@ -80,7 +80,7 @@ permalink: /pages/5a9bff/ 单链表中的每个结点不仅包含数据值,还包含一个指针,指向其后继节点。通过这种方式,单链表将所有结点按顺序组织起来。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320174829.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174829.png) 与数组不同,我们无法在常量时间内访问单链表中的随机元素。 如果我们想要获得第 i 个元素,我们必须从头结点逐个遍历。 我们按 `索引` 来 `访问元素` 平均要花费 `O(N)` 时间,其中 N 是链表的长度。 @@ -90,15 +90,15 @@ permalink: /pages/5a9bff/ (1)使用给定值初始化新结点 `cur`; -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320174908.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174908.png) (2)将 `cur` 的 `next` 字段链接到 `prev` 的下一个结点 `next` ; -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320174919.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174919.png) (3)将 `prev` 中的 `next` 字段链接到 `cur` 。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320174932.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174932.png) 与数组不同,我们不需要将所有元素移动到插入元素之后。因此,您可以在 `O(1)` 时间复杂度中将新结点插入到链表中,这非常高效。 @@ -108,11 +108,11 @@ permalink: /pages/5a9bff/ (1)找到 `cur` 的上一个结点 `prev` 及其下一个结点 `next` ; -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320174953.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174953.png) (2)接下来链接 `prev` 到 `cur` 的下一个节点 `next` 。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320175006.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320175006.png) 在我们的第一步中,我们需要找出 `prev` 和 `next`。使用 `cur` 的参考字段很容易找出 `next`,但是,我们必须从头结点遍历链表,以找出 `prev`,它的平均时间是 `O(N)`,其中 `N` 是链表的长度。因此,删除结点的时间复杂度将是 `O(N)`。 @@ -124,7 +124,7 @@ permalink: /pages/5a9bff/ 单链表的访问是单向的,而双链表的访问是双向的。显然,双链表比单链表操作更灵活,但是空间开销也更大。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320181150.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320181150.png) 双链表以类似的方式工作,但`还有一个引用字段`,称为`“prev”`字段。有了这个额外的字段,您就能够知道当前结点的前一个结点。 @@ -134,15 +134,15 @@ permalink: /pages/5a9bff/ (1)使用给定值初始化新结点 `cur`; -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320181208.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320181208.png) (2)链接 `cur` 与 `prev` 和 `next`,其中 `next` 是 `prev` 原始的下一个节点; -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320181303.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320181303.png) (3)用 `cur` 重新链接 `prev` 和 `next`。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320181504.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320181504.png) 与单链表类似,添加操作的时间和空间复杂度都是 `O(1)`。 @@ -163,11 +163,11 @@ permalink: /pages/5a9bff/ - 单链表的最后一个结点的后继指针 `next` 指向空地址。 - 循环链表的最后一个结点的后继指针 `next` 指向第一个节点(如果有头节点,就指向头节点)。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220322190534.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220322190534.png) #### 循环双链表 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220322190423.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220322190423.png) ## 数组 vs. 链表 diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/02.\346\240\210\345\222\214\351\230\237\345\210\227.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/02.\346\240\210\345\222\214\351\230\237\345\210\227.md" index 1785714..2df6ac1 100644 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/02.\346\240\210\345\222\214\351\230\237\345\210\227.md" +++ "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/02.\346\240\210\345\222\214\351\230\237\345\210\227.md" @@ -24,7 +24,7 @@ permalink: /pages/1f15c3/ **栈是一个 LIFO(后进先出) 数据结构**。**栈是一种“操作受限”的线性表**,只允许在一端插入和删除数据。通常,插入操作在栈中被称作入栈 push 。与队列类似,总是在堆栈的末尾添加一个新元素。但是,删除操作,退栈 pop ,将始终删除队列中相对于它的最后一个元素。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320200148.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320200148.png) **当某个数据集合只涉及在一端插入和删除数据,并且满足后进先出、先进后出的特性,我们就应该首选“栈”这种数据结构**。 @@ -42,11 +42,11 @@ permalink: /pages/1f15c3/ (1)**函数调用栈** -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220310091000.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310091000.jpg) (2)**表达式求值** -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220310091100.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310091100.jpg) (3)**表达式匹配** @@ -66,7 +66,7 @@ permalink: /pages/1f15c3/ 队列的最基本操作:**入队 `enqueue()`**,放一个数据到队列尾部;**出队 `dequeue()`**,从队列头部取一个元素。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320200213.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320200213.png) 队列可以用数组来实现,也可以用链表来实现。用数组实现的队列叫作**顺序队列**,用链表实现的队列叫作**链式队列**。 @@ -80,7 +80,7 @@ permalink: /pages/1f15c3/ 在用数组实现的非循环队列中,队满的判断条件是 `(tail+1) % n == head`,队空的判断条件是 `head == tail`。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220322214822.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220322214822.png) ### 为什么需要队列 @@ -95,9 +95,9 @@ permalink: /pages/1f15c3/ - 在队列为空的时候,从队头取数据会被阻塞。因为此时还没有数据可取,直到队列中有了数据才能返回; - 如果队列已经满了,那么插入数据的操作就会被阻塞,直到队列中有空闲位置后再插入数据,然后再返回。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220310092908.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310092908.jpg) -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220310093026.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310093026.jpg) (2)**并发队列** diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/12.\347\272\277\346\200\247\350\241\250\347\232\204\346\216\222\345\272\217.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/12.\347\272\277\346\200\247\350\241\250\347\232\204\346\216\222\345\272\217.md" index 029c7ae..2bee638 100644 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/12.\347\272\277\346\200\247\350\241\250\347\232\204\346\216\222\345\272\217.md" +++ "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/12.\347\272\277\346\200\247\350\241\250\347\232\204\346\216\222\345\272\217.md" @@ -36,7 +36,7 @@ permalink: /pages/21c5f2/ 假设有一个大小为 N 的无序序列。冒泡排序就是要每趟排序过程中通过两两比较,找到第 i 个小(大)的元素,将其往上排。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/algorithm/sort/bubble-sort.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/bubble-sort.png) 以上图为例,演示一下冒泡排序的实际流程: @@ -179,7 +179,7 @@ public void bubbleSort_2(int[] list) { 详细的图解往往比大堆的文字更有说明力,所以直接上图: -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/algorithm/sort/quick-sort.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/quick-sort.png) 上图中,演示了快速排序的处理过程: @@ -284,7 +284,7 @@ private void quickSort(int[] list, int left, int right) { 在讲解直接插入排序之前,先让我们脑补一下我们打牌的过程。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/algorithm/sort/insert-sort.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/insert-sort.png) - 先拿一张 5 在手里, - 再摸到一张 4,比 5 小,插到 5 前面, @@ -384,7 +384,7 @@ public void insertSort(int[] list) { 我们来通过演示图,更深入的理解一下这个过程。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/algorithm/sort/shell-sort.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/shell-sort.png) 在上面这幅图中: @@ -490,7 +490,7 @@ Donald Shell 最初建议步长选择为 N/2 并且对步长取半直到步长 **核心代码** -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/algorithm/sort/selection-sort.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/selection-sort.png) ### 算法分析 @@ -544,7 +544,7 @@ Donald Shell 最初建议步长选择为 N/2 并且对步长取半直到步长 其中 i=1,2,…,n/2 向下取整; -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/algorithm/sort/heap-sort.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/heap-sort.png) 如上图所示,序列 R{3, 8,15, 31, 25} 是一个典型的小根堆。 @@ -578,13 +578,13 @@ Donald Shell 最初建议步长选择为 N/2 并且对步长取半直到步长 设有一个无序序列 { 1, 3,4, 5, 2, 6, 9, 7, 8, 0 }。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/algorithm/sort/heap-sort-02.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/heap-sort-02.png) 构造了初始堆后,我们来看一下完整的堆排序处理: 还是针对前面提到的无序序列 { 1,3, 4, 5, 2, 6, 9, 7, 8, 0 } 来加以说明。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/algorithm/sort/heap-sort-03.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/heap-sort-03.png) 相信,通过以上两幅图,应该能很直观的演示堆排序的操作处理。 @@ -753,7 +753,7 @@ public void Merge(int[] array2, int low, int mid, int high) { 掌握了合并的方法,接下来,让我们来了解**如何分解**。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/algorithm/sort/merge-sort.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/merge-sort.png) 在某趟归并中,设各子表的长度为 **gap**,则归并前 R[0...n-1] 中共有 **n/gap** 个有序的子表:`R[0...gap-1]`, `R[gap...2*gap-1]`, ... , `R[(n/gap)*gap ... n-1]`。 @@ -847,7 +847,7 @@ public int[] sort(int[] list) { 我们先根据序列的个位数的数字来进行分类,将其分到指定的桶中。例如:R[0] = 50,个位数上是 0,将这个数存入编号为 0 的桶中。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/algorithm/sort/radix-sort.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/radix-sort.png) 分类后,我们在从各个桶中,将这些数按照从编号 0 到编号 9 的顺序依次将所有数取出来。 diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/01.\346\240\221\345\222\214\344\272\214\345\217\211\346\240\221.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/01.\346\240\221\345\222\214\344\272\214\345\217\211\346\240\221.md" index a1e6c90..8660f49 100644 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/01.\346\240\221\345\222\214\344\272\214\345\217\211\346\240\221.md" +++ "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/01.\346\240\221\345\222\214\344\272\214\345\217\211\346\240\221.md" @@ -29,7 +29,7 @@ permalink: /pages/92e4c1/ - 每个非根节点可以分为多个不相交的子树。 - 树里面没有环路。 -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220403163620.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220403163620.png) ### 树的术语 @@ -45,7 +45,7 @@ permalink: /pages/92e4c1/ - **子孙**:以某节点为根的子树中任一节点都称为该节点的子孙。 - **森林**:由 m(m>=0)棵互不相交的树的集合称为森林; -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220403164732.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220403164732.png) - **节点的高度**:节点到叶子节点的最长路径。高度是从下往上度量。 - **节点的深度**:根节点到该节点的最长路径。深度是从上往下度量。 @@ -88,7 +88,7 @@ permalink: /pages/92e4c1/ 除了叶子节点之外,每个节点都有左右两个子节点,这种二叉树就叫作**满二叉树**。 -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220403183927.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220403183927.png) ### 完全二叉树 @@ -96,7 +96,7 @@ permalink: /pages/92e4c1/ 特点:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。 -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220403183640.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220403183640.png) 存储一棵二叉树,有两种方法,一种是基于指针或者引用的二叉链式存储法,一种是基于数组的顺序存储法。 @@ -104,11 +104,11 @@ permalink: /pages/92e4c1/ 每个节点有三个字段,其中一个存储数据,另外两个是指向左右子节点的指针。 -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220403212249.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220403212249.png) **顺序存储法** -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220403214627.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220403214627.png) 如果节点 X 存储在数组中下标为 i 的位置,下标为 2 _ i 的位置存储的就是左子节点,下标为 2 _ i + 1 的位置存储的就是右子节点。反过来,下标为 i/2 的位置存储就是它的父节点。通过这种方式,我们只要知道根节点存储的位置(一般情况下,为了方便计算子节点,根节点会存储在下标为 1 的位置),这样就可以通过下标计算,把整棵树都串起来。 @@ -122,7 +122,7 @@ permalink: /pages/92e4c1/ - **中序遍历**:对于树中的任意节点来说,先打印它的左子树,然后再打印它本身,最后打印它的右子树。 - **后序遍历**是指,对于树中的任意节点来说,先打印它的左子树,然后再打印它的右子树,最后打印这个节点本身。 -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220404201713.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220404201713.png) ## 二叉查找树 @@ -130,19 +130,19 @@ permalink: /pages/92e4c1/ **二叉查找树要求,在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。** -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220405172359.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220405172359.png) ### 二叉查找树的查找 首先,我们看如何在二叉查找树中查找一个节点。我们先取根节点,如果它等于我们要查找的数据,那就返回。如果要查找的数据比根节点的值小,那就在左子树中递归查找;如果要查找的数据比根节点的值大,那就在右子树中递归查找。 -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220405172537.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220405172537.png) ### 二叉查找树的插入 如果要插入的数据比节点的数据大,并且节点的右子树为空,就将新数据直接插到右子节点的位置;如果不为空,就再递归遍历右子树,查找插入位置。同理,如果要插入的数据比节点数值小,并且节点的左子树为空,就将新数据插入到左子节点的位置;如果不为空,就再递归遍历左子树,查找插入位置。 -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220405172549.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220405172549.png) ### 二叉查找树的删除 @@ -150,13 +150,13 @@ permalink: /pages/92e4c1/ 第二种情况是,如果要删除的节点只有一个子节点(只有左子节点或者右子节点),我们只需要更新父节点中,指向要删除节点的指针,让它指向要删除节点的子节点就可以了。 -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220405200219.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220405200219.png) -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220405200234.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220405200234.png) 第三种情况是,如果要删除的节点有两个子节点,这就比较复杂了。我们需要找到这个节点的右子树中的最小节点,把它替换到要删除的节点上。然后再删除掉这个最小节点,因为最小节点肯定没有左子节点(如果有左子结点,那就不是最小节点了),所以,我们可以应用上面两条规则来删除这个最小节点。 -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220405200456.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220405200456.png) ### 二叉查找树的时间复杂度 @@ -164,7 +164,7 @@ permalink: /pages/92e4c1/ 二叉查找树的形态各式各样。比如这个图中,对于同一组数据,我们构造了三种二叉查找树。它们的查找、插入、删除操作的执行效率都是不一样的。图中第一种二叉查找树,根节点的左右子树极度不平衡,已经退化成了链表,所以查找的时间复杂度就变成了 O(n)。 -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220405234630.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220405234630.png) ### 为什么需要二叉查找树 diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/02.\345\240\206.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/02.\345\240\206.md" index 014e0c2..c66e6e1 100644 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/02.\345\240\206.md" +++ "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/02.\345\240\206.md" @@ -32,7 +32,7 @@ permalink: /pages/ce297c/ 完全二叉树比较适合用数组来存储。用数组来存储完全二叉树是非常节省存储空间的。因为我们不需要存储左右子节点的指针,单纯地通过数组的下标,就可以找到一个节点的左右子节点和父节点。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220311112542.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220311112542.jpg) 堆常见的操作: diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/03.B+\346\240\221.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/03.B+\346\240\221.md" index de03308..908780d 100644 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/03.B+\346\240\221.md" +++ "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/03.B+\346\240\221.md" @@ -19,11 +19,11 @@ permalink: /pages/3fd76e/ B+树是在二叉查找树的基础上进行了改造:树中的节点并不存储数据本身,而是只是作为索引。每个叶子节点串在一条链表上,链表中的数据是从小到大有序的。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220311092926.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220311092926.jpg) 改造之后,如果我们要求某个区间的数据。我们只需要拿区间的起始值,在树中进行查找,当查找到某个叶子节点之后,我们再顺着链表往后遍历,直到链表中的结点数据值大于区间的终止值为止。所有遍历到的数据,就是符合区间值的所有数据。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220311092929.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220311092929.jpg) 但是,我们要为几千万、上亿的数据构建索引,如果将索引存储在内存中,尽管内存访问的速度非常快,查询的效率非常高,但是,占用的内存会非常多。 diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/04.LSM\346\240\221.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/04.LSM\346\240\221.md" index bbcdd49..c5d67cd 100644 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/04.LSM\346\240\221.md" +++ "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/04.LSM\346\240\221.md" @@ -31,7 +31,7 @@ LSM 树就是根据这个思路设计了这样一个机制:当数据写入时 可以参考两个有序链表归并排序的过程,将 C0 树和 C1 树的所有叶子节点中存储的数据,看作是两个有序链表,那滚动合并问题就变成了我们熟悉的两个有序链表的归并问题。不过由于涉及磁盘操作,那为了提高写入效率和检索效率,我们还需要针对磁盘的特性,在一些归并细节上进行优化。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220316105440.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220316105440.png) 由于磁盘具有顺序读写效率高的特性,因此,为了提高 C1 树中节点的读写性能,除了根节点以外的节点都要尽可能地存放到连续的块中,让它们能作为一个整体单位来读写。这种包含多个节点的块就叫作多页块(Multi-Pages Block)。 @@ -43,7 +43,7 @@ LSM 树就是根据这个思路设计了这样一个机制:当数据写入时 第四步,重复第三步,直到遍历完 C0 树和 C1 树的所有叶子节点,并将所有的归并结果写入到磁盘。这个时候,我们就可以同时删除 C0 树和 C1 树中被处理过的叶子节点。这样就完成了滚动归并的过程。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220316110736.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220316110736.png) ### LSM 树是如何检索 @@ -72,7 +72,7 @@ WAL 技术保存和恢复数据的具体步骤如下: 3. 系统会周期性地检查内存中的数据是否都被处理完了(比如,被删除或者写入磁盘),并且生成对应的检查点(Check Point)记录在磁盘中。然后,我们就可以随时删除被处理完的数据了。这样一来,log 文件就不会无限增长了。 4. 系统崩溃重启,我们只需要从磁盘中读取检查点,就能知道最后一次成功处理的数据在 log 文件中的位置。接下来,我们就可以把这个位置之后未被处理的数据,从 log 文件中读出,然后重新加载到内存中。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220316104837.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220316104837.png) ## 参考资料 diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/05.\345\255\227\345\205\270\346\240\221.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/05.\345\255\227\345\205\270\346\240\221.md" index 338c57c..d5916a6 100644 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/05.\345\255\227\345\205\270\346\240\221.md" +++ "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/05.\345\255\227\345\205\270\346\240\221.md" @@ -22,13 +22,13 @@ Trie 树(又叫「前缀树」或「字典树」)是一种用于快速查询 - 从根节点到某一节点路径上所经过的字符连接起来,即为该节点对应的字符串; - 任意节点的所有子节点所包含的字符都不相同; -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220313181057.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220313181057.jpg) ### 字典树的构造 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220313181243.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220313181243.jpg) -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220313181425.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220313181425.jpg) 构建 Trie 树的过程,需要扫描所有的字符串,时间复杂度是 O(n)(n 表示所有字符串的长度和)。 @@ -48,7 +48,7 @@ Trie 树(又叫「前缀树」或「字典树」)是一种用于快速查询 4. 以此类推,进行迭代过程; 5. 在某个节点处,关键词的所有字母已被取出,则读取附在该节点上的信息,查找完成。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220313181305.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220313181305.jpg) 每次查询时,如果要查询的字符串长度是 k,那我们只需要比对大约 k 个节点,就能完成查询操作。跟原本那组字符串的长度和个数没有任何关系。所以说,构建好 Trie 树后,在其中查找字符串的时间复杂度是 O(k),k 表示要查找的字符串的长度。 @@ -70,25 +70,25 @@ Trie 树(又叫「前缀树」或「字典树」)是一种用于快速查询 (1)自动补全 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200305095300.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200305095300.png) (2)拼写检查 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200305101637.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200305101637.png) (3)IP 路由 (最长前缀匹配) -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200305102959.gif) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200305102959.gif) 图 3. 使用 Trie 树的最长前缀匹配算法,Internet 协议(IP)路由中利用转发表选择路径。 (4)T9 (九宫格) 打字预测 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200305103047.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200305103047.jpg) (5)单词游戏 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200305103052.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200305103052.png) Trie 树可通过剪枝搜索空间来高效解决 Boggle 单词游戏 diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/06.\347\272\242\351\273\221\346\240\221.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/06.\347\272\242\351\273\221\346\240\221.md" index f9274d5..dde06c0 100644 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/06.\347\272\242\351\273\221\346\240\221.md" +++ "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/06.\347\272\242\351\273\221\346\240\221.md" @@ -21,7 +21,7 @@ permalink: /pages/0a4414/ 完全二叉树、满二叉树其实都是平衡二叉树,但是非完全二叉树也有可能是平衡二叉树。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220310202113.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310202113.jpg) **平衡二叉查找树中“平衡”的意思,其实就是让整棵树左右看起来比较“对称”、比较“平衡”,不要出现左子树很高、右子树很矮的情况。这样就能让整棵树的高度相对来说低一些,相应的插入、删除、查找等操作的效率高一些**。 @@ -36,7 +36,7 @@ permalink: /pages/0a4414/ - 任何相邻的节点都不能同时为红色,也就是说,红色节点是被黑色节点隔开的; - 每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点; -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220310202612.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310202612.jpg) ### 为什么说红黑树是“近似平衡”的? @@ -48,7 +48,7 @@ permalink: /pages/0a4414/ 红色节点删除之后,有些节点就没有父节点了,它们会直接拿这些节点的祖父节点(父节点的父节点)作为父节点。所以,之前的二叉树就变成了四叉树。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220310202902.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310202902.jpg) 前面红黑树的定义里有这么一条:从任意节点到可达的叶子节点的每个路径包含相同数目的黑色节点。我们从四叉树中取出某些节点,放到叶节点位置,四叉树就变成了完全二叉树。所以,仅包含黑色节点的四叉树的高度,比包含相同节点个数的完全二叉树的高度还要小。 @@ -88,7 +88,7 @@ AVL 树是一种高度平衡的二叉树,所以查找的效率非常高,但 - 关注节点变成 a 的祖父节点 c; - 跳到 CASE 2 或者 CASE 3。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220310203600.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310203600.jpg) **CASE 2:如果关注节点是 a,它的叔叔节点 d 是黑色,关注节点 a 是其父节点 b 的右子节点**,我们就依次执行下面的操作: @@ -96,7 +96,7 @@ AVL 树是一种高度平衡的二叉树,所以查找的效率非常高,但 - 围绕新的关注节点 b 左旋; - 跳到 CASE 3。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220310203623.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310203623.jpg) **CASE 3:如果关注节点是 a,它的叔叔节点 d 是黑色,关注节点 a 是其父节点 b 的左子节点**,我们就依次执行下面的操作: @@ -104,7 +104,7 @@ AVL 树是一种高度平衡的二叉树,所以查找的效率非常高,但 - 将关注节点 a 的父节点 b、兄弟节点 c 的颜色互换。 - 调整结束。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220310203645.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310203645.jpg) ### 删除操作的平衡调整 @@ -116,7 +116,7 @@ AVL 树是一种高度平衡的二叉树,所以查找的效率非常高,但 - 节点 a 只能是黑色,节点 b 也只能是红色,其他情况均不符合红黑树的定义。这种情况下,我们把节点 b 改为黑色; - 调整结束,不需要进行二次调整。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220310204215.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310204215.jpg) **CASE 2:如果要删除的节点 a 有两个非空子节点,并且它的后继节点就是节点 a 的右子节点 c**。我们就依次进行下面的操作: diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/03.\345\223\210\345\270\214\350\241\250.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/03.\345\223\210\345\270\214\350\241\250.md" index c741083..a5b9ff1 100644 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/03.\345\223\210\345\270\214\350\241\250.md" +++ "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/03.\345\223\210\345\270\214\350\241\250.md" @@ -32,7 +32,7 @@ permalink: /pages/b501c7/ **哈希表用的是数组支持按照下标随机访问数据的特性,所以哈希表其实就是数组的一种扩展,由数组演化而来。可以说,如果没有数组,就没有哈希表**。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220320201844.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320201844.png) 哈希表通过散列函数把元素的键值映射为下标,然后将数据存储在数组中对应下标的位置。按照键值查询元素时,用同样的散列函数,将键值转化数组下标,从对应的数组下标的位置取数据。 @@ -92,7 +92,7 @@ permalink: /pages/b501c7/ **线性探测**(Linear Probing):当我们往哈希表中插入数据时,如果某个数据经过散列函数散列之后,存储位置已经被占用了,我们就从当前位置开始,依次往后查找,看是否有空闲位置,直到找到为止。 -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220323200359.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323200359.png) 对于使用线性探测法解决冲突的哈希表,删除操作稍微有些特别。我们不能单纯地把要删除的元素设置为空。这是为什么呢?在查找的时候,一旦我们通过线性探测方法,找到一个空闲位置,我们就可以认定哈希表中不存在这个数据。但是,如果这个空闲位置是我们后来删除的,就会导致原来的查找算法失效。本来存在的数据,会被认定为不存在。这个问题如何解决呢? @@ -108,7 +108,7 @@ permalink: /pages/b501c7/ **基于链表的散列冲突处理方法比较适合存储大对象、大数据量的哈希表,而且,比起开放寻址法,它更加灵活,支持更多的优化策略,比如用红黑树代替链表**。 -![](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220323200419.png) +![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323200419.png) 当插入的时候,我们只需要通过散列函数计算出对应的散列槽位,将其插入到对应链表中即可,所以插入的时间复杂度是 O(1)。当查找、删除一个元素时,我们同样通过散列函数计算出对应的槽,然后遍历链表查找或者删除。那查找或删除操作的时间复杂度是多少呢? diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/04.\350\267\263\350\241\250.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/04.\350\267\263\350\241\250.md" index a5355f2..f6af72a 100644 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/04.\350\267\263\350\241\250.md" +++ "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/04.\350\267\263\350\241\250.md" @@ -18,21 +18,21 @@ permalink: /pages/62671a/ 但是,即使是有序的链表,也只能使用低效的顺序查找,其时间复杂度为 `O(n)`。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220323113532.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323113532.png) 如何提高链表的查找效率呢? 我们可以对链表加一层索引。具体来说,可以每两个结点提取一个结点到上一级,我们把抽出来的那一级叫作**索引**或**索引层**。索引节点中通过一个 down 指针,指向下一级结点。通过这样的改造,就可以支持类似二分查找的算法。我们把改造之后的数据结构叫作**跳表**(Skip list)。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220323155309.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323155309.png) 随着数据的不断增长,一级索引层也变得越来越长。此时,我们可以为一级索引再增加一层索引层:二级索引层。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220323155346.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323155346.png) 随着数据的膨胀,当二级索引层也变得很长时,我们可以继续为其添加新的索引层。**这种链表加多级索引的结构,就是跳表**。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220323114408.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323114408.png) ### 跳表的时间复杂度 @@ -62,7 +62,7 @@ permalink: /pages/62671a/ 跳表不仅支持查找操作,还支持动态的插入、删除操作,而且插入、删除操作的时间复杂度也是 `O(logn)`。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220323155933.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323155933.png) - **插入操作**:对于纯粹的单链表,需要遍历每个结点,来找到插入的位置。但是,对于跳表来说,我们讲过查找某个结点的的时间复杂度是 `O(log n)`,所以这里查找某个数据应该插入的位置,方法也是类似的,时间复杂度也是 `O(log n)`。 - **删除操作**:如果这个结点在索引中也有出现,我们除了要删除原始链表中的结点,还要删除索引中的。因为单链表中的删除操作需要拿到要删除结点的前驱结点,然后通过指针操作完成删除。所以在查找要删除的结点的时候,一定要获取前驱结点。当然,如果我们用的是双向链表,就不需要考虑这个问题了。 @@ -71,7 +71,7 @@ permalink: /pages/62671a/ 当我们不停地往跳表中插入数据时,如果我们不更新索引,就有可能出现某 2 个索引结点之间数据非常多的情况。极端情况下,跳表还会退化成单链表。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220323161942.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323161942.png) 如红黑树、AVL 树这样的平衡二叉树,是通过左右旋的方式保持左右子树的大小平衡,而跳表是通过随机函数来维护前面提到的“平衡性”。 diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/05.\345\233\276.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/05.\345\233\276.md" index 765eff2..44dc4d3 100644 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/05.\345\233\276.md" +++ "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/05.\345\233\276.md" @@ -14,7 +14,7 @@ permalink: /pages/21529b/ 在计算机科学中,一个图就是一些*顶点*的集合,这些顶点通过一系列*边*结对(连接)。顶点用圆圈表示,边就是这些圆圈之间的连线。顶点之间通过边连接。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/data-structure/graph/graph.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/data-structure/graph/graph.png) ## 什么是图 @@ -34,7 +34,7 @@ permalink: /pages/21529b/ 如果图的边没有方向性,则被成为无向图。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20220314093554.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220314093554.jpg) ## 图的基本操作 diff --git a/docs/README.md b/docs/README.md index 1008641..2e6316d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -39,7 +39,7 @@ footer: CC-BY-SA-4.0 Licensed | Copyright © 2018-Now Dunwu ## 📖 内容 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200702071922.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200702071922.png) - 综合 - [数据结构和算法指南](01.数据结构和算法/00.综合/01.数据结构和算法指南.md) From 1964a4d1110653c366e8ef32a1c76b7df8545865 Mon Sep 17 00:00:00 2001 From: dunwu Date: Mon, 13 Jan 2025 07:38:00 +0800 Subject: [PATCH 02/21] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\346\225\260\344\271\213\345\222\214.java" | 96 +--- ...46\225\260\344\271\213\345\222\214II.java" | 79 ++++ ...\351\207\215\345\244\215\351\241\271.java" | 37 +- ...\345\255\227\347\254\246\344\270\262.java" | 34 ++ ...\347\272\277\351\201\215\345\216\206.java" | 59 ++- ...\345\277\203\347\264\242\345\274\225.java" | 18 + ...\345\205\245\344\275\215\347\275\256.java" | 9 +- ...\351\231\244\345\205\203\347\264\240.java" | 22 +- .../algorithm/list/DoublyLinkedList.java | 230 +++++++++ .../github/dunwu/algorithm/list/ListNode.java | 31 ++ .../github/dunwu/algorithm/list/ListUtil.java | 4 +- .../dunwu/algorithm/list/MyLinkedList.java | 244 ++++++++++ .../algorithm/list/SinglyLinkedList.java | 446 ++++++++---------- ...\351\232\224\351\223\276\350\241\250.java" | 21 +- ...\344\270\252\347\273\223\347\202\271.java" | 48 ++ ...\350\241\250\347\244\272\344\276\213.java" | 12 +- ...\345\272\217\351\223\276\350\241\250.java" | 27 ++ ...350\241\250\350\247\243\346\263\2252.java" | 11 +- ...\345\275\242\351\223\276\350\241\250.java" | 31 +- ...45\275\242\351\223\276\350\241\250II.java" | 38 +- ...\344\272\244\351\223\276\350\241\250.java" | 37 +- ...\344\270\252\350\212\202\347\202\271.java" | 45 +- ...\347\233\226\345\255\220\344\270\262.java" | 19 + ...\346\226\207\345\255\220\344\270\262.java" | 45 ++ .../algorithm/list/DoubleLinkListTests.java | 83 ++++ .../algorithm/list/SingleLinkListTests.java | 52 +- 26 files changed, 1307 insertions(+), 471 deletions(-) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/DoublyLinkedList.java create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/MyLinkedList.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" create mode 100644 codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214.java" index 9f8ad23..efad0ce 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214.java" @@ -6,105 +6,51 @@ import java.util.Map; /** + * 题目:1. 两数之和 + * * @author Zhang Peng * @since 2020-06-05 */ public class 两数之和 { public static void main(String[] args) { - Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSumInSorted(new int[] { 2, 7, 11, 15 }, 9)); - Assertions.assertArrayEquals(new int[] { 1, 3 }, twoSumInSorted(new int[] { 2, 3, 4 }, 6)); - Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSumInSorted(new int[] { 0, 0, 3, 4 }, 0)); + Assertions.assertArrayEquals(new int[] { 0, 1 }, twoSumInSorted(new int[] { 2, 7, 11, 15 }, 9)); + Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSumInSorted(new int[] { 3, 2, 4 }, 6)); + Assertions.assertArrayEquals(new int[] { 0, 1 }, twoSumInSorted(new int[] { 3, 3 }, 6)); - Assertions.assertArrayEquals(new int[] { 0, 1 }, - twoSum_method1(new int[] { 2, 7, 11, 15 }, 9)); - Assertions.assertArrayEquals(new int[] { 1, 2 }, - twoSum_method1(new int[] { 3, 2, 4 }, 6)); - Assertions.assertArrayEquals(new int[] { -1, -1 }, - twoSum_method1(new int[] { 3, 2, 4 }, 9)); - - Assertions.assertArrayEquals(new int[] { 0, 1 }, - twoSum_method2(new int[] { 2, 7, 11, 15 }, 9)); - Assertions.assertArrayEquals(new int[] { 1, 2 }, - twoSum_method2(new int[] { 3, 2, 4 }, 6)); - Assertions.assertArrayEquals(new int[] { -1, -1 }, - twoSum_method2(new int[] { 3, 2, 4 }, 9)); + Assertions.assertArrayEquals(new int[] { 0, 1 }, twoSumInSorted2(new int[] { 2, 7, 11, 15 }, 9)); + Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSumInSorted2(new int[] { 3, 2, 4 }, 6)); + Assertions.assertArrayEquals(new int[] { 0, 1 }, twoSumInSorted2(new int[] { 3, 3 }, 6)); } /** - * 题目:1. 两数之和 - *

- * 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 - *

- * 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 + * 时间复杂度:O(n^2) */ public static int[] twoSumInSorted(int[] nums, int target) { - final int[] notFound = new int[] { -1, -1 }; - if (nums == null || nums.length < 2) { - return notFound; - } - - int left = 0, right = nums.length - 1; - while (left <= right) { - int v = nums[left] + nums[right]; - if (v == target) { - return new int[] { left + 1, right + 1 }; - } else if (v > target) { - right--; - } else { - left++; - } - } - return notFound; - } - - /** - * 题目:1. 两数之和 - *

- * 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 - *

- * 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 - */ - public static int[] twoSum_method1(int[] nums, int target) { - final int[] notFound = new int[] { -1, -1 }; - if (nums == null || nums.length < 2) { - return notFound; - } - - for (int i = 0; i < nums.length; i++) { - for (int j = i + 1; j < nums.length; j++) { - if (nums[i] + nums[j] == target) { - return new int[] { i, j }; + for (int left = 0; left < nums.length; left++) { + for (int right = left + 1; right < nums.length; right++) { + if (nums[left] + nums[right] == target) { + return new int[] { left, right }; } } } - return notFound; + return new int[] { -1, -1 }; } /** - * 题目:1. 两数之和 - *

- * 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 - *

- * 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 + * 时间复杂度:O(n) */ - public static int[] twoSum_method2(int[] nums, int target) { - final int[] notFound = new int[] { -1, -1 }; - if (nums == null || nums.length < 2) { - return notFound; - } - - Map map = new HashMap<>(); + public static int[] twoSumInSorted2(int[] nums, int target) { + Map map = new HashMap<>(nums.length); for (int i = 0; i < nums.length; i++) { - int temp = target - nums[i]; - if (map.containsKey(temp)) { - return new int[] { map.get(temp), i }; + int expectNum = target - nums[i]; + if (map.containsKey(expectNum)) { + return new int[] { map.get(expectNum), i }; } else { map.put(nums[i], i); } } - - return notFound; + return new int[] { -1, -1 }; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II.java" new file mode 100644 index 0000000..5c09531 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II.java" @@ -0,0 +1,79 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; +import java.util.Map; + +/** + * 题目:167. 两数之和 II - 输入有序数组 + * + * @author Zhang Peng + * @since 2020-06-05 + */ +public class 两数之和II { + + public static void main(String[] args) { + Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSum(new int[] { 2, 7, 11, 15 }, 9)); + Assertions.assertArrayEquals(new int[] { 1, 3 }, twoSum(new int[] { 2, 3, 4 }, 6)); + Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSum(new int[] { -1, 0 }, -1)); + + Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSum2(new int[] { 2, 7, 11, 15 }, 9)); + Assertions.assertArrayEquals(new int[] { 1, 3 }, twoSum2(new int[] { 2, 3, 4 }, 6)); + Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSum2(new int[] { -1, 0 }, -1)); + + Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSum3(new int[] { 2, 7, 11, 15 }, 9)); + Assertions.assertArrayEquals(new int[] { 1, 3 }, twoSum3(new int[] { 2, 3, 4 }, 6)); + Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSum3(new int[] { -1, 0 }, -1)); + } + + /** + * 时间复杂度:O(n^2) + */ + public static int[] twoSum(int[] numbers, int target) { + for (int i = 0; i < numbers.length; i++) { + for (int j = i + 1; j < numbers.length; j++) { + if (numbers[i] + numbers[j] == target) { + return new int[] { i + 1, j + 1 }; + } + } + } + return new int[] { -1, -1 }; + } + + /** + * 时间复杂度:O(n) + */ + public static int[] twoSum2(int[] numbers, int target) { + int len = numbers.length; + Map map = new HashMap<>(len); + for (int i = 0; i < len; i++) { + int num = numbers[i]; + int diff = target - num; + if (map.containsKey(diff)) { + return new int[] { map.get(diff) + 1, i + 1 }; + } + map.put(num, i); + } + return new int[] { -1, -1 }; + } + + /** + * 时间复杂度:O(logn) + */ + public static int[] twoSum3(int[] numbers, int target) { + int left = 0, right = numbers.length - 1; + while (left < right) { + int sum = numbers[left] + numbers[right]; + if (sum == target) { + return new int[] { left + 1, right + 1 }; + } else if (sum < target) { + left++; + } else { + right--; + } + } + return new int[] { -1, -1 }; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" index f8f7cd2..06ad78f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" @@ -48,40 +48,31 @@ public class 删除排序数组中的重复项 { public static void main(String[] args) { int[] nums1 = { 1, 1, 2 }; - Assertions.assertEquals(2, 删除排序数组中的重复项.removeDuplicates(nums1)); + Assertions.assertEquals(2, removeDuplicates(nums1)); int[] nums2 = { 0, 0, 1, 1, 1, 2, 2, 3, 3, 4 }; - Assertions.assertEquals(5, 删除排序数组中的重复项.removeDuplicates(nums2)); + Assertions.assertEquals(5, removeDuplicates(nums2)); int[] nums3 = { 1, 2 }; - Assertions.assertEquals(2, 删除排序数组中的重复项.removeDuplicates(nums3)); + Assertions.assertEquals(2, removeDuplicates(nums3)); int[] nums4 = { 2, 2 }; - Assertions.assertEquals(1, 删除排序数组中的重复项.removeDuplicates(nums4)); + Assertions.assertEquals(1, removeDuplicates(nums4)); } public static int removeDuplicates(int[] nums) { - int left = 0; - int right = nums.length - 1; - - while (left <= right) { - for (int i = left + 1; i <= right; i++) { - if (nums[i] == nums[left]) { - remove(nums, i); - right--; - i--; - } - } - left++; + if (nums.length == 0) { + return 0; } - - return right + 1; - } - - private static void remove(int[] nums, int pos) { - for (int i = pos; i < nums.length - 1; i++) { - nums[i] = nums[i + 1]; + int slow = 0, fast = 0; + while (fast < nums.length) { + if (nums[slow] != nums[fast]) { + slow++; + nums[slow] = nums[fast]; + } + fast++; } + return slow + 1; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" new file mode 100644 index 0000000..7004912 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" @@ -0,0 +1,34 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * 题目:344. 反转字符串 + * + * @author Zhang Peng + * @since 2020-06-05 + */ +public class 反转字符串 { + + public static void main(String[] args) { + char[] s1 = new char[] { 'h', 'e', 'l', 'l', 'o' }; + reverseString(s1); + Assertions.assertArrayEquals(new char[] { 'o', 'l', 'l', 'e', 'h' }, s1); + + char[] s2 = new char[] { 'H', 'a', 'n', 'n', 'a', 'h' }; + reverseString(s2); + Assertions.assertArrayEquals(new char[] { 'h', 'a', 'n', 'n', 'a', 'H' }, s2); + } + + public static void reverseString(char[] s) { + int left = 0, right = s.length - 1; + while (left < right) { + char temp = s[left]; + s[left] = s[right]; + s[right] = temp; + left++; + right--; + } + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" index 3921f19..eb648a8 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" @@ -28,9 +28,19 @@ public class 对角线遍历 { public static void main(String[] args) { - int[][] matrix = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; - int[] expected = { 1, 2, 4, 7, 5, 3, 6, 8, 9 }; + + int[][] matrix = { { 1, 2 }, { 3, 4 } }; + int[] expected = { 1, 2, 3, 4 }; + + int[][] matrix2 = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + int[] expected2 = { 1, 2, 4, 7, 5, 3, 6, 8, 9 }; + + int[][] matrix3 = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }, { 13, 14, 15, 16 } }; + int[] expected3 = { 1, 2, 5, 9, 6, 3, 4, 7, 10, 13, 14, 11, 8, 12, 15, 16 }; + Assertions.assertArrayEquals(expected, 对角线遍历.findDiagonalOrder(matrix)); + Assertions.assertArrayEquals(expected2, 对角线遍历.findDiagonalOrder(matrix2)); + Assertions.assertArrayEquals(expected3, 对角线遍历.findDiagonalOrder(matrix3)); } public static int[] findDiagonalOrder(int[][] matrix) { @@ -67,4 +77,49 @@ public static int[] findDiagonalOrder(int[][] matrix) { return arr; } + public static int[] findDiagonalOrder2(int[][] matrix) { + final int UP = 1; + final int DOWN = 2; + final int M = matrix.length; + final int N = matrix[0].length; + int i = 0, j = 0, status = UP; + + int[] result = new int[M * N]; + // System.out.println("========================================"); + // System.out.println(JSONUtil.toJsonStr(matrix)); + // System.out.println("========================================"); + int index = 0; + while (i < M && j < N) { + result[index] = matrix[i][j]; + System.out.println(result[index]); + index++; + if (status == UP) { + if (i == 0 || j == N - 1) { + status = DOWN; + if (j == N - 1) { + i++; + } else { + j++; + } + } else { + i--; + j++; + } + } else { + if (j == 0 || i == M - 1) { + status = UP; + if (i == M - 1) { + j++; + } else { + i++; + } + } else { + i++; + j--; + } + } + } + return result; + } + } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" index e9f379c..a6d10be 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" @@ -44,6 +44,8 @@ import org.junit.jupiter.api.Assertions; +import java.util.Arrays; + /** * 724. 寻找数组的中心索引 * @@ -56,9 +58,25 @@ public static void main(String[] args) { Assertions.assertEquals(3, pivotIndex(new int[] { 1, 7, 3, 6, 5, 6 })); Assertions.assertEquals(-1, pivotIndex(new int[] { 1, 2, 3 })); Assertions.assertEquals(0, pivotIndex(new int[] { 2, 1, -1 })); + + Assertions.assertEquals(3, pivotIndex2(new int[] { 1, 7, 3, 6, 5, 6 })); + Assertions.assertEquals(-1, pivotIndex2(new int[] { 1, 2, 3 })); + Assertions.assertEquals(0, pivotIndex2(new int[] { 2, 1, -1 })); } public static int pivotIndex(int[] nums) { + int sum = 0; + int total = Arrays.stream(nums).sum(); + for (int pos = 0; pos < nums.length; pos++) { + if (sum * 2 + nums[pos] == total) { + return pos; + } + sum += nums[pos]; + } + return -1; + } + + public static int pivotIndex2(int[] nums) { for (int pos = 0; pos < nums.length; pos++) { // pos 左侧所有元素累加 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" index ea60c23..8a0a55e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" @@ -58,12 +58,9 @@ public static void main(String[] args) { } public static int searchInsert(int[] nums, int target) { - if (nums == null || nums.length == 0) return 0; - if (nums[0] >= target) return 0; - if (nums[nums.length - 1] < target) return nums.length; - for (int i = 1; i < nums.length; i++) { - if (nums[i] >= target) { - return i; + for (int pos = 0; pos < nums.length; pos++) { + if (nums[pos] >= target) { + return pos; } } return nums.length; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\351\231\244\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\351\231\244\345\205\203\347\264\240.java" index f9fd8ab..907341f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\351\231\244\345\205\203\347\264\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\351\231\244\345\205\203\347\264\240.java" @@ -52,19 +52,25 @@ public class 移除元素 { public static void main(String[] args) { int[] nums1 = { 3, 2, 2, 3 }; - Assertions.assertEquals(2, 移除元素.removeElement(nums1, 3)); + Assertions.assertEquals(2, removeElement(nums1, 3)); + + int[] nums2 = { 0, 1, 2, 2, 3, 0, 4, 2 }; + Assertions.assertEquals(5, removeElement(nums2, 2)); } public static int removeElement(int[] nums, int val) { - int end = 0; - final int n = nums.length; - for (int i = 0; i < n; i++) { - if (nums[i] != val) { - nums[end] = nums[i]; - end++; + if (nums.length == 0) { + return 0; + } + int slow = 0, fast = 0; + while (fast < nums.length) { + if (nums[fast] != val) { + nums[slow] = nums[fast]; + slow++; } + fast++; } - return end; + return slow; } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/DoublyLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/DoublyLinkedList.java new file mode 100644 index 0000000..a5e05f8 --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/DoublyLinkedList.java @@ -0,0 +1,230 @@ +package io.github.dunwu.algorithm.list; + +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +public class DoublyLinkedList { + + private int size = 0; + private Node first = null; + private Node last = null; + + public DoublyLinkedList() { + first = new Node<>(null); + last = new Node<>(null); + first.next = last; + last.prev = first; + } + + public int size() { + return size; + } + + public boolean isEmpty() { + return size == 0; + } + + public int indexOf(E element) { + int pos = 0; + + Node p = first.next; + while (p != null) { + if (p.element.equals(element)) { + return pos; + } + p = p.next; + pos++; + } + return -1; + } + + public E get(int index) { + Node node = node(index); + return node == null ? null : node.element; + } + + Node node(int index) { + int i = 0; + + Node p = first; + while (p != null && i != index) { + p = p.next; + i++; + } + return p; + } + + public void addFirst(E element) { + + Node node = new Node<>(element); + Node temp = first.next; + + node.next = temp; + temp.prev = node; + + node.prev = first; + first.next = node; + + size++; + } + + public void addLast(E element) { + + Node node = new Node<>(element); + Node temp = last.prev; + + temp.next = node; + node.prev = temp; + + last.prev = node; + node.next = last; + + size++; + } + + public boolean add(int index, E element) { + + if (index == 0) { + addFirst(element); + return true; + } + + Node p = node(index); + Node node = new Node<>(element); + node.next = p.next; + p.next.prev = node; + + node.prev = p; + p.next = node; + + size++; + return true; + } + + public boolean remove(E e) { + if (e == null) { + Node p = first; + while (p.next != null) { + Node x = p.next; + if (x.element == null) { + p.next = x.next; + size--; + return true; + } + p = p.next; + } + } else { + Node p = first; + while (p != null && p.next != null) { + Node x = p.next; + if (e.equals(x.element)) { + p.next = x.next; + size--; + return true; + } + p = p.next; + } + } + return false; + } + + public boolean removeAll(E e) { + + if (first.next == null) { + return false; + } + + if (e == null) { + Node p = first; + while (p.next != null) { + Node x = p.next; + if (x.element == null) { + p.next = x.next; + size--; + } + p = p.next; + } + } else { + Node p = first; + while (p != null && p.next != null) { + if (e.equals(p.next.element)) { + p.next = p.next.next; + size--; + } else { + p = p.next; + } + } + } + return true; + } + + public void clear() { + first.next = last; + last.prev = first; + size = 0; + } + + public void printAll() { + Node p = first; + while (p.next != null && p.next != last) { + p = p.next; + System.out.print(p.element + " "); + } + System.out.println(); + } + + public List toList() { + List list = new ArrayList<>(); + Node node = first.next; + while (node != null && node != last) { + list.add(node.element); + node = node.next; + } + return list; + } + + @Getter + @Setter + public static class Node { + + private E element; + private Node next; + private Node prev; + + public Node(E element) { + this.element = element; + this.next = null; + this.prev = null; + } + + public Node(E element, Node prev, Node next) { + this.element = element; + this.prev = prev; + this.next = next; + } + + } + + public static void main(String[] args) { + int[] nums = { 1, 2, 3, 4, 5 }; + DoublyLinkedList list = new DoublyLinkedList<>(); + DoublyLinkedList reverseList = new DoublyLinkedList<>(); + for (int num : nums) { + list.addLast(num); + reverseList.addFirst(num); + } + + list.add(5, 999); + System.out.println("【队尾写入链表】"); + list.printAll(); + System.out.println("【队头写入链表】"); + reverseList.printAll(); + list.printAll(); + System.out.println("999 在队列中的位置:" + list.indexOf(999)); + System.out.println("队列中位置 5 的元素值:" + list.get(5)); + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListNode.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListNode.java index 2096ad3..fc8db7f 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListNode.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListNode.java @@ -23,4 +23,35 @@ public int hashCode() { return Objects.hash(val, next); } + public static ListNode createLinkedList(int[] arr) { + if (arr == null || arr.length == 0) { + return null; + } + ListNode head = new ListNode(arr[0]); + ListNode cur = head; + for (int i = 1; i < arr.length; i++) { + cur.next = new ListNode(arr[i]); + cur = cur.next; + } + return head; + } + + public static void addLast() { + + } + + public static void main(String[] args) { + int[] arr = { 1, 2, 3, 4, 5 }; + ListNode head = createLinkedList(arr); + ListNode p = head; + while (p.next != null) { + p = p.next; + } + p.next = new ListNode(6); + while (head != null) { + System.out.println(head.val); + head = head.next; + } + } + } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListUtil.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListUtil.java index 8694c09..6176f9f 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListUtil.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListUtil.java @@ -9,7 +9,7 @@ */ public class ListUtil { - private ListUtil() {} + private ListUtil() { } public static ListNode buildList(int... list) { ListNode head = new ListNode(-1); @@ -46,7 +46,7 @@ public static ListNode buildCycleList(int pos, int[] list) { ListNode cycleBeginNode = null; for (int val : list) { ListNode item = new ListNode(val); - if (pos == 0) { + if (pos == 0 && cycleBeginNode == null) { cycleBeginNode = item; } else { pos--; diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/MyLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/MyLinkedList.java new file mode 100644 index 0000000..6601d2e --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/MyLinkedList.java @@ -0,0 +1,244 @@ +package io.github.dunwu.algorithm.list; + +import java.util.NoSuchElementException; + +public class MyLinkedList { + + // 虚拟头尾节点 + private int size; + final private Node head, tail; + + // 双链表节点 + private static class Node { + + E data; + Node next; + Node prev; + + Node(E data) { + this.data = data; + } + + } + + // 构造函数初始化虚拟头尾节点 + public MyLinkedList() { + this.head = new Node<>(null); + this.tail = new Node<>(null); + head.next = tail; + tail.prev = head; + this.size = 0; + } + + // ***** 增 ***** + + public void addLast(T data) { + Node node = new Node<>(data); + Node temp = tail.prev; + // temp <-> x + temp.next = node; + node.prev = temp; + + node.next = tail; + tail.prev = node; + // temp <-> x <-> tail + size++; + } + + public void addFirst(T e) { + Node x = new Node<>(e); + Node temp = head.next; + // head <-> temp + temp.prev = x; + x.next = temp; + + head.next = x; + x.prev = head; + // head <-> x <-> temp + size++; + } + + public void add(int index, T element) { + checkPositionIndex(index); + if (index == size) { + addLast(element); + return; + } + + // 找到 index 对应的 Node + Node p = getNode(index); + Node temp = p.prev; + // temp <-> p + + // 新要插入的 Node + Node x = new Node<>(element); + + p.prev = x; + temp.next = x; + + x.prev = temp; + x.next = p; + + // temp <-> x <-> p + + size++; + } + + // ***** 删 ***** + + public T removeFirst() { + if (size < 1) { + throw new NoSuchElementException(); + } + // 虚拟节点的存在是我们不用考虑空指针的问题 + Node x = head.next; + Node temp = x.next; + // head <-> x <-> temp + head.next = temp; + temp.prev = head; + + x.prev = null; + x.next = null; + // head <-> temp + + size--; + return x.data; + } + + public T removeLast() { + if (size < 1) { + throw new NoSuchElementException(); + } + Node x = tail.prev; + Node temp = tail.prev.prev; + // temp <-> x <-> tail + + tail.prev = temp; + temp.next = tail; + + x.prev = null; + x.next = null; + // temp <-> tail + + size--; + return x.data; + } + + public T remove(int index) { + checkElementIndex(index); + // 找到 index 对应的 Node + Node x = getNode(index); + Node prev = x.prev; + Node next = x.next; + // prev <-> x <-> next + prev.next = next; + next.prev = prev; + + x.prev = x.next = null; + // prev <-> next + + size--; + + return x.data; + } + + // ***** 查 ***** + + public T get(int index) { + checkElementIndex(index); + // 找到 index 对应的 Node + Node p = getNode(index); + + return p.data; + } + + public T getFirst() { + if (size < 1) { + throw new NoSuchElementException(); + } + + return head.next.data; + } + + public T getLast() { + if (size < 1) { + throw new NoSuchElementException(); + } + + return tail.prev.data; + } + + // ***** 改 ***** + + public T set(int index, T val) { + checkElementIndex(index); + // 找到 index 对应的 Node + Node p = getNode(index); + + T oldVal = p.data; + p.data = val; + + return oldVal; + } + + // ***** 其他工具函数 ***** + + public int size() { + return size; + } + + public boolean isEmpty() { + return size == 0; + } + + private Node getNode(int index) { + checkElementIndex(index); + Node p = head.next; + // TODO: 可以优化,通过 index 判断从 head 还是 tail 开始遍历 + for (int i = 0; i < index; i++) { + p = p.next; + } + return p; + } + + private boolean isElementIndex(int index) { + return index >= 0 && index < size; + } + + private boolean isPositionIndex(int index) { + return index >= 0 && index <= size; + } + + // 检查 index 索引位置是否可以存在元素 + private void checkElementIndex(int index) { + if (!isElementIndex(index)) { throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); } + } + + // 检查 index 索引位置是否可以添加元素 + private void checkPositionIndex(int index) { + if (!isPositionIndex(index)) { throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); } + } + + private void display() { + System.out.println("size = " + size); + for (Node p = head.next; p != tail; p = p.next) { + System.out.print(p.data + " <-> "); + } + System.out.println("null"); + System.out.println(); + } + + public static void main(String[] args) { + MyLinkedList list = new MyLinkedList<>(); + list.addLast(1); + list.addLast(2); + list.addLast(3); + list.addFirst(0); + list.add(2, 100); + + list.display(); + // size = 5 + // 0 <-> 1 <-> 100 <-> 2 -> 3 -> null + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/SinglyLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/SinglyLinkedList.java index 081fdfd..e661110 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/SinglyLinkedList.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/SinglyLinkedList.java @@ -1,334 +1,264 @@ package io.github.dunwu.algorithm.list; -/** - * 1)单链表的插入、删除、查找操作; 2)链表中存储的是int类型的数据; - *

- * Author:Zheng - */ -public class SinglyLinkedList { - - private Node head = null; - - public Node findByValue(int value) { - Node p = head; - while (p != null && p.data != value) { - p = p.next; - } +import lombok.Getter; +import lombok.Setter; - return p; - } +import java.util.ArrayList; +import java.util.List; - public Node findByIndex(int index) { - Node p = head; - int pos = 0; - while (p != null && pos != index) { - p = p.next; - ++pos; - } +public class SinglyLinkedList { - return p; - } + private int size = 0; + private Node first = null; - //无头结点 - //表头部插入 - //这种操作将于输入的顺序相反,逆序 - public void insertToHead(int value) { - Node newNode = new Node(value, null); - insertToHead(newNode); + public SinglyLinkedList() { + this.size = 0; + this.first = new Node<>(null); } - public void insertToHead(Node newNode) { - if (head == null) { - head = newNode; - } else { - newNode.next = head; - head = newNode; + public SinglyLinkedList(E[] elementArray) { + this.size = 0; + this.first = new Node<>(null); + for (E element : elementArray) { + addLast(element); } } - //顺序插入 - //链表尾部插入 - public void insertTail(int value) { - - Node newNode = new Node(value, null); - //空链表,可以插入新节点作为head,也可以不操作 - if (head == null) { - head = newNode; - } else { - Node q = head; - while (q.next != null) { - q = q.next; - } - newNode.next = q.next; - q.next = newNode; - } + public int size() { + return size; } - public void insertAfter(Node p, int value) { - Node newNode = new Node(value, null); - insertAfter(p, newNode); + public boolean isEmpty() { + return size == 0; } - public void insertAfter(Node p, Node newNode) { - if (p == null) return; - - newNode.next = p.next; - p.next = newNode; + public int indexOf(E element) { + int pos = 0; + Node p = first.next; + while (p != null) { + if (p.element.equals(element)) { + return pos; + } + p = p.next; + pos++; + } + return -1; } - public void insertBefore(Node p, int value) { - Node newNode = new Node(value, null); - insertBefore(p, newNode); + public E get(int index) { + Node node = node(index); + return node == null ? null : node.element; } - public void insertBefore(Node p, Node newNode) { - if (p == null) return; - if (head == p) { - insertToHead(newNode); - return; + Node node(int index) { + int i = 0; + Node p = first; + while (p != null && i != index) { + p = p.next; + i++; } + return p; + } - Node q = head; - while (q != null && q.next != p) { - q = q.next; - } + public void addFirst(E element) { + Node node = new Node<>(element); + node.next = first.next; + first.next = node; + size++; + } - if (q == null) { - return; + public void addLast(E element) { + Node node = new Node<>(element); + Node p = first; + while (p.next != null) { + p = p.next; } - - newNode.next = p; - q.next = newNode; + p.next = node; + size++; } - public void deleteByNode(Node p) { - if (p == null || head == null) return; + public boolean add(int index, E element) { - if (p == head) { - head = head.next; - return; - } - - Node q = head; - while (q != null && q.next != p) { - q = q.next; - } + checkPositionIndex(index); - if (q == null) { - return; + if (index == 0) { + addFirst(element); + return true; } - q.next = q.next.next; + Node p = node(index - 1); + Node node = new Node<>(element); + node.next = p.next; + p.next = node; + size++; + return true; } - public void deleteByValue(int value) { - if (head == null) return; + public void removeFirst() { + first = first.next; + size--; + } - Node p = head; - Node q = null; - while (p != null && p.data != value) { - q = p; + public void removeLast() { + Node p = first; + while (p.next.next != null) { p = p.next; } + p.next = null; + size--; + } - if (p == null) return; + public boolean remove(int index) { - if (q == null) { - head = head.next; - } else { - q.next = q.next.next; - } + checkElementIndex(index); - // 可重复删除指定value的代码 - /* - if (head != null && head.data == value) { - head = head.next; - } - - Node pNode = head; - while (pNode != null) { - if (pNode.next.data == data) { - pNode.next = pNode.next.next; - continue; - } - pNode = pNode.next; - } - */ - } + if (index == 0) { + removeFirst(); + } - public void printAll() { - Node p = head; - while (p != null) { - System.out.print(p.data + " "); + int pos = 0; + Node p = first; + while (pos < index - 1) { p = p.next; + pos++; } - System.out.println(); + p.next = p.next.next; + size--; + return true; } - //判断true or false - public boolean TFResult(Node left, Node right) { - Node l = left; - Node r = right; - - boolean flag = true; - System.out.println("left_:" + l.data); - System.out.println("right_:" + r.data); - while (l != null && r != null) { - if (l.data == r.data) { - l = l.next; - r = r.next; - continue; - } else { - flag = false; - break; + public boolean remove(E e) { + if (e == null) { + Node p = first; + while (p.next != null) { + Node x = p.next; + if (x.element == null) { + p.next = x.next; + size--; + return true; + } + p = p.next; } - } - - System.out.println("什么结果"); - return flag; - /* if (l==null && r==null){ - System.out.println("什么结果"); - return true; - }else{ - return false; - }*/ - } - // 判断是否为回文 - - public boolean palindrome() { - if (head == null) { - return false; } else { - System.out.println("开始执行找到中间节点"); - Node p = head; - Node q = head; - if (p.next == null) { - System.out.println("只有一个元素"); - return true; - } - while (q.next != null && q.next.next != null) { + Node p = first; + while (p.next != null) { + Node x = p.next; + if (x.element.equals(e)) { + p.next = x.next; + size--; + return true; + } p = p.next; - q = q.next.next; - } - - System.out.println("中间节点" + p.data); - System.out.println("开始执行奇数节点的回文判断"); - Node leftLink = null; - Node rightLink = null; - if (q.next == null) { - // p 一定为整个链表的中点,且节点数目为奇数 - rightLink = p.next; - leftLink = inverseLinkList(p).next; - System.out.println("左边第一个节点" + leftLink.data); - System.out.println("右边第一个节点" + rightLink.data); - } else { - //p q 均为中点 - rightLink = p.next; - leftLink = inverseLinkList(p); } - return TFResult(leftLink, rightLink); } + return false; } - //带结点的链表翻转 - public Node inverseLinkList_head(Node p) { - // Head 为新建的一个头结点 - Node Head = new Node(9999, null); - // p 为原来整个链表的头结点,现在Head指向 整个链表 - Head.next = p; - /* - 带头结点的链表翻转等价于 - 从第二个元素开始重新头插法建立链表 - */ - Node Cur = p.next; - p.next = null; - Node next = null; + public boolean removeAll(E e) { - while (Cur != null) { - next = Cur.next; - Cur.next = Head.next; - Head.next = Cur; - System.out.println("first " + Head.data); + if (first.next == null) { + return false; + } - Cur = next; + if (e == null) { + Node p = first; + while (p.next != null) { + Node x = p.next; + if (x.element == null) { + p.next = x.next; + size--; + } + p = p.next; + } + } else { + Node p = first; + while (p != null && p.next != null) { + if (p.next.element.equals(e)) { + p.next = p.next.next; + size--; + } else { + p = p.next; + } + } } + return true; + } - // 返回左半部分的中点之前的那个节点 - // 从此处开始同步像两边比较 - return Head; + public void clear() { + first.next = null; + size = 0; } - //无头结点的链表翻转 - public Node inverseLinkList(Node p) { + private void checkElementIndex(int index) { + if (index >= 0 && index < size) { return; } + throw new RuntimeException("超出边界!"); + } - Node pre = null; - Node r = head; - System.out.println("z---" + r.data); - Node next = null; - while (r != p) { - next = r.next; + private void checkPositionIndex(int index) { + if (index >= 0 && index <= size) { return; } + throw new RuntimeException("超出边界!"); + } - r.next = pre; - pre = r; - r = next; + public void printAll() { + Node p = first.next; + while (p != null) { + System.out.print(p.element + " "); + p = p.next; } - - r.next = pre; - // 返回左半部分的中点之前的那个节点 - // 从此处开始同步像两边比较 - return r; + System.out.println(); } - public static Node createNode(int value) { - return new Node(value, null); + public List toList() { + List list = new ArrayList<>(); + Node node = first.next; + while (node != null) { + list.add(node.element); + node = node.next; + } + return list; } - public static class Node { + @Getter + @Setter + private static class Node { - private int data; - private Node next; + private E element; + private Node next; - public Node(int data, Node next) { - this.data = data; - this.next = next; + public Node(E element) { + this.element = element; + this.next = null; } - public int getData() { - return data; + public Node(E element, Node next) { + this.element = element; + this.next = next; } } public static void main(String[] args) { - SinglyLinkedList link = new SinglyLinkedList(); - System.out.println("hello"); - //int data[] = {1}; - //int data[] = {1,2}; - //int data[] = {1,2,3,1}; - //int data[] = {1,2,5}; - //int data[] = {1,2,2,1}; - // int data[] = {1,2,5,2,1}; - int data[] = { 1, 2, 5, 3, 1 }; - - for (int i = 0; i < data.length; i++) { - //link.insertToHead(data[i]); - link.insertTail(data[i]); - } - // link.printAll(); - // Node p = link.inverseLinkList_head(link.head); - // while(p != null){ - // System.out.println("aa"+p.data); - // p = p.next; - // } - - System.out.println("打印原始:"); - link.printAll(); - if (link.palindrome()) { - System.out.println("回文"); - } else { - System.out.println("不是回文"); + Integer[] nums = { 1, 2, 3, 4, 5 }; + SinglyLinkedList list = new SinglyLinkedList<>(nums); + SinglyLinkedList reverseList = new SinglyLinkedList<>(); + for (int num : nums) { + reverseList.addFirst(num); } + + list.add(5, 999); + System.out.println("【队尾写入链表】"); + list.printAll(); + System.out.println("【队头写入链表】"); + reverseList.printAll(); + System.out.println("999 在队列中的位置:" + list.indexOf(999)); + System.out.println("队列中位置 5 的元素值:" + list.get(5)); + + System.out.println("【删除指定位置元素】"); + list.removeLast(); + list.printAll(); + list.remove(new Integer(999)); + list.printAll(); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\206\351\232\224\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\206\351\232\224\351\223\276\350\241\250.java" index 749f5e7..d75b224 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\206\351\232\224\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\206\351\232\224\351\223\276\350\241\250.java" @@ -29,7 +29,26 @@ public static void main(String[] args) { } public static ListNode partition(ListNode head, int x) { - return null; + ListNode dummy1 = new ListNode(-1); + ListNode dummy2 = new ListNode(-1); + ListNode d1 = dummy1; + ListNode d2 = dummy2; + ListNode p = head; + while (p != null) { + if (p.val < x) { + d1.next = p; + d1 = d1.next; + } else { + d2.next = p; + d2 = d2.next; + } + ListNode temp = p.next; + p.next = null; + p = temp; + } + d1.next = dummy2.next; + d2.next = null; + return dummy1.next; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" new file mode 100644 index 0000000..103b695 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" @@ -0,0 +1,48 @@ +package io.github.dunwu.algorithm.list; + +import org.junit.jupiter.api.Assertions; + +import java.util.List; + +/** + * @author Zhang Peng + * @see 删除链表的倒数第 N 个结点 + * @since 2020-06-09 + */ +public class 删除链表的倒数第N个结点 { + + public static void main(String[] args) { + ListNode head1 = ListUtil.buildList(1, 2, 3, 4, 5); + ListNode result = removeNthFromEnd(head1, 2); + List list = ListUtil.toList(result); + System.out.println(list); + Assertions.assertArrayEquals(new Integer[] { 1, 2, 3, 5 }, list.toArray(new Integer[0])); + + ListNode head2 = ListUtil.buildList(1); + ListNode result2 = removeNthFromEnd(head2, 1); + List list2 = ListUtil.toList(result2); + System.out.println(list2); + Assertions.assertArrayEquals(new Integer[] {}, list2.toArray(new Integer[0])); + } + + public static ListNode removeNthFromEnd(ListNode head, int n) { + + if (n < 1) { + return head; + } + + ListNode fast = head; + for (int i = 0; i < n + 1 && fast != null; i++) { + fast = fast.next; + } + + ListNode slow = head; + while (fast != null) { + fast = fast.next; + slow = slow.next; + } + slow.next = slow.next.next; + return head; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" index 8bef8cf..6e656a6 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" @@ -25,7 +25,7 @@ public class 单链表示例 { * * @param value 数据值 */ - public void addHead(E value) { + public void addFirst(E value) { ListNode newNode = new ListNode<>(value, null); newNode.next = this.head.next; this.head.next = newNode; @@ -36,7 +36,7 @@ public void addHead(E value) { * * @param value 数据值 */ - public void addTail(E value) { + public void addLast(E value) { // init new node ListNode newNode = new ListNode<>(value, null); @@ -65,15 +65,15 @@ public void remove(ListNode node) { * 删除首个值为 value 的节点 * * @param value 数据值 - * @return {@link ListNode} + * @return {@link io.github.dunwu.algorithm.list.单链表示例.ListNode} */ - public ListNode removeFirst(E value) { + public E removeFirst(E value) { ListNode prev = this.head; while (prev.next != null) { ListNode curr = prev.next; if (curr.value.equals(value)) { prev.next = curr.next; - return curr; + return curr.value; } prev = prev.next; } @@ -124,7 +124,7 @@ public void clear() { * 从头开始查找,一旦发现有数值与查找值相等的节点,直接返回此节点。如果遍历结束,表明未找到节点,返回 null。 * * @param value 数据值 - * @return {@link ListNode} + * @return {@link io.github.dunwu.algorithm.list.单链表示例.ListNode} */ public ListNode find(E value) { ListNode node = this.head.next; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250.java" index f3feee4..30b0465 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250.java" @@ -2,6 +2,8 @@ import org.junit.jupiter.api.Assertions; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -19,6 +21,12 @@ public static void main(String[] args) { List list = ListUtil.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 1, 1, 2, 3, 4, 4, 5, 6 }, list.toArray(new Integer[0])); + + ListNode[] array2 = new ListNode[] {}; + ListNode result2 = mergeKLists(array2); + List list2 = ListUtil.toList(result2); + System.out.println(list2); + Assertions.assertArrayEquals(new Integer[] {}, list2.toArray(new Integer[0])); } /** @@ -72,4 +80,23 @@ public static ListNode mergeKLists(ListNode[] lists) { return root.next; } + public static ListNode mergeKLists2(ListNode[] lists) { + List nodeList = new ArrayList<>(); + for (ListNode head : lists) { + while (head != null) { + nodeList.add(head); + head = head.next; + } + } + + ListNode result = new ListNode(-1); + ListNode p = result; + Collections.sort(nodeList, (a, b) -> a.val - b.val); + for (ListNode node : nodeList) { + p.next = node; + p = p.next; + } + return result.next; + } + } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250\350\247\243\346\263\2252.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250\350\247\243\346\263\2252.java" index 1bfaa86..85d0958 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250\350\247\243\346\263\2252.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250\350\247\243\346\263\2252.java" @@ -19,6 +19,12 @@ public static void main(String[] args) { List list = ListUtil.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 1, 1, 2, 3, 4, 4, 5, 6 }, list.toArray(new Integer[0])); + + ListNode[] array2 = new ListNode[] {}; + ListNode result2 = mergeKLists(array2); + List list2 = ListUtil.toList(result2); + System.out.println(list2); + Assertions.assertArrayEquals(new Integer[] {}, list2.toArray(new Integer[0])); } /** @@ -40,10 +46,9 @@ public static void main(String[] args) { * @see 23. 合并K个排序链表 */ public static ListNode mergeKLists(ListNode[] lists) { - if (lists == null || lists.length == 1) { - return lists[0]; + if (lists == null || lists.length == 0) { + return null; } - ListNode result = lists[0]; for (int i = 1; i < lists.length; i++) { result = 合并两个有序链表.mergeTwoLists(result, lists[i]); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" index be74796..302023f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" @@ -13,29 +13,26 @@ public static void main(String[] args) { ListNode head = ListUtil.buildList(3, 2, 0, -4); Assertions.assertFalse(hasCycle(head)); - head = ListUtil.buildCycleList(1, new int[] { 3, 2, 0, -4 }); - Assertions.assertTrue(hasCycle(head)); + ListNode head2 = ListUtil.buildCycleList(1, new int[] { 3, 2, 0, -4 }); + Assertions.assertTrue(hasCycle(head2)); - head = ListUtil.buildCycleList(0, new int[] { 1, 2 }); - Assertions.assertTrue(hasCycle(head)); + ListNode head3 = ListUtil.buildCycleList(0, new int[] { 1, 2 }); + Assertions.assertTrue(hasCycle(head3)); + + ListNode head4 = ListUtil.buildCycleList(1, new int[] { 1 }); + Assertions.assertFalse(hasCycle(head4)); } public static boolean hasCycle(ListNode head) { - if (head == null || head.next == null) { - return false; - } - - ListNode slow = head; - ListNode fast = head.next; - while (slow != fast) { - if (fast == null || fast.next == null) { - return false; - } - slow = slow.next; + ListNode fast = head.next, slow = head; + while (fast != null && fast.next != null) { fast = fast.next.next; + slow = slow.next; + if (fast == slow) { + return true; + } } - - return true; + return false; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" index 7405c45..89ce85a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" @@ -1,27 +1,45 @@ package io.github.dunwu.algorithm.list; +import org.junit.jupiter.api.Assertions; + /** * @author Zhang Peng * @since 2020-07-08 */ public class 环形链表II { + public static void main(String[] args) { + // ListNode head = ListUtil.buildList(3, 2, 0, -4); + // Assertions.assertEquals(null, detectCycle(head)); + + ListNode head2 = ListUtil.buildCycleList(1, new int[] { 3, 2, 0, -4 }); + Assertions.assertEquals(2, detectCycle(head2).val); + + ListNode head3 = ListUtil.buildCycleList(0, new int[] { 1, 2 }); + Assertions.assertEquals(1, detectCycle(head3).val); + + ListNode head4 = ListUtil.buildCycleList(1, new int[] { 1 }); + Assertions.assertEquals(null, detectCycle(head4)); + } + public static ListNode detectCycle(ListNode head) { - ListNode slow = head; - ListNode fast = head; - while (true) { - if (fast == null || fast.next == null) { - return null; - } - slow = slow.next; + ListNode fast = head, slow = head; + while (fast != null && fast.next != null) { fast = fast.next.next; - if (slow == fast) break; + slow = slow.next; + if (fast == slow) { + break; + } + } + + if (fast == null || fast.next == null) { + return null; } fast = head; - while (slow != fast) { - slow = slow.next; + while (fast != slow) { fast = fast.next; + slow = slow.next; } return fast; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" index 9eaf090..f1f7987 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" @@ -7,14 +7,39 @@ */ public class 相交链表 { + /** + * 时间复杂度:O(m * n) + */ public static ListNode getIntersectionNode(final ListNode headA, final ListNode headB) { - if (headA == null || headB == null) return null; - ListNode pA = headA, pB = headB; - while (pA != pB) { - pA = pA == null ? headB : pA.next; - pB = pB == null ? headA : pB.next; + ListNode a = headA; + while (a != null) { + ListNode b = headB; + while (b != null) { + if (a == b) { + return a; + } + b = b.next; + } + a = a.next; } - return pA; + return null; + } + + public static ListNode getIntersectionNode2(final ListNode headA, final ListNode headB) { + ListNode a = headA, b = headB; + while (a != b) { + if (a == null) { + a = headB; + } else { + a = a.next; + } + if (b == null) { + b = headA; + } else { + b = b.next; + } + } + return a; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" index f6bfbe5..3256313 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" @@ -12,41 +12,30 @@ public static void main(String[] args) { ListNode head = ListUtil.buildList(1, 2, 3, 4, 5); int val = kthToLast(head, 2); Assertions.assertEquals(4, val); + + ListNode head2 = ListUtil.buildList(1); + int val2 = kthToLast(head2, 1); + Assertions.assertEquals(1, val2); } /** - * @see 面试题 02.02. 返回倒数第 k 个节点 + * @see 面试题 02.02. 返回倒数第 k + * 个节点 */ public static int kthToLast(ListNode head, int k) { - int length = length(head); - if (k > length) { - return -1; - } - int pos = length - k; - ListNode node = head; - while (node != null && pos > 0) { - node = node.next; - pos--; + ListNode fast = head; + // fast 指针先走 k 步 + for (int i = 0; i < k; i++) { + fast = fast.next; } - if (node != null) { - return node.val; - } else { - return -1; - } - } - - public static int length(ListNode head) { - if (head == null) { - return 0; - } - - int count = 1; - ListNode node = head.next; - while (node != null) { - count++; - node = node.next; + // fast、slow 同时走,直到结束 + ListNode slow = head; + while (fast != null) { + fast = fast.next; + slow = slow.next; } - return count; + // slow 现在指向第 n - k + 1 个节点,即倒数第 k 个节点 + return slow.val; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" new file mode 100644 index 0000000..614a7f5 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" @@ -0,0 +1,19 @@ +package io.github.dunwu.algorithm.string; + +import org.junit.jupiter.api.Assertions; + +/** + * @author Zhang Peng + * @date 2025-01-10 + */ +public class 最小覆盖子串 { + + public static void main(String[] args) { + Assertions.assertEquals("BANC", minWindow("ADOBECODEBANC", "ABC")); + } + + public static String minWindow(String s, String t) { + return null; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" new file mode 100644 index 0000000..afcb0a9 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" @@ -0,0 +1,45 @@ +package io.github.dunwu.algorithm.string; + +import org.junit.jupiter.api.Assertions; + +/** + * @author Zhang Peng + * @date 2025-01-10 + */ +public class 最长回文子串 { + + public static void main(String[] args) { + Assertions.assertEquals("bab", longestPalindrome("babad")); + Assertions.assertEquals("bb", longestPalindrome("cbbd")); + Assertions.assertEquals("aca", longestPalindrome("aacabdkacaa")); + } + + public static String longestPalindrome(String s) { + char[] chars = s.toCharArray(); + String max = s.substring(0, 1); + for (int i = 0; i < chars.length; i++) { + for (int j = chars.length - 1; j > i; j--) { + if (check(chars, i, j)) { + String temp = s.substring(i, j + 1); + if (temp.length() > max.length()) { + max = temp; + } + } + } + } + return max; + } + + public static boolean check(char[] chars, int begin, int end) { + int left = begin, right = end; + while (left < right) { + if (chars[left] != chars[right]) { + return false; + } + left++; + right--; + } + return true; + } + +} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java new file mode 100644 index 0000000..a89cfb7 --- /dev/null +++ b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java @@ -0,0 +1,83 @@ +package io.github.dunwu.algorithm.list; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; + +/** + * @author Zhang Peng + * @since 2020-01-26 + */ +public class DoubleLinkListTests { + + @Test + public void addTest() { + DoublyLinkedList list = new DoublyLinkedList<>(); + list.addLast(2); + list.addLast(3); + list.addFirst(1); + List result = list.toList(); + System.out.println(result); + Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, result.toArray()); + } + + @Test + public void removeFirstTest() { + DoublyLinkedList list = new DoublyLinkedList<>(); + list.addLast(1); + list.addLast(1); + list.remove(new Integer(1)); + List result = list.toList(); + System.out.println(result); + Assertions.assertArrayEquals(new Integer[] { 1 }, result.toArray()); + + list.clear(); + list.addLast(1); + list.addLast(2); + list.addLast(3); + list.remove(new Integer(1)); + result = list.toList(); + System.out.println(result); + Assertions.assertArrayEquals(new Integer[] { 2, 3 }, result.toArray()); + + list.clear(); + list.addLast(1); + list.addLast(2); + list.addLast(3); + list.remove(new Integer(3)); + result = list.toList(); + System.out.println(result); + Assertions.assertArrayEquals(new Integer[] { 1, 2 }, result.toArray()); + + list.clear(); + list.addLast(1); + list.addLast(2); + list.remove(new Integer(4)); + result = list.toList(); + System.out.println(result); + Assertions.assertArrayEquals(new Integer[] { 1, 2 }, result.toArray()); + } + + @Test + public void removeAllTest() { + DoublyLinkedList list = new DoublyLinkedList<>(); + list.addLast(1); + list.addLast(1); + list.addLast(1); + list.removeAll(1); + List result = list.toList(); + System.out.println(result); + Assertions.assertArrayEquals(new Integer[] {}, result.toArray()); + + list.clear(); + list.addLast(1); + list.addLast(2); + list.addLast(3); + list.removeAll(4); + result = list.toList(); + System.out.println(result); + Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, result.toArray()); + } + +} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java index 3df27b9..06cf157 100644 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java +++ b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java @@ -13,10 +13,10 @@ public class SingleLinkListTests { @Test public void addTest() { - 单链表示例 list = new 单链表示例<>(); - list.addTail(2); - list.addTail(3); - list.addHead(1); + SinglyLinkedList list = new SinglyLinkedList<>(); + list.addLast(2); + list.addLast(3); + list.addFirst(1); List result = list.toList(); System.out.println(result); Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, result.toArray()); @@ -24,36 +24,36 @@ public void addTest() { @Test public void removeFirstTest() { - 单链表示例 list = new 单链表示例<>(); - list.addTail(1); - list.addTail(1); - list.removeFirst(1); + SinglyLinkedList list = new SinglyLinkedList<>(); + list.addLast(1); + list.addLast(1); + list.remove(new Integer(1)); List result = list.toList(); System.out.println(result); Assertions.assertArrayEquals(new Integer[] { 1 }, result.toArray()); list.clear(); - list.addTail(1); - list.addTail(2); - list.addTail(3); - list.removeFirst(1); + list.addLast(1); + list.addLast(2); + list.addLast(3); + list.remove(new Integer(1)); result = list.toList(); System.out.println(result); Assertions.assertArrayEquals(new Integer[] { 2, 3 }, result.toArray()); list.clear(); - list.addTail(1); - list.addTail(2); - list.addTail(3); - list.removeFirst(3); + list.addLast(1); + list.addLast(2); + list.addLast(3); + list.remove(new Integer(3)); result = list.toList(); System.out.println(result); Assertions.assertArrayEquals(new Integer[] { 1, 2 }, result.toArray()); list.clear(); - list.addTail(1); - list.addTail(2); - list.removeFirst(4); + list.addLast(1); + list.addLast(2); + list.remove(new Integer(4)); result = list.toList(); System.out.println(result); Assertions.assertArrayEquals(new Integer[] { 1, 2 }, result.toArray()); @@ -61,19 +61,19 @@ public void removeFirstTest() { @Test public void removeAllTest() { - 单链表示例 list = new 单链表示例<>(); - list.addTail(1); - list.addTail(1); - list.addTail(1); + SinglyLinkedList list = new SinglyLinkedList<>(); + list.addLast(1); + list.addLast(1); + list.addLast(1); list.removeAll(1); List result = list.toList(); System.out.println(result); Assertions.assertArrayEquals(new Integer[] {}, result.toArray()); list.clear(); - list.addTail(1); - list.addTail(2); - list.addTail(3); + list.addLast(1); + list.addLast(2); + list.addLast(3); list.removeAll(4); result = list.toList(); System.out.println(result); From 54042d4a8f0c00a814107142a81ca7c9d8e2c213 Mon Sep 17 00:00:00 2001 From: dunwu Date: Mon, 17 Feb 2025 07:49:15 +0800 Subject: [PATCH 03/21] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- codes/algorithm/pom.xml | 101 +++++++++--------- .../array/\344\270\221\346\225\260I.java" | 30 ++++++ .../array/\344\270\221\346\225\260II.java" | 51 +++++++++ .../array/\344\270\221\346\225\260III.java" | 40 +++++++ ...\345\210\266\346\261\202\345\222\214.java" | 46 ++++++++ ...\351\207\215\345\244\215\351\241\271.java" | 40 +------ ...\347\232\204\345\205\203\347\264\240.java" | 63 +++++++++++ ...\345\257\271\346\225\260\345\255\227.java" | 85 +++++++++++++++ ...\344\270\252\345\225\206\345\223\201.java" | 36 +++++++ ...\347\247\273\345\212\250\351\233\266.java" | 52 +++++++-- ...\347\272\247\344\270\221\346\225\260.java" | 45 ++++++++ ...\346\225\260\347\233\270\345\212\240.java" | 58 ++++------ ...46\225\260\347\233\270\345\212\240II.java" | 51 +++++++++ ...\345\244\215\345\205\203\347\264\240.java" | 94 ++++++++++++++++ ...\345\244\215\345\205\203\347\264\240.java" | 24 +++-- ...45\244\215\345\205\203\347\264\240II.java" | 76 ++++++++++--- ...\344\270\252\347\273\223\347\202\271.java" | 24 +++-- ...\350\275\254\351\223\276\350\241\250.java" | 74 +++++++++---- ...50\275\254\351\223\276\350\241\250II.java" | 57 ++++++++++ ...\345\272\217\351\223\276\350\241\250.java" | 46 ++------ ...350\241\250\350\247\243\346\263\2252.java" | 59 ---------- ...\346\226\207\351\223\276\350\241\250.java" | 28 ++++- ...\345\275\242\351\223\276\350\241\250.java" | 12 ++- ...45\275\242\351\223\276\350\241\250II.java" | 27 ++++- ...\344\272\244\351\223\276\350\241\250.java" | 64 +++++------ ...\344\270\252\350\212\202\347\202\271.java" | 7 +- ...\351\227\264\347\273\223\347\202\271.java" | 49 ++------- ...\347\233\226\345\255\220\344\270\262.java" | 66 +++++++++++- 28 files changed, 1040 insertions(+), 365 deletions(-) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260II.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260III.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250\350\247\243\346\263\2252.java" diff --git a/codes/algorithm/pom.xml b/codes/algorithm/pom.xml index e79e70d..307f4bd 100644 --- a/codes/algorithm/pom.xml +++ b/codes/algorithm/pom.xml @@ -1,55 +1,60 @@ - 4.0.0 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - - io.github.dunwu - dunwu-parent - 1.0.8 - + io.github.dunwu.algorithm + algorithm + 1.0.0 + jar + 算法示例 + 数据示例源码 - io.github.dunwu.algorithm - algorithm - jar - 算法示例 - 数据示例源码 + + UTF-8 + 1.8 + ${java.version} + ${java.version} + - - UTF-8 - 1.8 - ${java.version} - ${java.version} - + + + cn.hutool + hutool-all + 5.8.29 + + + org.projectlombok + lombok + 1.18.36 + provided + + + ch.qos.logback + logback-classic + 1.2.9 + + + org.junit.jupiter + junit-jupiter + 5.8.2 + + + org.assertj + assertj-core + 3.26.3 + + - - - cn.hutool - hutool-all - - - ch.qos.logback - logback-classic - - - org.junit.jupiter - junit-jupiter - - - org.assertj - assertj-core - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - none - - - - + + + + org.apache.maven.plugins + maven-javadoc-plugin + + none + + + + diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" new file mode 100644 index 0000000..9fa6302 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" @@ -0,0 +1,30 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashSet; +import java.util.Set; + +/** + * 263. 丑数 + * + * @author Zhang Peng + * @date 2025-01-24 + */ +public class 丑数I { + + public static void main(String[] args) { + Assertions.assertTrue(isUgly(6)); + Assertions.assertTrue(isUgly(1)); + Assertions.assertFalse(isUgly(14)); + } + + public static boolean isUgly(int n) { + while (n <= 0) return false; + while (n % 2 == 0) n /= 2; + while (n % 3 == 0) n /= 3; + while (n % 5 == 0) n /= 5; + return n == 1; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260II.java" new file mode 100644 index 0000000..8033c89 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260II.java" @@ -0,0 +1,51 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * 264. 丑数II + * + * @author Zhang Peng + * @date 2025-01-24 + */ +public class 丑数II { + + public static void main(String[] args) { + Assertions.assertEquals(12, nthUglyNumber(10)); + Assertions.assertEquals(1, nthUglyNumber(1)); + } + + public static int nthUglyNumber(int n) { + if (n == 1) { + return 1; + } + + // 可以理解为三个指向有序链表头结点的指针 + int p2 = 1, p3 = 1, p5 = 1; + // 可以理解为三个有序链表的头节点的值 + int product2 = 1, product3 = 1, product5 = 1; + // 可以理解为最终合并的有序链表(结果链表) + int[] ugly = new int[n + 1]; + // 可以理解为结果链表上的指针 + int u = 1; + + while (u <= n) { + int min = Math.min(product2, Math.min(product3, product5)); + ugly[u++] = min; + if (min == product2) { + product2 = 2 * ugly[p2]; + p2++; + } + if (min == product3) { + product3 = 3 * ugly[p3]; + p3++; + } + if (min == product5) { + product5 = 5 * ugly[p5]; + p5++; + } + } + return ugly[n]; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260III.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260III.java" new file mode 100644 index 0000000..27434b8 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260III.java" @@ -0,0 +1,40 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * 264. 丑数II + * + * @author Zhang Peng + * @date 2025-01-24 + */ +public class 丑数III { + + public static void main(String[] args) { + Assertions.assertEquals(4, nthUglyNumber(3, 2, 3, 5)); + Assertions.assertEquals(6, nthUglyNumber(4, 2, 3, 4)); + Assertions.assertEquals(10, nthUglyNumber(5, 2, 11, 13)); + Assertions.assertEquals(1999999984, nthUglyNumber(1000000000, 2, 217983653, 336916467)); + } + + public static int nthUglyNumber(int n, int a, int b, int c) { + int p = 1; + int vA = a, vB = b, vC = c; + long min = Integer.MAX_VALUE; + while (p <= n) { + min = Math.min(vA, Math.min(vB, vC)); + if (min == vA) { + vA += a; + } + if (min == vB) { + vB += b; + } + if (min == vC) { + vC += c; + } + p++; + } + return (int) min; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" new file mode 100644 index 0000000..e2fff7c --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" @@ -0,0 +1,46 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * 67. 二进制求和 + * + * @author Zhang Peng + * @date 2025-01-21 + */ +public class 二进制求和 { + + public static void main(String[] args) { + Assertions.assertEquals("100", addBinary("11", "1")); + Assertions.assertEquals("10101", addBinary("1010", "1011")); + } + + public static String addBinary(String a, String b) { + + if (a == null || a.length() == 0) return b; + if (b == null || b.length() == 0) return a; + + char[] arrA = a.toCharArray(); + char[] arrB = b.toCharArray(); + StringBuilder sb = new StringBuilder(); + int carry = 0; + int i = arrA.length - 1, j = arrB.length - 1; + while (i >= 0 || j >= 0) { + int value = carry; + if (i >= 0) { + value += arrA[i--] - '0'; + } + if (j >= 0) { + value += arrB[j--] - '0'; + } + carry = value / 2; + value = value % 2; + sb.append(value); + } + if (carry != 0) { + sb.append(carry); + } + return sb.reverse().toString(); + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" index 06ad78f..03a7e1f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" @@ -1,46 +1,10 @@ package io.github.dunwu.algorithm.array; -// 【删除排序数组中的重复项】 - -// -// 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 -// -// 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 -// -// 示例 1: -// -// 给定数组 nums = [1,1,2], -// -// 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 -// -// 你不需要考虑数组中超出新长度后面的元素。 -// 示例 2: -// -// 给定 nums = [0,0,1,1,1,2,2,3,3,4], -// -// 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 -// -// 你不需要考虑数组中超出新长度后面的元素。 -// 说明: -// -// 为什么返回数值是整数,但输出的答案是数组呢? -// -// 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 -// -// 你可以想象内部操作如下: -// -// // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 -// int len = removeDuplicates(nums); -// -// // 在函数里修改输入数组对于调用者是可见的。 -// // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 -// for (int i = 0; i < len; i++) { -// print(nums[i]); -// } - import org.junit.jupiter.api.Assertions; /** + * 26. 删除有序数组中的重复项 + * * @author Zhang Peng * @since 2018-11-05 */ diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" new file mode 100644 index 0000000..ef0e1ac --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" @@ -0,0 +1,63 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * @author Zhang Peng + * @date 2025-01-21 + */ +public class 有序矩阵中第K小的元素 { + + public static void main(String[] args) { + + int[][] matrix = { { 1, 5, 9 }, { 10, 11, 13 }, { 12, 13, 15 } }; + Assertions.assertEquals(13, kthSmallest(matrix, 8)); + + int[][] matrix2 = { { -5 } }; + Assertions.assertEquals(-5, kthSmallest(matrix2, 1)); + + int[][] matrix3 = { { 1, 2 }, { 1, 3 } }; + Assertions.assertEquals(1, kthSmallest(matrix3, 2)); + + int[][] matrix4 = { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } }; + Assertions.assertEquals(3, kthSmallest(matrix4, 8)); + } + + public static int kthSmallest(int[][] matrix, int n) { + int row = matrix.length; + if (row == 1) { + return matrix[0][n - 1]; + } + int i = 1; + int[] arr = matrix[0]; + while (i < row) { + arr = merge(matrix[i], arr); + i++; + } + return arr[n - 1]; + } + + public static int[] merge(int[] arr1, int[] arr2) { + int i = 0, j = 0, k = 0; + int[] merge = new int[arr1.length + arr2.length]; + while (i < arr1.length && j < arr2.length) { + if (arr1[i] <= arr2[j]) { + merge[k++] = arr1[i++]; + } else { + merge[k++] = arr2[j++]; + } + } + if (i < arr1.length) { + while (i < arr1.length) { + merge[k++] = arr1[i++]; + } + } + if (j < arr2.length) { + while (j < arr2.length) { + merge[k++] = arr2[j++]; + } + } + return merge; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" new file mode 100644 index 0000000..e7a6a02 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" @@ -0,0 +1,85 @@ +package io.github.dunwu.algorithm.array; + +import cn.hutool.json.JSONUtil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.TreeMap; + +/** + * 373. 查找和最小的 K 对数字 + * + * @author Zhang Peng + * @date 2025-01-21 + */ +public class 查找和最小的K对数字 { + + public static void main(String[] args) { + List> expectList1 = new ArrayList<>(); + expectList1.add(Arrays.asList(1, 2)); + expectList1.add(Arrays.asList(1, 4)); + expectList1.add(Arrays.asList(1, 6)); + List> list1 = kSmallestPairs2(new int[] { 1, 7, 11 }, new int[] { 2, 4, 6 }, 3); + System.out.println(JSONUtil.toJsonStr(list1)); + + List> list2 = kSmallestPairs2(new int[] { 1, 1, 2 }, new int[] { 1, 2, 3 }, 2); + System.out.println(JSONUtil.toJsonStr(list2)); + } + + public static List> kSmallestPairs(int[] nums1, int[] nums2, int k) { + List> list = new ArrayList<>(); + list.add(Arrays.asList(0, 0)); + TreeMap map = new TreeMap<>(); + int i = 0, j = 0; + while (i < nums1.length && j < nums2.length) { + + if (i == nums1.length - 1 && j != nums2.length - 1) { + i = 0; + j++; + } else if (i != nums1.length - 1 && j == nums2.length - 1) { + j = 0; + i++; + } + if (i == nums1.length - 1 && j == nums2.length - 1) { + break; + } + + if (nums1[i] + nums2[j + 1] <= nums1[i + 1] + nums2[j]) { + list.add(Arrays.asList(i, j + 1)); + j++; + } else { + list.add(Arrays.asList(i + 1, j)); + i++; + } + + if (i + 1 >= nums1.length && j + 1 >= nums2.length) { } + } + return list; + } + + public static List> kSmallestPairs2(int[] nums1, int[] nums2, int k) { + int i = 0, j = 0; + List> result = new ArrayList<>(); + result.add(Arrays.asList(nums1[i], nums2[j])); + while (i < nums1.length - 1 && j < nums2.length - 1) { + if (nums1[i] + nums2[j + 1] <= nums1[i + 1] + nums2[j]) { + j++; + } else { + i++; + } + result.add(Arrays.asList(nums1[i], nums2[j])); + if (i == nums1.length - 1 && j != nums2.length - 1) { + i = 0; + j++; + } + if (i != nums1.length - 1 && j == nums2.length - 1) { + j = 0; + i++; + } + } + System.out.println(JSONUtil.toJsonStr(result)); + return null; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" new file mode 100644 index 0000000..1e98ab3 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" @@ -0,0 +1,36 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * LCR 179. 查找总价格为目标值的两个商品 + * + * @author Zhang Peng + * @date 2025-01-13 + */ +public class 查找总价格为目标值的两个商品 { + + public static void main(String[] args) { + Assertions.assertArrayEquals(new int[] { 3, 15 }, twoSum(new int[] { 3, 9, 12, 15 }, 18)); + Assertions.assertArrayEquals(new int[] { 27, 34 }, twoSum(new int[] { 8, 21, 27, 34, 52, 66 }, 61)); + } + + /** + * 时间复杂度:O(N) + */ + public static int[] twoSum(int[] price, int target) { + int left = 0, right = price.length - 1; + while (left < right) { + int sum = price[left] + price[right]; + if (sum == target) { + return new int[] { price[left], price[right] }; + } else if (sum < target) { + left++; + } else { + right--; + } + } + return new int[] { -1, -1 }; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\345\212\250\351\233\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\345\212\250\351\233\266.java" index cb26e3d..4528b3f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\345\212\250\351\233\266.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\345\212\250\351\233\266.java" @@ -24,33 +24,65 @@ public class 移动零 { public static void main(String[] args) { int[] nums1 = { 0, 1, 0, 3, 12 }; - 移动零.moveZeroes(nums1); + moveZeroes2(nums1); Assertions.assertArrayEquals(new int[] { 1, 3, 12, 0, 0 }, nums1); int[] nums2 = { 0, 0, 1 }; - 移动零.moveZeroes(nums2); + moveZeroes2(nums2); Assertions.assertArrayEquals(new int[] { 1, 0, 0 }, nums2); + + int[] nums3 = { 0 }; + moveZeroes2(nums3); + Assertions.assertArrayEquals(new int[] { 0 }, nums3); } + /** + * 时间复杂度:O(N^2) + */ public static void moveZeroes(int[] nums) { - int i = 0; - int right = nums.length - 1; - while (i <= right) { - if (nums[i] == 0) { - move(nums, i); + int left = 0, right = nums.length - 1; + while (left < right) { + if (nums[left] == 0) { + move(nums, left); + left = 0; right--; } else { - i++; + left++; } } } private static void move(int[] nums, int pos) { - int temp = nums[pos]; for (int i = pos; i < nums.length - 1; i++) { + int temp = nums[i]; nums[i] = nums[i + 1]; + nums[i + 1] = temp; + } + } + + /** + * 时间复杂度:O(N) + */ + public static void moveZeroes2(int[] nums) { + int count = removeElement(nums, 0); + while (count < nums.length) { + nums[count++] = 0; + } + } + + public static int removeElement(int[] nums, int val) { + if (nums.length == 0) { + return 0; + } + int slow = 0, fast = 0; + while (fast < nums.length) { + if (nums[fast] != val) { + nums[slow] = nums[fast]; + slow++; + } + fast++; } - nums[nums.length - 1] = temp; + return slow; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" new file mode 100644 index 0000000..c372b91 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" @@ -0,0 +1,45 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * 313. 超级丑数 + * + * @author Zhang Peng + * @date 2025-01-24 + */ +public class 超级丑数 { + + public static void main(String[] args) { + Assertions.assertEquals(32, nthSuperUglyNumber(12, new int[] { 2, 7, 13, 19 })); + Assertions.assertEquals(1, nthSuperUglyNumber(1, new int[] { 2, 3, 5 })); + } + + public static int nthSuperUglyNumber(int n, int[] primes) { + int len = primes.length; + int[] offsets = new int[len]; + long[] values = new long[len]; + long[] ugly = new long[n + 1]; + int u = 1; + for (int i = 0; i < len; i++) { + offsets[i] = 1; + values[i] = 1; + } + while (u <= n) { + long min = Integer.MAX_VALUE; + for (int i = 0; i < len; i++) { + min = Math.min(values[i], min); + } + ugly[u++] = min; + + for (int i = 0; i < len; i++) { + if (values[i] == min) { + values[i] = primes[i] * ugly[offsets[i]]; + offsets[i] = offsets[i] + 1; + } + } + } + return (int) ugly[n]; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240.java" index d48687a..c2128a4 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240.java" @@ -5,52 +5,30 @@ import java.util.List; /** + * 2. 两数相加 + * * @author Zhang Peng * @since 2020-06-09 */ public class 两数相加 { public static void main(String[] args) { - ListNode head1 = ListUtil.buildList(2, 4, 3); - ListNode head2 = ListUtil.buildList(5, 6, 4); - ListNode result = addTwoNumbers(head1, head2); - ListUtil.toList(head1); - ListUtil.toList(head2); + ListNode result = addTwoNumbers(ListUtil.buildList(2, 4, 3), ListUtil.buildList(5, 6, 4)); List list = ListUtil.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 7, 0, 8 }, list.toArray()); - head1 = new ListNode(1); - head2 = ListUtil.buildList(9, 9); - result = addTwoNumbers(head1, head2); - ListUtil.toList(head1); - ListUtil.toList(head2); - list = ListUtil.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 0, 0, 1 }, list.toArray()); + ListNode result2 = addTwoNumbers(ListUtil.buildList(0), ListUtil.buildList(0)); + List list2 = ListUtil.toList(result2); + System.out.println(list2); + Assertions.assertArrayEquals(new Integer[] { 0 }, list2.toArray()); + + ListNode result3 = addTwoNumbers(ListUtil.buildList(9, 9, 9, 9, 9, 9, 9), ListUtil.buildList(9, 9, 9, 9)); + List list3 = ListUtil.toList(result3); + System.out.println(list3); + Assertions.assertArrayEquals(new Integer[] { 8, 9, 9, 9, 0, 0, 0, 1 }, list3.toArray()); } - /** - * 两数相加 算法实现 - *

- * 给出两个 非空 的链表用来表示两个非负的整数。 - *

- * 其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 - *

- * 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 - *

- * 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 - *

- * 示例: - *

-     * 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
-     * 输出:7 -> 0 -> 8
-     * 原因:342 + 465 = 807
-     * 
- * - * @see 两数相加 - * @see 面试题 02.05. 链表求和 - */ public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { // 如果任意一个表示数的链表为空,直接返回另一个链表 @@ -61,8 +39,8 @@ public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { int carry = 0; ListNode x = l1; ListNode y = l2; - ListNode resultHead = new ListNode(-1); - ListNode currNode = resultHead; + ListNode dummy = new ListNode(-1); + ListNode p = dummy; // 同时遍历两个操作数链表,任意操作数链表的当前位数所对应元素不为 null 则累加 while (x != null || y != null) { @@ -79,14 +57,14 @@ public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { } carry = value / 10; - currNode.next = new ListNode(value % 10); - currNode = currNode.next; + p.next = new ListNode(value % 10); + p = p.next; } if (carry != 0) { - currNode.next = new ListNode(carry); + p.next = new ListNode(carry); } - return resultHead.next; + return dummy.next; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" new file mode 100644 index 0000000..0df454e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" @@ -0,0 +1,51 @@ +package io.github.dunwu.algorithm.list; + +import org.junit.jupiter.api.Assertions; + +import java.util.List; + +/** + * LCR 025. 两数相加II + * + * @author Zhang Peng + * @date 2025-01-21 + */ +public class 两数相加II { + + public static void main(String[] args) { + ListNode result = addTwoNumbers(ListUtil.buildList(7, 2, 4, 3), ListUtil.buildList(5, 6, 4)); + List list = ListUtil.toList(result); + System.out.println(list); + Assertions.assertArrayEquals(new Integer[] { 7, 8, 0, 7 }, list.toArray()); + + ListNode result2 = addTwoNumbers(ListUtil.buildList(2, 4, 3), ListUtil.buildList(5, 6, 4)); + List list2 = ListUtil.toList(result2); + System.out.println(list2); + Assertions.assertArrayEquals(new Integer[] { 8, 0, 7 }, list2.toArray()); + + ListNode result3 = addTwoNumbers(ListUtil.buildList(0), ListUtil.buildList(0)); + List list3 = ListUtil.toList(result3); + System.out.println(list3); + Assertions.assertArrayEquals(new Integer[] { 0 }, list3.toArray()); + } + + public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { + // 将两个链表倒置,方便先从低位到高位,逐次相加 + ListNode r1 = reverse(l1); + ListNode r2 = reverse(l2); + ListNode result = 两数相加.addTwoNumbers(r1, r2); + return reverse(result); + } + + public static ListNode reverse(ListNode head) { + ListNode pre = null, cur = head; + while (cur != null) { + ListNode next = cur.next; + cur.next = pre; + pre = cur; + cur = next; + } + return pre; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" new file mode 100644 index 0000000..d4a69af --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" @@ -0,0 +1,94 @@ +package io.github.dunwu.algorithm.list; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 83. 删除排序链表中的重复元素 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 从未排序的链表中移除重复元素 { + + public static void main(String[] args) { + ListNode head = ListUtil.buildList(1, 2, 3, 2); + System.out.println(ListUtil.toList(head)); + ListNode result = deleteDuplicates2(head); + List list = ListUtil.toList(result); + System.out.println(list); + Assertions.assertArrayEquals(new Integer[] { 1, 3 }, list.toArray(new Integer[0])); + + ListNode head2 = ListUtil.buildList(2, 1, 1, 2); + System.out.println(ListUtil.toList(head2)); + ListNode result2 = deleteDuplicates2(head2); + List list2 = ListUtil.toList(result2); + System.out.println(list2); + Assertions.assertArrayEquals(new Integer[] {}, list2.toArray(new Integer[0])); + + ListNode head3 = ListUtil.buildList(3, 2, 2, 1, 3, 2, 4); + System.out.println(ListUtil.toList(head3)); + ListNode result3 = deleteDuplicates2(head3); + List list3 = ListUtil.toList(result3); + System.out.println(list3); + Assertions.assertArrayEquals(new Integer[] { 1, 4 }, list3.toArray(new Integer[0])); + } + + public static ListNode deleteDuplicates(ListNode head) { + Map map = new HashMap<>(); + ListNode p = head; + while (p != null) { + map.put(p.val, map.getOrDefault(p.val, 0) + 1); + p = p.next; + } + + ListNode dup = new ListNode(101); + ListNode nodup = new ListNode(101); + ListNode pDup = dup, pNodup = nodup; + p = head; + while (p != null) { + if (map.get(p.val) > 1) { + pDup.next = p; + pDup = pDup.next; + } else { + pNodup.next = p; + pNodup = pNodup.next; + } + + p = p.next; + pDup.next = null; + pNodup.next = null; + } + return nodup.next; + } + + public static ListNode deleteDuplicates2(ListNode head) { + ListNode dupList = new ListNode(0); + ListNode nodupList = new ListNode(0); + ListNode dup = dupList, nodup = nodupList; + ListNode p = head; + Map map = new HashMap<>(); + while (p != null) { + map.put(p.val, map.getOrDefault(p.val, 0) + 1); + p = p.next; + } + p = head; + while (p != null) { + if (map.get(p.val) > 1) { + dup.next = p; + dup = dup.next; + } else { + nodup.next = p; + nodup = nodup.next; + } + p = p.next; + dup.next = null; + nodup.next = null; + } + return nodupList.next; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" index 5873f31..e38379b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" @@ -5,8 +5,9 @@ import java.util.List; /** + * 83. 删除排序链表中的重复元素 + * * @author Zhang Peng - * @see 83. 删除排序链表中的重复元素 * @since 2020-06-09 */ public class 删除排序链表中的重复元素 { @@ -18,16 +19,27 @@ public static void main(String[] args) { List list = ListUtil.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 1, 2 }, list.toArray(new Integer[0])); + + ListNode head2 = ListUtil.buildList(1, 1, 2, 3, 3); + System.out.println(ListUtil.toList(head2)); + ListNode result2 = deleteDuplicates(head2); + List list2 = ListUtil.toList(result2); + System.out.println(list2); + Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, list2.toArray(new Integer[0])); } public static ListNode deleteDuplicates(ListNode head) { - ListNode node = head; - while (node != null && node.next != null) { - if (node.val == node.next.val) { - node.next = node.next.next; + if (head == null || head.next == null) { + return head; + } + ListNode slow = head, fast = head.next; + while (fast != null) { + if (slow.val == fast.val) { + slow.next = fast.next; } else { - node = node.next; + slow = slow.next; } + fast = fast.next; } return head; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.java" index 1bc2a84..a037bb1 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.java" @@ -5,33 +5,75 @@ import java.util.List; /** + * 83. 删除排序链表中的重复元素 + * * @author Zhang Peng - * @since 2020-07-06 + * @since 2020-06-09 */ public class 删除排序链表中的重复元素II { public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 1, 2); - System.out.println(ListUtil.toList(head)); - ListNode result = deleteDuplicates(head); - List list = ListUtil.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 2 }, list.toArray(new Integer[0])); + // ListNode head = ListUtil.buildList(1, 2, 3, 3, 4, 4, 5); + // System.out.println(ListUtil.toList(head)); + // ListNode result = deleteDuplicates2(head); + // List list = ListUtil.toList(result); + // System.out.println(list); + // Assertions.assertArrayEquals(new Integer[] { 1, 2, 5 }, list.toArray(new Integer[0])); + // + // ListNode head2 = ListUtil.buildList(1, 1, 1, 2, 3); + // System.out.println(ListUtil.toList(head2)); + // ListNode result2 = deleteDuplicates2(head2); + // List list2 = ListUtil.toList(result2); + // System.out.println(list2); + // Assertions.assertArrayEquals(new Integer[] { 2, 3 }, list2.toArray(new Integer[0])); + + ListNode head3 = ListUtil.buildList(1, 2, 2); + System.out.println(ListUtil.toList(head3)); + ListNode result3 = deleteDuplicates2(head3); + List list3 = ListUtil.toList(result3); + System.out.println(list3); + Assertions.assertArrayEquals(new Integer[] { 1 }, list3.toArray(new Integer[0])); } public static ListNode deleteDuplicates(ListNode head) { - if (head == null) return head; // 若head为空则直接返回null - ListNode dummy = new ListNode(-1); // 建立一个虚拟头结点 - ListNode tail = dummy; // 定义一个尾巴,用于尾插法。 - for (ListNode l = head, r = head; l != null; l = r) { - while (r != null && r.val == l.val) r = r.next; // 只要r不为空并且与l的值相等则一直向后移动 - if (l.next == r) { // 若长度为1,则通过尾插法加入。 - tail.next = l; // 基本的尾插法 - tail = l; - tail.next = null; // 这里记得将尾部的后面置为null,不然可能后面会带着一些其他的节点。 + ListNode dupList = new ListNode(101); + ListNode nodupList = new ListNode(101); + + ListNode dup = dupList, nodup = nodupList; + ListNode cur = head; + while (cur != null) { + if ((cur.next != null && cur.val == cur.next.val) || cur.val == dup.val) { + dup.next = cur; + dup = dup.next; + } else { + nodup.next = cur; + nodup = nodup.next; + } + cur = cur.next; + dup.next = null; + nodup.next = null; + } + return nodupList.next; + } + + public static ListNode deleteDuplicates2(ListNode head) { + ListNode dupList = new ListNode(101); + ListNode nodupList = new ListNode(101); + ListNode dup = dupList, nodup = nodupList; + ListNode p = head; + while (p != null) { + if ((p.next != null && p.val == p.next.val) || p.val == dup.val) { + dup.next = p; + dup = dup.next; + } else { + nodup.next = p; + nodup = nodup.next; } + p = p.next; + dup.next = null; + nodup.next = null; } - return dummy.next; + return nodupList.next; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" index 103b695..43e81d7 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" @@ -5,8 +5,9 @@ import java.util.List; /** + * 19. 删除链表的倒数第 N 个结点 + * * @author Zhang Peng - * @see 删除链表的倒数第 N 个结点 * @since 2020-06-09 */ public class 删除链表的倒数第N个结点 { @@ -23,26 +24,31 @@ public static void main(String[] args) { List list2 = ListUtil.toList(result2); System.out.println(list2); Assertions.assertArrayEquals(new Integer[] {}, list2.toArray(new Integer[0])); + + ListNode head3 = ListUtil.buildList(1, 2); + ListNode result3 = removeNthFromEnd(head3, 1); + List list3 = ListUtil.toList(result3); + System.out.println(list3); + Assertions.assertArrayEquals(new Integer[] { 1 }, list3.toArray(new Integer[0])); } public static ListNode removeNthFromEnd(ListNode head, int n) { + ListNode dummy = new ListNode(-1); + dummy.next = head; - if (n < 1) { - return head; - } - - ListNode fast = head; - for (int i = 0; i < n + 1 && fast != null; i++) { + ListNode fast = dummy; + for (int i = 0; i < n + 1; i++) { fast = fast.next; } - ListNode slow = head; + ListNode slow = dummy; while (fast != null) { fast = fast.next; slow = slow.next; } + slow.next = slow.next.next; - return head; + return dummy.next; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250.java" index 952f02e..47963f5 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250.java" @@ -15,15 +15,34 @@ public class 反转链表 { public static void main(String[] args) { ListNode head = ListUtil.buildList(1, 2, 3, 4); System.out.println(ListUtil.toList(head)); - ListNode result = reverseList2(head); + ListNode result = reverseList3(head); List list = ListUtil.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 4, 3, 2, 1 }, list.toArray(new Integer[0])); + + ListNode head2 = ListUtil.buildList(1, 2); + System.out.println(ListUtil.toList(head2)); + ListNode result2 = reverseList3(head2); + List list2 = ListUtil.toList(result2); + System.out.println(list2); + Assertions.assertArrayEquals(new Integer[] { 2, 1 }, list2.toArray(new Integer[0])); + + ListNode head3 = ListUtil.buildList(); + System.out.println(ListUtil.toList(head3)); + ListNode result3 = reverseList3(head3); + List list3 = ListUtil.toList(result3); + System.out.println(list3); + Assertions.assertArrayEquals(new Integer[] {}, list3.toArray(new Integer[0])); } - // 借助栈来实现 + /** + * 借助栈来实现,时间复杂度:O(2N) + */ public static ListNode reverseList(ListNode head) { - if (head == null) return null; + if (head == null) { + return head; + } + Stack stack = new Stack<>(); ListNode node = head; while (node != null) { @@ -31,32 +50,49 @@ public static ListNode reverseList(ListNode head) { node = node.next; } - ListNode dummy = new ListNode(-1); - node = dummy; + ListNode dummy = new ListNode(-5001); + ListNode p = dummy; while (!stack.isEmpty()) { - node.next = stack.pop(); - node.next.next = null; - node = node.next; + ListNode top = stack.pop(); + top.next = null; + p.next = top; + p = p.next; } return dummy.next; } + /** + * 双指针,时间复杂度:O(N) + */ public static ListNode reverseList2(ListNode head) { + if (head == null) { - return null; + return head; + } + + ListNode pre = null, cur = head; + while (cur != null) { + ListNode next = cur.next; + cur.next = pre; + pre = cur; + cur = next; } + return pre; + } + + /** + * 递归 + */ + public static ListNode reverseList3(ListNode head) { - ListNode dummy = new ListNode(-1); - dummy.next = head; - ListNode prev = null; - ListNode curr = head; - while (curr != null) { - ListNode temp = curr.next; - curr.next = prev; - prev = curr; - curr = temp; + if (head == null || head.next == null) { + return head; } - return prev; + + ListNode last = reverseList3(head.next); + head.next.next = head; + head.next = null; + return last; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" new file mode 100644 index 0000000..6923236 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" @@ -0,0 +1,57 @@ +package io.github.dunwu.algorithm.list; + +import org.junit.jupiter.api.Assertions; + +import java.util.List; + +/** + * 92. 反转链表 II + * + * @author Zhang Peng + * @date 2025-01-20 + */ +public class 反转链表II { + + public static void main(String[] args) { + ListNode head = ListUtil.buildList(1, 2, 3, 4, 5); + System.out.println(ListUtil.toList(head)); + ListNode result = reverseList(head, 2, 4); + List list = ListUtil.toList(result); + System.out.println(list); + Assertions.assertArrayEquals(new Integer[] { 1, 4, 3, 2, 5 }, list.toArray(new Integer[0])); + } + + /** + * 借助栈来实现,时间复杂度:O(2N) + */ + public static ListNode reverseList(ListNode head, int m, int n) { + if (m == 1) { + return reverseN(head, n); + } + ListNode cur = head; + for (int i = 1; i < m - 1; i++) { + cur = cur.next; + } + cur.next = reverseN(cur.next, n - m + 1); + return head; + } + + public static ListNode reverseN(ListNode head, int n) { + if (head == null || head.next == null) { + return head; + } + ListNode pre = null, cur = head; + while (cur != null && n > 0) { + ListNode next = cur.next; + cur.next = pre; + pre = cur; + cur = next; + n--; + } + if (head != null) { + head.next = cur; + } + return pre; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250.java" index 30b0465..af0644a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250.java" @@ -2,11 +2,11 @@ import org.junit.jupiter.api.Assertions; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** + * 23. 合并K个排序链表 + * * @author Zhang Peng * @since 2020-06-09 */ @@ -17,36 +17,18 @@ public static void main(String[] args) { ListNode head2 = ListUtil.buildList(1, 3, 4); ListNode head3 = ListUtil.buildList(2, 6); ListNode[] array = new ListNode[] { head1, head2, head3 }; - ListNode result = mergeKLists(array); + ListNode result = mergeKLists2(array); List list = ListUtil.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 1, 1, 2, 3, 4, 4, 5, 6 }, list.toArray(new Integer[0])); ListNode[] array2 = new ListNode[] {}; - ListNode result2 = mergeKLists(array2); + ListNode result2 = mergeKLists2(array2); List list2 = ListUtil.toList(result2); System.out.println(list2); Assertions.assertArrayEquals(new Integer[] {}, list2.toArray(new Integer[0])); } - /** - * 23. 合并K个排序链表 算法实现 - *

- * 合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。 - *

- * 示例: - *

-     * 输入:
-     * [
-     *   1->4->5,
-     *   1->3->4,
-     *   2->6
-     * ]
-     * 输出: 1->1->2->3->4->4->5->6
-     * 
- * - * @see 23. 合并K个排序链表 - */ public static ListNode mergeKLists(ListNode[] lists) { if (lists == null || lists.length == 0) { return null; @@ -81,22 +63,14 @@ public static ListNode mergeKLists(ListNode[] lists) { } public static ListNode mergeKLists2(ListNode[] lists) { - List nodeList = new ArrayList<>(); - for (ListNode head : lists) { - while (head != null) { - nodeList.add(head); - head = head.next; - } + if (lists == null || lists.length == 0) { + return null; } - - ListNode result = new ListNode(-1); - ListNode p = result; - Collections.sort(nodeList, (a, b) -> a.val - b.val); - for (ListNode node : nodeList) { - p.next = node; - p = p.next; + ListNode result = lists[0]; + for (int i = 1; i < lists.length; i++) { + result = 合并两个有序链表.mergeTwoLists(result, lists[i]); } - return result.next; + return result; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250\350\247\243\346\263\2252.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250\350\247\243\346\263\2252.java" deleted file mode 100644 index 85d0958..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250\350\247\243\346\263\2252.java" +++ /dev/null @@ -1,59 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -import java.util.List; - -/** - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 合并K个排序链表解法2 { - - public static void main(String[] args) { - ListNode head1 = ListUtil.buildList(1, 4, 5); - ListNode head2 = ListUtil.buildList(1, 3, 4); - ListNode head3 = ListUtil.buildList(2, 6); - ListNode[] array = new ListNode[] { head1, head2, head3 }; - ListNode result = mergeKLists(array); - List list = ListUtil.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 1, 1, 2, 3, 4, 4, 5, 6 }, list.toArray(new Integer[0])); - - ListNode[] array2 = new ListNode[] {}; - ListNode result2 = mergeKLists(array2); - List list2 = ListUtil.toList(result2); - System.out.println(list2); - Assertions.assertArrayEquals(new Integer[] {}, list2.toArray(new Integer[0])); - } - - /** - * 23. 合并K个排序链表 算法实现 - *

- * 合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。 - *

- * 示例: - *

-     * 输入:
-     * [
-     *   1->4->5,
-     *   1->3->4,
-     *   2->6
-     * ]
-     * 输出: 1->1->2->3->4->4->5->6
-     * 
- * - * @see 23. 合并K个排序链表 - */ - public static ListNode mergeKLists(ListNode[] lists) { - if (lists == null || lists.length == 0) { - return null; - } - ListNode result = lists[0]; - for (int i = 1; i < lists.length; i++) { - result = 合并两个有序链表.mergeTwoLists(result, lists[i]); - } - return result; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" index a983424..8e3e249 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" @@ -15,10 +15,10 @@ public class 回文链表 { public static void main(String[] args) { ListNode head = ListUtil.buildList(1, 2, 2, 1); - Assertions.assertTrue(isPalindrome(head)); + Assertions.assertTrue(isPalindrome2(head)); head = ListUtil.buildList(1, 2); - Assertions.assertFalse(isPalindrome(head)); + Assertions.assertFalse(isPalindrome2(head)); } public static boolean isPalindrome(ListNode head) { @@ -38,4 +38,28 @@ public static boolean isPalindrome(ListNode head) { return true; } + public static boolean isPalindrome2(ListNode head) { + ListNode left = head; + ListNode right = reverse(head); + while (left != null && right != null) { + if (left.val != right.val) { + return false; + } + left = left.next; + right = right.next; + } + return true; + } + + public static ListNode reverse(ListNode head) { + ListNode pre = null, cur = head; + while (cur != null) { + ListNode next = cur.next; + cur.next = pre; + pre = cur; + cur = next; + } + return pre; + } + } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" index 302023f..2d10a78 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" @@ -3,8 +3,9 @@ import org.junit.jupiter.api.Assertions; /** + * 141. 环形链表 + * * @author Zhang Peng - * @see 141. 环形链表 * @since 2020-06-09 */ public class 环形链表 { @@ -24,13 +25,14 @@ public static void main(String[] args) { } public static boolean hasCycle(ListNode head) { - ListNode fast = head.next, slow = head; + if (head == null || head.next == null) return false; + ListNode slow = head, fast = head.next; while (fast != null && fast.next != null) { - fast = fast.next.next; - slow = slow.next; - if (fast == slow) { + if (slow == fast) { return true; } + slow = slow.next; + fast = fast.next.next; } return false; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" index 89ce85a..ed79e53 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" @@ -3,6 +3,8 @@ import org.junit.jupiter.api.Assertions; /** + * 142. 环形链表 II + * * @author Zhang Peng * @since 2020-07-08 */ @@ -13,13 +15,13 @@ public static void main(String[] args) { // Assertions.assertEquals(null, detectCycle(head)); ListNode head2 = ListUtil.buildCycleList(1, new int[] { 3, 2, 0, -4 }); - Assertions.assertEquals(2, detectCycle(head2).val); + Assertions.assertEquals(2, detectCycle2(head2).val); ListNode head3 = ListUtil.buildCycleList(0, new int[] { 1, 2 }); - Assertions.assertEquals(1, detectCycle(head3).val); + Assertions.assertEquals(1, detectCycle2(head3).val); ListNode head4 = ListUtil.buildCycleList(1, new int[] { 1 }); - Assertions.assertEquals(null, detectCycle(head4)); + Assertions.assertEquals(null, detectCycle2(head4)); } public static ListNode detectCycle(ListNode head) { @@ -43,5 +45,24 @@ public static ListNode detectCycle(ListNode head) { } return fast; } + public static ListNode detectCycle2(ListNode head) { + ListNode slow = head, fast = head; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + if (slow == fast) { + break; + } + } + if (fast == null || fast.next == null) { + return null; + } + slow = head; + while (slow != fast) { + slow = slow.next; + fast = fast.next; + } + return slow; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" index f1f7987..ebd64e2 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" @@ -1,45 +1,49 @@ package io.github.dunwu.algorithm.list; +import org.junit.jupiter.api.Assertions; + /** + * 相交链表 + * * @author Zhang Peng - * @see 相交链表 * @since 2020-06-09 */ public class 相交链表 { - /** - * 时间复杂度:O(m * n) - */ - public static ListNode getIntersectionNode(final ListNode headA, final ListNode headB) { - ListNode a = headA; - while (a != null) { - ListNode b = headB; - while (b != null) { - if (a == b) { - return a; - } - b = b.next; - } - a = a.next; + public static void main(String[] args) { + ListNode listA = ListUtil.buildList(4, 1, 8, 4, 5); + ListNode listB = ListUtil.buildList(5, 6, 1, 8, 4, 5); + buildMetPot(listA, listB, 2, 3); + ListNode result = getIntersectionNode(listA, listB); + Assertions.assertEquals(8, result.val); + + ListNode listA2 = ListUtil.buildList(1, 9, 1, 2, 4); + ListNode listB2 = ListUtil.buildList(3, 2, 4); + buildMetPot(listA2, listB2, 3, 1); + ListNode result2 = getIntersectionNode(listA2, listB2); + Assertions.assertEquals(2, result2.val); + } + + public static void buildMetPot(ListNode listA, ListNode listB, int skipA, int skipB) { + ListNode pA = listA; + for (int i = 0; i < skipA; i++) { + pA = pA.next; + } + ListNode pB = listB; + for (int i = 0; i < skipB - 1; i++) { + pB = pB.next; } - return null; + pB.next = pA; } - public static ListNode getIntersectionNode2(final ListNode headA, final ListNode headB) { - ListNode a = headA, b = headB; - while (a != b) { - if (a == null) { - a = headB; - } else { - a = a.next; - } - if (b == null) { - b = headA; - } else { - b = b.next; - } + public static ListNode getIntersectionNode(ListNode headA, ListNode headB) { + if (headA == null || headB == null) return null; + ListNode pA = headA, pB = headB; + while (pA != pB) { + pA = pA == null ? headB : pA.next; + pB = pB == null ? headA : pB.next; } - return a; + return pA; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" index 3256313..fcd5f98 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" @@ -3,6 +3,9 @@ import org.junit.jupiter.api.Assertions; /** + * 面试题 02. 返回倒数第 k 个节点 + * LCR 140. 训练计划 II + * * @author Zhang Peng * @since 2020-06-09 */ @@ -18,10 +21,6 @@ public static void main(String[] args) { Assertions.assertEquals(1, val2); } - /** - * @see 面试题 02.02. 返回倒数第 k - * 个节点 - */ public static int kthToLast(ListNode head, int k) { ListNode fast = head; // fast 指针先走 k 步 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" index 9602f79..47b9b1e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" @@ -5,59 +5,32 @@ import java.util.List; /** + * 876. 链表的中间结点 + * * @author Zhang Peng * @since 2020-06-09 */ public class 链表的中间结点 { public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 2, 3, 4, 5, 6); + ListNode head = ListUtil.buildList(1, 2, 3, 4, 5); System.out.println(ListUtil.toList(head)); ListNode result = middleNode(head); List list = ListUtil.toList(result); System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 4, 5, 6 }, list.toArray(new Integer[0])); - - head = ListUtil.buildList(1, 2, 3, 4, 5); - - System.out.println(ListUtil.toList(head)); - result = middleNode(head); - list = ListUtil.toList(result); - System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 3, 4, 5 }, list.toArray(new Integer[0])); + + ListNode head2 = ListUtil.buildList(1, 2, 3, 4, 5, 6); + System.out.println(ListUtil.toList(head2)); + ListNode result2 = middleNode(head2); + List list2 = ListUtil.toList(result2); + System.out.println(list2); + Assertions.assertArrayEquals(new Integer[] { 4, 5, 6 }, list2.toArray(new Integer[0])); } - /** - * 链表的中间结点 算法实现 - *

- * 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。 - *

- * 如果有两个中间结点,则返回第二个中间结点。 - *

- * 示例 1: - *

-     * 输入:[1,2,3,4,5]
-     * 输出:此列表中的结点 3 (序列化形式:[3,4,5])
-     * 返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
-     * 注意,我们返回了一个 ListNode 类型的对象 ans,这样:
-     * ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
-     * 
- *

- * 示例 2: - *

-     * 输入:[1,2,3,4,5,6]
-     * 输出:此列表中的结点 4 (序列化形式:[4,5,6])
-     * 由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。
-     * 
- *

- * 提示:给定链表的结点数介于 1 和 100 之间。 - * - * @see 链表的中间结点 - */ public static ListNode middleNode(ListNode head) { // 利用快慢指针,慢指针每次偏移一个节点,快指针每次偏移两个节点 - ListNode slow = head; - ListNode fast = head; + ListNode slow = head, fast = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" index 614a7f5..b2b4702 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" @@ -1,19 +1,83 @@ package io.github.dunwu.algorithm.string; +import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Assertions; +import java.util.HashMap; + /** + * 76. 最小覆盖子串 + * * @author Zhang Peng * @date 2025-01-10 */ +@Slf4j public class 最小覆盖子串 { public static void main(String[] args) { Assertions.assertEquals("BANC", minWindow("ADOBECODEBANC", "ABC")); + Assertions.assertEquals("a", minWindow("a", "a")); + Assertions.assertEquals("", minWindow("a", "aa")); } public static String minWindow(String s, String t) { - return null; + // 用合适的数据结构记录窗口中的数据,根据具体场景变通 + // 比如说,我想记录窗口中元素出现的次数,就用 map + // 如果我想记录窗口中的元素和,就可以只用一个 int + + // 记录 window 中的字符出现次数 + HashMap window = new HashMap<>(); + // 记录所需的字符出现次数 + HashMap need = new HashMap<>(); + for (int i = 0; i < t.length(); i++) { + char c = t.charAt(i); + need.put(c, need.getOrDefault(c, 0) + 1); + } + + int valid = 0; + int left = 0, right = 0; + // 记录最小覆盖子串的起始索引及长度 + int start = 0, len = Integer.MAX_VALUE; + while (right < s.length()) { + // c 是将移入窗口的字符 + char c = s.charAt(right); + // 增大窗口 + right++; + // 进行窗口内数据的一系列更新 + if (need.containsKey(c)) { + window.put(c, window.getOrDefault(c, 0) + 1); + if (window.get(c).equals(need.get(c))) { + valid++; + } + } + + // *** debug 输出的位置 *** + // 注意在最终的解法代码中不要 print + // 因为 IO 操作很耗时,可能导致超时 + log.info("window: [{}, {})", left, right); + + // 判断左侧窗口是否要收缩 + while (left < right && valid == need.size()) { + // 在这里更新最小覆盖子串 + if (right - left < len) { + start = left; + len = right - left; + } + + // d 是将移出窗口的字符 + char d = s.charAt(left); + // 缩小窗口 + left++; + // 进行窗口内数据的一系列更新 + if (need.containsKey(d)) { + if (window.get(d).equals(need.get(d))) { + valid--; + } + window.put(d, window.getOrDefault(d, 0) - 1); + } + } + } + return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len); } } From e114f1913a73196a0a800355ea2ffa3f4fb87c5e Mon Sep 17 00:00:00 2001 From: dunwu Date: Wed, 6 Aug 2025 23:18:12 +0800 Subject: [PATCH 04/21] =?UTF-8?q?feat:=20=E5=88=B7=20leetcode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 111 ++++++++------- ...\346\225\260\344\271\213\345\222\214.java" | 12 +- ...46\225\260\344\271\213\345\222\214II.java" | 46 +++---- ...\345\272\217\346\225\260\347\273\204.java" | 34 +++++ ...\345\210\206\346\237\245\346\211\276.java" | 34 +++++ ...\351\207\215\345\244\215\351\241\271.java" | 9 +- ...51\207\215\345\244\215\351\241\271II.java" | 43 ++++++ ...\345\255\227\347\254\246\344\270\262.java" | 2 +- ...\345\272\217\346\225\260\347\273\204.java" | 49 +++++++ ...\345\205\245\344\275\215\347\275\256.java" | 2 +- ...\345\210\206\346\237\245\346\211\276.java" | 40 ------ ...\350\275\254\345\233\276\345\203\217.java" | 55 ++++++++ ...\347\233\226\345\255\220\344\270\262.java" | 2 +- ...\346\226\207\345\255\220\344\270\262.java" | 2 +- ...\347\232\204\345\205\203\347\264\240.java" | 44 ++---- ...\345\257\271\346\225\260\345\255\227.java" | 73 ++++------ ...\344\270\252\345\225\206\345\223\201.java" | 21 ++- ...\347\247\273\345\212\250\351\233\266.java" | 86 +++++------- ...\351\231\244\345\205\203\347\264\240.java" | 50 +------ ...\350\211\262\345\210\206\347\261\273.java" | 82 +++++++++++ ...\345\233\236\346\226\207\344\270\262.java" | 39 ++++++ ...\350\275\254\351\223\276\350\241\250.java" | 127 ++++++++++++++++++ ...\346\225\260\347\233\270\345\212\240.java" | 52 ++++--- ...46\225\260\347\233\270\345\212\240II.java" | 54 ++++++-- ...\351\232\224\351\223\276\350\241\250.java" | 24 ++-- ...45\244\215\345\205\203\347\264\240II.java" | 88 ++++++------ ...\350\241\250\347\244\272\344\276\213.java" | 4 +- ...50\275\254\351\223\276\350\241\250II.java" | 48 ++++--- ...\345\272\217\351\223\276\350\241\250.java" | 45 +++---- ...\345\272\217\351\223\276\350\241\250.java" | 13 +- ...\346\226\207\351\223\276\350\241\250.java" | 52 +++---- ...\345\275\242\351\223\276\350\241\250.java" | 11 +- ...45\275\242\351\223\276\350\241\250II.java" | 36 ++--- ...\344\272\244\351\223\276\350\241\250.java" | 7 +- 34 files changed, 879 insertions(+), 518 deletions(-) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\345\210\206\346\237\245\346\211\276.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271II.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\225\260\347\273\204\344\272\214\345\210\206\346\237\245\346\211\276.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\345\233\276\345\203\217.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" (98%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" (96%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\242\234\350\211\262\345\210\206\347\261\273.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" (62%) diff --git a/README.md b/README.md index 365fc6e..c43ccdc 100644 --- a/README.md +++ b/README.md @@ -58,54 +58,75 @@ ## 💻 刷题 -### 数组 +### 链表 -- [三数之和](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/三数之和.java) -- [两数之和](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/两数之和.java) -- [二维数组](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/二维数组.java) -- [删除排序数组中的重复项](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/删除排序数组中的重复项.java) -- [加一](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/加一.java) -- [在排序数组中查找元素的第一个和最后一个位置](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/在排序数组中查找元素的第一个和最后一个位置.java) -- [在排序数组中查找数字 I](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/在排序数组中查找数字I.java) -- [存在重复元素](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/存在重复元素.java) -- [对角线遍历](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/对角线遍历.java) -- [寻找数组的中心索引](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/寻找数组的中心索引.java) -- [将数组分成和相等的三个部分](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/将数组分成和相等的三个部分.java) -- [数组二分查找](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/数组二分查找.java) -- [数组拆分 1](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/数组拆分1.java) -- [旋转数组](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/旋转数组.java) -- [旋转矩阵](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/旋转矩阵.java) -- [最大连续 1 的个数](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/最大连续1的个数.java) -- [杨辉三角](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/杨辉三角.java) -- [杨辉三角 2](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/杨辉三角2.java) -- [模拟 ArrayList1](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/模拟ArrayList1.java) -- [模拟 ArrayList2](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/模拟ArrayList2.java) -- [移动零](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/移动零.java) -- [移除元素](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/移除元素.java) -- [至少是其他数字两倍的最大数](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/至少是其他数字两倍的最大数.java) -- [螺旋矩阵](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/螺旋矩阵.java) -- [长度最小的子数组](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/长度最小的子数组.java) -- [零矩阵](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/零矩阵.java) +#### 双指针技巧秒杀七道链表题目 -### 链表 +| 题目 | 掌握度 | +| ------------------------------------------------------------------------------------------------------------------ | ------ | +| [141. 环形链表](https://leetcode.cn/problems/linked-list-cycle/) | 已掌握 | +| [142. 环形链表 II](https://leetcode.cn/problems/linked-list-cycle-ii/) | 已掌握 | +| [160. 相交链表](https://leetcode.cn/problems/intersection-of-two-linked-lists/) | 已掌握 | +| [19. 删除链表的倒数第 N 个结点](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/) | 已掌握 | +| [21. 合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/) | 已掌握 | +| [23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/) | 未掌握 | +| [86. 分隔链表](https://leetcode.cn/problems/partition-list/) | 已掌握 | +| [876. 链表的中间结点](https://leetcode.cn/problems/middle-of-the-linked-list/) | 已掌握 | +| [剑指 Offer 22. 链表中倒数第 k 个节点](https://leetcode.cn/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/) | 已掌握 | + +#### 【练习】链表双指针经典习题 + +| 题目 | 掌握度 | +| ------------------------------------------------------------------------------------------------------ | ------ | +| [82. 删除排序链表中的重复元素 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/) | 已掌握 | +| [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | 未掌握 | +| [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | 未掌握 | +| [2. 两数相加](https://leetcode.cn/problems/add-two-numbers/) | 已掌握 | +| [445. 两数相加 II](https://leetcode.cn/problems/add-two-numbers-ii/) | 已掌握 | + +#### 如何判断回文链表 + +#### 单链表的花式反转方法汇总 + +| 题目 | 掌握度 | +| ------------------------------------------------------------ | ------ | +| [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/) | 未掌握 | +| [92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/) | 不熟练 | +| [25. K 个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group/) | 不熟练 | + +### 数组 -- [两数相加](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/两数相加.java) -- [二进制链表转整数](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/二进制链表转整数.java) -- [删除排序链表中的重复元素](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/删除排序链表中的重复元素.java) -- [单链表示例](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/单链表示例.java) -- [双链表示例](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/双链表示例.java) -- [反转链表](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/反转链表.java) -- [合并 K 个排序链表](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/合并K个排序链表.java) -- [合并 K 个排序链表解法 2](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/合并K个排序链表解法2.java) -- [合并两个有序链表](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/合并两个有序链表.java) -- [回文链表](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/回文链表.java) -- [排序链表](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/排序链表.java) -- [环形链表](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/环形链表.java) -- [相交链表](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/相交链表.java) -- [移除重复节点](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/移除重复节点.java) -- [移除链表元素](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/移除链表元素.java) -- [返回倒数第 k 个节点](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/返回倒数第k个节点.java) -- [链表的中间结点](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/链表的中间结点.java) +#### 双指针技巧秒杀七道数组题目 + +| 题目 | 掌握度 | +| ------------------------------------------------------------ | ------ | +| [26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/) | 已掌握 | +| [27. 移除元素](https://leetcode.cn/problems/remove-element/) | 已掌握 | +| [283. 移动零](https://leetcode.cn/problems/move-zeroes/) | 已掌握 | +| [704. 二分查找](https://leetcode.cn/problems/binary-search/) | 已掌握 | +| [1. 两数之和](https://leetcode.cn/problems/two-sum/) | 已掌握 | +| [167. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/) | 已掌握 | +| [LCR 179. 查找总价格为目标值的两个商品](https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/) | 已掌握 | +| [LCR 006. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/kLl5u1/) | 已掌握 | +| [344. 反转字符串](https://leetcode.cn/problems/reverse-string/) | 已掌握 | +| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 未掌握 | + +#### 二维数组的花式遍历技巧 + +| 题目 | 掌握度 | +| ------------------------------------------------------------ | ------ | +| [48. 旋转图像](https://leetcode.cn/problems/rotate-image/) | 未掌握 | +| [54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/) | 未掌握 | +| [59. 螺旋矩阵 II](https://leetcode.cn/problems/spiral-matrix-ii/) | 未掌握 | + +#### 【练习】数组双指针经典习题 + +| 题目 | 掌握度 | +| ------------------------------------------------------------ | ------ | +| [80. 删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/) | 已掌握 | +| [125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/) | 已掌握 | +| [75. 颜色分类](https://leetcode.cn/problems/sort-colors/) | 已掌握 | +| [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/) | | ### 栈 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214.java" index efad0ce..e20ac30 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214.java" @@ -6,7 +6,7 @@ import java.util.Map; /** - * 题目:1. 两数之和 + * 1. 两数之和 * * @author Zhang Peng * @since 2020-06-05 @@ -34,7 +34,7 @@ public static int[] twoSumInSorted(int[] nums, int target) { } } } - return new int[] { -1, -1 }; + return new int[] {}; } /** @@ -43,14 +43,14 @@ public static int[] twoSumInSorted(int[] nums, int target) { public static int[] twoSumInSorted2(int[] nums, int target) { Map map = new HashMap<>(nums.length); for (int i = 0; i < nums.length; i++) { - int expectNum = target - nums[i]; - if (map.containsKey(expectNum)) { - return new int[] { map.get(expectNum), i }; + int diff = target - nums[i]; + if (map.containsKey(diff)) { + return new int[] { map.get(diff), i }; } else { map.put(nums[i], i); } } - return new int[] { -1, -1 }; + return new int[] {}; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II.java" index 5c09531..4a1b96f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II.java" @@ -6,7 +6,7 @@ import java.util.Map; /** - * 题目:167. 两数之和 II - 输入有序数组 + * 167. 两数之和 II - 输入有序数组 * * @author Zhang Peng * @since 2020-06-05 @@ -28,17 +28,21 @@ public static void main(String[] args) { } /** - * 时间复杂度:O(n^2) + * 时间复杂度:O(logn) */ public static int[] twoSum(int[] numbers, int target) { - for (int i = 0; i < numbers.length; i++) { - for (int j = i + 1; j < numbers.length; j++) { - if (numbers[i] + numbers[j] == target) { - return new int[] { i + 1, j + 1 }; - } + int left = 0, right = numbers.length - 1; + while (left < right) { + int sum = numbers[left] + numbers[right]; + if (sum == target) { + return new int[] { left + 1, right + 1 }; + } else if (sum < target) { + left++; + } else { + right--; } } - return new int[] { -1, -1 }; + return new int[] {}; } /** @@ -48,32 +52,28 @@ public static int[] twoSum2(int[] numbers, int target) { int len = numbers.length; Map map = new HashMap<>(len); for (int i = 0; i < len; i++) { - int num = numbers[i]; - int diff = target - num; + int diff = target - numbers[i]; if (map.containsKey(diff)) { return new int[] { map.get(diff) + 1, i + 1 }; + } else { + map.put(numbers[i], i); } - map.put(num, i); } - return new int[] { -1, -1 }; + return new int[] {}; } /** - * 时间复杂度:O(logn) + * 时间复杂度:O(n^2) */ public static int[] twoSum3(int[] numbers, int target) { - int left = 0, right = numbers.length - 1; - while (left < right) { - int sum = numbers[left] + numbers[right]; - if (sum == target) { - return new int[] { left + 1, right + 1 }; - } else if (sum < target) { - left++; - } else { - right--; + for (int left = 0; left < numbers.length; left++) { + for (int right = left + 1; right < numbers.length; right++) { + if (numbers[left] + numbers[right] == target) { + return new int[] { left + 1, right + 1 }; + } } } - return new int[] { -1, -1 }; + return new int[] {}; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204.java" new file mode 100644 index 0000000..bdc6751 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204.java" @@ -0,0 +1,34 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * LCR 006. 两数之和 II - 输入有序数组 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 两数之和II_输入有序数组 { + + public static void main(String[] args) { + Assertions.assertArrayEquals(new int[] { 1, 3 }, twoSum(new int[] { 1, 2, 4, 6, 10 }, 8)); + Assertions.assertArrayEquals(new int[] { 0, 2 }, twoSum(new int[] { 2, 3, 4 }, 6)); + Assertions.assertArrayEquals(new int[] { 0, 1 }, twoSum(new int[] { -1, 0 }, -1)); + } + + public static int[] twoSum(int[] numbers, int target) { + int left = 0, right = numbers.length - 1; + while (left < right) { + int sum = numbers[left] + numbers[right]; + if (sum == target) { + return new int[] { left, right }; + } else if (sum < target) { + left++; + } else { + right--; + } + } + return new int[0]; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\345\210\206\346\237\245\346\211\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\345\210\206\346\237\245\346\211\276.java" new file mode 100644 index 0000000..867a875 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\345\210\206\346\237\245\346\211\276.java" @@ -0,0 +1,34 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * 704. 二分查找 + * + * @author Zhang Peng + * @since 2020-06-05 + */ +public class 二分查找 { + + public static void main(String[] args) { + Assertions.assertEquals(4, search(new int[] { -1, 0, 3, 5, 9, 12 }, 9)); + Assertions.assertEquals(-1, search(new int[] { -1, 0, 3, 5, 9, 12 }, 2)); + } + + public static int search(int[] nums, int target) { + if (nums == null || nums.length == 0) return -1; + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = (left + right) / 2; + if (nums[mid] == target) { + return mid; + } else if (nums[mid] < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return -1; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" index 03a7e1f..7c504b5 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Assertions; /** - * 26. 删除有序数组中的重复项 + * 26. 删除有序数组中的重复项 * * @author Zhang Peng * @since 2018-11-05 @@ -25,10 +25,9 @@ public static void main(String[] args) { } public static int removeDuplicates(int[] nums) { - if (nums.length == 0) { - return 0; - } - int slow = 0, fast = 0; + if (nums == null || nums.length == 0) return 0; + if (nums.length == 1) return 1; + int slow = 0, fast = 1; while (fast < nums.length) { if (nums[slow] != nums[fast]) { slow++; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271II.java" new file mode 100644 index 0000000..964ee51 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271II.java" @@ -0,0 +1,43 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * 26. 删除有序数组中的重复项 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 删除排序数组中的重复项II { + + public static void main(String[] args) { + int[] nums1 = { 1, 1, 1, 2, 2, 3 }; + Assertions.assertEquals(5, removeDuplicates(nums1)); + + int[] nums2 = { 0, 0, 1, 1, 1, 1, 2, 3, 3 }; + Assertions.assertEquals(7, removeDuplicates(nums2)); + } + + public static int removeDuplicates(int[] nums) { + if (nums == null || nums.length == 0) return 0; + if (nums.length == 1) return 1; + int slow = 0, fast = 1; + int count = 0; + while (fast < nums.length) { + if (nums[slow] != nums[fast]) { + slow++; + nums[slow] = nums[fast]; + count = 0; + } else { + if (count == 0) { + slow++; + nums[slow] = nums[fast]; + count++; + } + } + fast++; + } + return slow + 1; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" index 7004912..33114c6 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Assertions; /** - * 题目:344. 反转字符串 + * 344. 反转字符串 * * @author Zhang Peng * @since 2020-06-05 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" new file mode 100644 index 0000000..0e6c6ad --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" @@ -0,0 +1,49 @@ +package io.github.dunwu.algorithm.array; + +import cn.hutool.core.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +import java.lang.reflect.InvocationTargetException; +import java.util.PriorityQueue; + +/** + * 88. 合并两个有序数组 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 合并两个有序数组 { + + public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { + int[] nums1 = new int[] { 1, 2, 3, 0, 0, 0 }; + int[] nums2 = new int[] { 2, 5, 6 }; + merge(nums1, 3, nums2, 3); + Assertions.assertTrue(ArrayUtil.equals(new int[] { 1, 2, 2, 3, 5, 6 }, nums1)); + + int[] nums3 = new int[] { 1 }; + int[] nums4 = new int[] {}; + merge(nums3, 1, nums4, 0); + Assertions.assertTrue(ArrayUtil.equals(new int[] { 1 }, nums3)); + + int[] nums5 = new int[] { 0 }; + int[] nums6 = new int[] { 1 }; + merge(nums5, 0, nums6, 1); + Assertions.assertTrue(ArrayUtil.equals(new int[] { 1 }, nums5)); + } + + public static void merge(int[] nums1, int m, int[] nums2, int n) { + PriorityQueue pq = new PriorityQueue<>((a, b) -> a - b); + for (int i = 0; i < m; i++) { + pq.offer(nums1[i]); + } + for (int i = 0; i < n; i++) { + pq.offer(nums2[i]); + } + + int pos = 0; + while (!pq.isEmpty() && pos < (m + n)) { + nums1[pos++] = pq.poll(); + } + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" index 8a0a55e..193d6f5 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" @@ -35,7 +35,7 @@ // nums 为无重复元素的升序排列数组 // -104 <= target <= 104 // -// 来源:力扣(LeetCode) +// 来源:LeetCode(LeetCode) // 链接:https://leetcode-cn.com/problems/search-insert-position package io.github.dunwu.algorithm.array; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\225\260\347\273\204\344\272\214\345\210\206\346\237\245\346\211\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\225\260\347\273\204\344\272\214\345\210\206\346\237\245\346\211\276.java" deleted file mode 100644 index fb81cc9..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\225\260\347\273\204\344\272\214\345\210\206\346\237\245\346\211\276.java" +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 数组二分查找 { - - public static void main(String[] args) { - Assertions.assertEquals(5, binarySearch(new int[] { 5, 7, 7, 8, 8, 10 }, 10)); - Assertions.assertEquals(0, binarySearch(new int[] { 5, 7, 7, 8, 8, 10 }, 5)); - Assertions.assertEquals(2, binarySearch(new int[] { 5, 7, 7, 8, 8, 10 }, 7)); - } - - /** - * 数组二分查找,要求传入的数组是有序排列 - *

- * 参考:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/solution/er-fen-cha-zhao-suan-fa-xi-jie-xiang-jie-by-labula/ - */ - public static int binarySearch(int[] nums, int target) { - if (nums == null || nums.length == 0) { return -1; } - - int left = 0, right = nums.length - 1; - while (left <= right) { - int mid = left + (right - left) / 2; // 防止 mid 溢出 - if (nums[mid] == target) { - return mid; - } else if (nums[mid] < target) { - left = mid + 1; - } else if (nums[mid] > target) { - right = mid - 1; - } - } - - return -1; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\345\233\276\345\203\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\345\233\276\345\203\217.java" new file mode 100644 index 0000000..e8dce72 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\345\233\276\345\203\217.java" @@ -0,0 +1,55 @@ +package io.github.dunwu.algorithm.array; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.json.JSONUtil; +import org.junit.jupiter.api.Assertions; + +/** + * LCR 006. 两数之和 II - 输入有序数组 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 旋转图像 { + + public static void main(String[] args) { + int[][] matrix = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + rotate(matrix); + int[][] expect = { { 7, 4, 1 }, { 8, 5, 2 }, { 9, 6, 3 } }; + System.out.println("matrix: " + JSONUtil.toJsonStr(matrix)); + Assertions.assertTrue(ArrayUtil.equals(expect, matrix)); + + int[][] matrix2 = { { 5, 1, 9, 11 }, { 2, 4, 8, 10 }, { 13, 3, 6, 7 }, { 15, 14, 12, 16 } }; + rotate(matrix2); + int[][] expect2 = { { 15, 13, 2, 5 }, { 14, 3, 4, 1 }, { 12, 6, 8, 9 }, { 16, 7, 10, 11 } }; + System.out.println("matrix: " + JSONUtil.toJsonStr(matrix2)); + Assertions.assertTrue(ArrayUtil.equals(expect2, matrix2)); + } + + public static void rotate(int[][] matrix) { + int n = matrix.length; + for (int i = 0; i < n; i++) { + for (int j = i; j < n; j++) { + int temp = matrix[i][j]; + matrix[i][j] = matrix[j][i]; + matrix[j][i] = temp; + } + } + + for (int i = 0; i < n; i++) { + reverse(matrix[i]); + } + } + + public static void reverse(int[] arr) { + int left = 0, right = arr.length - 1; + while (left < right) { + int temp = arr[left]; + arr[left] = arr[right]; + arr[right] = temp; + left++; + right--; + } + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" similarity index 98% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" index b2b4702..d6109b5 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.string; +package io.github.dunwu.algorithm.array; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" index afcb0a9..fe13f2b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.string; +package io.github.dunwu.algorithm.array; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" index ef0e1ac..05de84d 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" @@ -2,7 +2,12 @@ import org.junit.jupiter.api.Assertions; +import java.util.Optional; +import java.util.PriorityQueue; + /** + * 378. 有序矩阵中第 K 小的元素 + * * @author Zhang Peng * @date 2025-01-21 */ @@ -24,40 +29,17 @@ public static void main(String[] args) { } public static int kthSmallest(int[][] matrix, int n) { - int row = matrix.length; - if (row == 1) { - return matrix[0][n - 1]; - } - int i = 1; - int[] arr = matrix[0]; - while (i < row) { - arr = merge(matrix[i], arr); - i++; - } - return arr[n - 1]; - } - - public static int[] merge(int[] arr1, int[] arr2) { - int i = 0, j = 0, k = 0; - int[] merge = new int[arr1.length + arr2.length]; - while (i < arr1.length && j < arr2.length) { - if (arr1[i] <= arr2[j]) { - merge[k++] = arr1[i++]; - } else { - merge[k++] = arr2[j++]; - } - } - if (i < arr1.length) { - while (i < arr1.length) { - merge[k++] = arr1[i++]; + PriorityQueue queue = new PriorityQueue<>((a, b) -> a - b); + for (int[] row : matrix) { + for (int val : row) { + queue.offer(val); } } - if (j < arr2.length) { - while (j < arr2.length) { - merge[k++] = arr2[j++]; - } + Integer num = null; + for (int i = 0; i < n; i++) { + num = queue.poll(); } - return merge; + return Optional.ofNullable(num).orElse(0); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" index e7a6a02..8581d0a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.PriorityQueue; import java.util.TreeMap; /** @@ -20,66 +21,42 @@ public static void main(String[] args) { expectList1.add(Arrays.asList(1, 2)); expectList1.add(Arrays.asList(1, 4)); expectList1.add(Arrays.asList(1, 6)); - List> list1 = kSmallestPairs2(new int[] { 1, 7, 11 }, new int[] { 2, 4, 6 }, 3); + List> list1 = kSmallestPairs(new int[] { 1, 7, 11 }, new int[] { 2, 4, 6 }, 3); System.out.println(JSONUtil.toJsonStr(list1)); - List> list2 = kSmallestPairs2(new int[] { 1, 1, 2 }, new int[] { 1, 2, 3 }, 2); + List> list2 = kSmallestPairs(new int[] { 1, 1, 2 }, new int[] { 1, 2, 3 }, 2); System.out.println(JSONUtil.toJsonStr(list2)); } public static List> kSmallestPairs(int[] nums1, int[] nums2, int k) { - List> list = new ArrayList<>(); - list.add(Arrays.asList(0, 0)); - TreeMap map = new TreeMap<>(); - int i = 0, j = 0; - while (i < nums1.length && j < nums2.length) { - if (i == nums1.length - 1 && j != nums2.length - 1) { - i = 0; - j++; - } else if (i != nums1.length - 1 && j == nums2.length - 1) { - j = 0; - i++; - } - if (i == nums1.length - 1 && j == nums2.length - 1) { - break; - } + // 存储三元组 (num1[i], nums2[i], i) + // i 记录 nums2 元素的索引位置,用于生成下一个节点 + PriorityQueue pq = new PriorityQueue<>((a, b) -> { + // 按照数对的元素和升序排序 + return (a[0] + a[1]) - (b[0] + b[1]); + }); + for (int i = 0; i < nums1.length; i++) { + pq.offer(new int[] { nums1[i], nums2[0], 0 }); + } - if (nums1[i] + nums2[j + 1] <= nums1[i + 1] + nums2[j]) { - list.add(Arrays.asList(i, j + 1)); - j++; - } else { - list.add(Arrays.asList(i + 1, j)); - i++; + List> list = new ArrayList<>(); + // 执行合并多个有序链表的逻辑 + while (!pq.isEmpty() && k > 0) { + int[] cur = pq.poll(); + k--; + // 链表中的下一个节点加入优先级队列 + int next = cur[2] + 1; + if (next < nums2.length) { + pq.add(new int[] { cur[0], nums2[next], next }); } - if (i + 1 >= nums1.length && j + 1 >= nums2.length) { } + List pair = new ArrayList<>(); + pair.add(cur[0]); + pair.add(cur[1]); + list.add(pair); } return list; } - public static List> kSmallestPairs2(int[] nums1, int[] nums2, int k) { - int i = 0, j = 0; - List> result = new ArrayList<>(); - result.add(Arrays.asList(nums1[i], nums2[j])); - while (i < nums1.length - 1 && j < nums2.length - 1) { - if (nums1[i] + nums2[j + 1] <= nums1[i + 1] + nums2[j]) { - j++; - } else { - i++; - } - result.add(Arrays.asList(nums1[i], nums2[j])); - if (i == nums1.length - 1 && j != nums2.length - 1) { - i = 0; - j++; - } - if (i != nums1.length - 1 && j == nums2.length - 1) { - j = 0; - i++; - } - } - System.out.println(JSONUtil.toJsonStr(result)); - return null; - } - } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" index 1e98ab3..9386473 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" @@ -2,6 +2,9 @@ import org.junit.jupiter.api.Assertions; +import java.util.HashMap; +import java.util.Map; + /** * LCR 179. 查找总价格为目标值的两个商品 * @@ -13,12 +16,28 @@ public class 查找总价格为目标值的两个商品 { public static void main(String[] args) { Assertions.assertArrayEquals(new int[] { 3, 15 }, twoSum(new int[] { 3, 9, 12, 15 }, 18)); Assertions.assertArrayEquals(new int[] { 27, 34 }, twoSum(new int[] { 8, 21, 27, 34, 52, 66 }, 61)); + + Assertions.assertArrayEquals(new int[] { 3, 15 }, twoSum2(new int[] { 3, 9, 12, 15 }, 18)); + Assertions.assertArrayEquals(new int[] { 27, 34 }, twoSum2(new int[] { 8, 21, 27, 34, 52, 66 }, 61)); } /** * 时间复杂度:O(N) */ public static int[] twoSum(int[] price, int target) { + Map map = new HashMap<>(price.length); + for (int i = 0; i < price.length; i++) { + int diff = target - price[i]; + if (map.containsKey(diff)) { + return new int[] { diff, price[i] }; + } else { + map.put(price[i], i); + } + } + return new int[0]; + } + + public static int[] twoSum2(int[] price, int target) { int left = 0, right = price.length - 1; while (left < right) { int sum = price[left] + price[right]; @@ -30,7 +49,7 @@ public static int[] twoSum(int[] price, int target) { right--; } } - return new int[] { -1, -1 }; + return new int[0]; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\345\212\250\351\233\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\345\212\250\351\233\266.java" index 4528b3f..ceb6050 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\345\212\250\351\233\266.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\345\212\250\351\233\266.java" @@ -1,88 +1,64 @@ package io.github.dunwu.algorithm.array; -// 【移动零】 - -// -// 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 -// -// 示例: -// -// 输入: [0,1,0,3,12] -// 输出: [1,3,12,0,0] -// 说明: -// -// 必须在原数组上操作,不能拷贝额外的数组。 -// 尽量减少操作次数。 - import org.junit.jupiter.api.Assertions; /** - * @author Zhang Peng + * 283. 移动零 + * + * @author Zhang Peng * @since 2018-11-05 */ public class 移动零 { public static void main(String[] args) { int[] nums1 = { 0, 1, 0, 3, 12 }; - moveZeroes2(nums1); + moveZeroes(nums1); Assertions.assertArrayEquals(new int[] { 1, 3, 12, 0, 0 }, nums1); int[] nums2 = { 0, 0, 1 }; - moveZeroes2(nums2); + moveZeroes(nums2); Assertions.assertArrayEquals(new int[] { 1, 0, 0 }, nums2); int[] nums3 = { 0 }; - moveZeroes2(nums3); + moveZeroes(nums3); Assertions.assertArrayEquals(new int[] { 0 }, nums3); } - /** - * 时间复杂度:O(N^2) - */ public static void moveZeroes(int[] nums) { - int left = 0, right = nums.length - 1; - while (left < right) { - if (nums[left] == 0) { - move(nums, left); - left = 0; - right--; - } else { - left++; - } - } - } - - private static void move(int[] nums, int pos) { - for (int i = pos; i < nums.length - 1; i++) { - int temp = nums[i]; - nums[i] = nums[i + 1]; - nums[i + 1] = temp; + int pos = 移除元素.removeElement(nums, 0); + while (pos < nums.length) { + nums[pos] = 0; + pos++; } } /** - * 时间复杂度:O(N) + * 时间复杂度:O(N^2) */ public static void moveZeroes2(int[] nums) { - int count = removeElement(nums, 0); - while (count < nums.length) { - nums[count++] = 0; + if (nums.length <= 1) { + return; } - } - - public static int removeElement(int[] nums, int val) { - if (nums.length == 0) { - return 0; - } - int slow = 0, fast = 0; - while (fast < nums.length) { - if (nums[fast] != val) { - nums[slow] = nums[fast]; - slow++; + int slow = 0; + while (slow < nums.length) { + if (nums[slow] == 0) { + int fast = slow + 1; + while (fast < nums.length && nums[fast] == 0) { + fast++; + } + if (fast >= nums.length) { + break; + } + replacePos(nums, slow, fast); } - fast++; + slow++; } - return slow; + } + + private static void replacePos(int[] nums, int left, int right) { + int temp = nums[left]; + nums[left] = nums[right]; + nums[right] = temp; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\351\231\244\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\351\231\244\345\205\203\347\264\240.java" index 907341f..e1c519d 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\351\231\244\345\205\203\347\264\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\351\231\244\345\205\203\347\264\240.java" @@ -1,51 +1,11 @@ package io.github.dunwu.algorithm.array; -// 【移除元素】 - -// -// 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。 -// -// 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 -// -// 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 -// -// 示例 1: -// -// 给定 nums = [3,2,2,3], val = 3, -// -// 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 -// -// 你不需要考虑数组中超出新长度后面的元素。 -// 示例 2: -// -// 给定 nums = [0,1,2,2,3,0,4,2], val = 2, -// -// 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。 -// -// 注意这五个元素可为任意顺序。 -// -// 你不需要考虑数组中超出新长度后面的元素。 -// 说明: -// -// 为什么返回数值是整数,但输出的答案是数组呢? -// -// 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 -// -// 你可以想象内部操作如下: -// -// // nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝 -// int len = removeElement(nums, val); -// -// // 在函数里修改输入数组对于调用者是可见的。 -// // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 -// for (int i = 0; i < len; i++) { -// print(nums[i]); -// } - import org.junit.jupiter.api.Assertions; /** - * @author Zhang Peng + * 27. 移除元素 + * + * @author Zhang Peng * @since 2018-11-05 */ public class 移除元素 { @@ -59,9 +19,7 @@ public static void main(String[] args) { } public static int removeElement(int[] nums, int val) { - if (nums.length == 0) { - return 0; - } + if (nums == null || nums.length == 0) return 0; int slow = 0, fast = 0; while (fast < nums.length) { if (nums[fast] != val) { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\242\234\350\211\262\345\210\206\347\261\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\242\234\350\211\262\345\210\206\347\261\273.java" new file mode 100644 index 0000000..cac5676 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\242\234\350\211\262\345\210\206\347\261\273.java" @@ -0,0 +1,82 @@ +package io.github.dunwu.algorithm.array; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ReflectUtil; +import org.junit.jupiter.api.Assertions; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * 75. 颜色分类 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 颜色分类 { + + public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { + test(颜色分类.class, "sortColors2"); + test(颜色分类.class, "sortColors3"); + } + + public static void test(Class clazz, String methodName) + throws InvocationTargetException, IllegalAccessException { + + Method method = ReflectUtil.getMethodByName(clazz, methodName); + + int[] arr1 = new int[] { 2, 0, 2, 1, 1, 0 }; + method.invoke(clazz, arr1); + Assertions.assertTrue(ArrayUtil.equals(new int[] { 0, 0, 1, 1, 2, 2 }, arr1)); + + int[] arr2 = new int[] { 2, 0, 1 }; + method.invoke(clazz, arr2); + Assertions.assertTrue(ArrayUtil.equals(new int[] { 0, 1, 2 }, arr2)); + + int[] arr3 = new int[] { 1, 2 }; + method.invoke(clazz, arr3); + Assertions.assertTrue(ArrayUtil.equals(new int[] { 1, 2 }, arr3)); + } + + /** + * 先将 2 往后移,再将 1 往后移:时间复杂度 O(2N) + */ + public static void sortColors2(int[] nums) { + int len = moveToTail(nums, nums.length, 2); + int len2 = moveToTail(nums, len, 1); + } + + public static int moveToTail(int[] nums, int len, int val) { + if (nums == null || len <= 1) { + return len; + } + int slow = 0, fast = 0; + while (fast < len) { + if (nums[fast] != val) { + int temp = nums[slow]; + nums[slow] = nums[fast]; + nums[fast] = temp; + slow++; + } + fast++; + } + return slow; + } + + /** + * 冒泡排序:时间复杂度 O(N^2) + */ + public static void sortColors3(int[] nums) { + if (nums == null || nums.length <= 1) return; + for (int i = 0; i < nums.length; i++) { + for (int j = i + 1; j < nums.length; j++) { + if (nums[i] > nums[j]) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } + } + } + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" new file mode 100644 index 0000000..de13f69 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" @@ -0,0 +1,39 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * 125. 验证回文串 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 验证回文串 { + + public static void main(String[] args) { + Assertions.assertTrue(isPalindrome("A man, a plan, a canal: Panama")); + Assertions.assertFalse(isPalindrome("race a car")); + Assertions.assertTrue(isPalindrome(" ")); + Assertions.assertTrue(isPalindrome("ab_a")); + } + + public static boolean isPalindrome(String s) { + String format = s.toLowerCase(); + format = format.replaceAll("[^a-zA-Z0-9]", ""); + return doIsPalindrome(format); + } + + public static boolean doIsPalindrome(String s) { + if (s.length() == 0) { return true; } + int left = 0, right = s.length() - 1; + while (left < right) { + if (s.charAt(left) != s.charAt(right)) { + return false; + } + left++; + right--; + } + return true; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" new file mode 100644 index 0000000..671bbc2 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" @@ -0,0 +1,127 @@ +package io.github.dunwu.algorithm.list; + +import org.junit.jupiter.api.Assertions; + +import java.util.List; +import java.util.PriorityQueue; + +/** + * 23. 合并 K 个升序链表 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class K个一组翻转链表 { + + public static void main(String[] args) { + + ListNode result1 = reverseKGroup(ListUtil.buildList(1, 2, 3, 4, 5), 2); + List list = ListUtil.toList(result1); + System.out.println(list); + Assertions.assertArrayEquals(new Integer[] { 2, 1, 4, 3, 5 }, list.toArray(new Integer[0])); + + ListNode result2 = reverseKGroup(ListUtil.buildList(1, 2, 3, 4, 5), 3); + List list2 = ListUtil.toList(result2); + System.out.println(list2); + Assertions.assertArrayEquals(new Integer[] { 3, 2, 1, 4, 5 }, list2.toArray(new Integer[0])); + } + + public static ListNode reverseKGroup(ListNode head, int k) { + if (head == null) return null; + ListNode left = head, right = head; + for (int i = 0; i < k; i++) { + if (right == null) { + return head; + } + right = right.next; + } + + ListNode newHead = reverseN(left, k); + left.next = reverseKGroup(right, k); + return newHead; + } + + public static ListNode reverseN(ListNode head, int n) { + if (head == null || head.next == null) { + return head; + } + ListNode prev = null, curr = head, next = head.next; + while (n > 0) { + curr.next = prev; + prev = curr; + curr = next; + if (next != null) { + next = next.next; + } + n--; + } + // 此时的 cur 是第 n + 1 个节点,head 是反转后的尾结点 + head.next = curr; + // 此时的 pre 是反转后的头结点 + return prev; + } + + public static ListNode reverseKGroup2(ListNode head, int k) { + if (head == null || head.next == null) { + return head; + } + //定义一个假的节点。 + ListNode dummy = new ListNode(0); + //假节点的next指向head。 + // dummy->1->2->3->4->5 + dummy.next = head; + //初始化pre和end都指向dummy。pre指每次要翻转的链表的头结点的上一个节点。end指每次要翻转的链表的尾节点 + ListNode pre = dummy; + ListNode end = dummy; + + while (end.next != null) { + //循环k次,找到需要翻转的链表的结尾,这里每次循环要判断end是否等于空,因为如果为空,end.next会报空指针异常。 + //dummy->1->2->3->4->5 若k为2,循环2次,end指向2 + for (int i = 0; i < k && end != null; i++) { + end = end.next; + } + //如果end==null,即需要翻转的链表的节点数小于k,不执行翻转。 + if (end == null) { + break; + } + //先记录下end.next,方便后面链接链表 + ListNode next = end.next; + //然后断开链表 + end.next = null; + //记录下要翻转链表的头节点 + ListNode start = pre.next; + //翻转链表,pre.next指向翻转后的链表。1->2 变成2->1。 dummy->2->1 + pre.next = reverse(start); + //翻转后头节点变到最后。通过.next把断开的链表重新链接。 + start.next = next; + //将pre换成下次要翻转的链表的头结点的上一个节点。即start + pre = start; + //翻转结束,将end置为下次要翻转的链表的头结点的上一个节点。即start + end = start; + } + return dummy.next; + } + + //链表翻转 + // 例子: head: 1->2->3->4 + public static ListNode reverse(ListNode head) { + //单链表为空或只有一个节点,直接返回原单链表 + if (head == null || head.next == null) { + return head; + } + //前一个节点指针 + ListNode preNode = null; + //当前节点指针 + ListNode curNode = head; + //下一个节点指针 + ListNode nextNode = null; + while (curNode != null) { + nextNode = curNode.next;//nextNode 指向下一个节点,保存当前节点后面的链表。 + curNode.next = preNode;//将当前节点next域指向前一个节点 null<-1<-2<-3<-4 + preNode = curNode;//preNode 指针向后移动。preNode指向当前节点。 + curNode = nextNode;//curNode指针向后移动。下一个节点变成当前节点 + } + return preNode; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240.java" index c2128a4..20588d3 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240.java" @@ -30,38 +30,32 @@ public static void main(String[] args) { } public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { - - // 如果任意一个表示数的链表为空,直接返回另一个链表 - if (l1 == null) return l2; - if (l2 == null) return l1; - - // 初始化 int carry = 0; - ListNode x = l1; - ListNode y = l2; - ListNode dummy = new ListNode(-1); - ListNode p = dummy; - - // 同时遍历两个操作数链表,任意操作数链表的当前位数所对应元素不为 null 则累加 - while (x != null || y != null) { - int value = carry; - - if (x != null) { - value += x.val; - x = x.next; - } - - if (y != null) { - value += y.val; - y = y.next; - } - - carry = value / 10; - p.next = new ListNode(value % 10); + ListNode dummy = new ListNode(0); + ListNode x = l1, y = l2, p = dummy; + while (x != null && y != null) { + int sum = x.val + y.val + carry; + carry = sum / 10; + p.next = sum >= 0 ? new ListNode(sum % 10) : new ListNode(sum); p = p.next; + x = x.next; + y = y.next; } - - if (carry != 0) { + while (x != null) { + int sum = x.val + carry; + carry = sum / 10; + p.next = sum >= 0 ? new ListNode(sum % 10) : new ListNode(sum); + p = p.next; + x = x.next; + } + while (y != null) { + int sum = y.val + carry; + carry = sum / 10; + p.next = sum >= 0 ? new ListNode(sum % 10) : new ListNode(sum); + p = p.next; + y = y.next; + } + if (carry > 0) { p.next = new ListNode(carry); } return dummy.next; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" index 0df454e..35fb871 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" @@ -2,6 +2,7 @@ import org.junit.jupiter.api.Assertions; +import java.util.LinkedList; import java.util.List; /** @@ -30,22 +31,49 @@ public static void main(String[] args) { } public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { - // 将两个链表倒置,方便先从低位到高位,逐次相加 - ListNode r1 = reverse(l1); - ListNode r2 = reverse(l2); - ListNode result = 两数相加.addTwoNumbers(r1, r2); - return reverse(result); + LinkedList list1 = reverse(l1); + LinkedList list2 = reverse(l2); + LinkedList list = new LinkedList<>(); + int carry = 0; + while (!list1.isEmpty() && !list2.isEmpty()) { + int x = list1.pop(); + int y = list2.pop(); + int sum = x + y + carry; + carry = sum / 10; + list.push(sum % 10); + } + while (!list1.isEmpty()) { + int x = list1.pop(); + int sum = x + carry; + carry = sum / 10; + list.push(sum % 10); + } + while (!list2.isEmpty()) { + int y = list2.pop(); + int sum = y + carry; + carry = sum / 10; + list.push(sum % 10); + } + if (carry > 0) { + list.push(carry); + } + ListNode dummy = new ListNode(-1); + ListNode p = dummy; + while (!list.isEmpty()) { + int x = list.pop(); + p.next = new ListNode(x); + p = p.next; + } + return dummy.next; } - public static ListNode reverse(ListNode head) { - ListNode pre = null, cur = head; - while (cur != null) { - ListNode next = cur.next; - cur.next = pre; - pre = cur; - cur = next; + public static LinkedList reverse(ListNode head) { + LinkedList list = new LinkedList<>(); + while (head != null) { + list.push(head.val); + head = head.next; } - return pre; + return list; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\206\351\232\224\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\206\351\232\224\351\223\276\350\241\250.java" index d75b224..d0d19f2 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\206\351\232\224\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\206\351\232\224\351\223\276\350\241\250.java" @@ -5,8 +5,9 @@ import java.util.List; /** + * 86. 分隔链表 + * * @author Zhang Peng - * @see 86. 分隔链表 * @since 2020-07-06 */ public class 分隔链表 { @@ -29,26 +30,23 @@ public static void main(String[] args) { } public static ListNode partition(ListNode head, int x) { - ListNode dummy1 = new ListNode(-1); - ListNode dummy2 = new ListNode(-1); - ListNode d1 = dummy1; - ListNode d2 = dummy2; - ListNode p = head; + ListNode left = new ListNode(-1); + ListNode right = new ListNode(-1); + ListNode p = head, l = left, r = right; while (p != null) { if (p.val < x) { - d1.next = p; - d1 = d1.next; + l.next = p; + l = l.next; } else { - d2.next = p; - d2 = d2.next; + r.next = p; + r = r.next; } ListNode temp = p.next; p.next = null; p = temp; } - d1.next = dummy2.next; - d2.next = null; - return dummy1.next; + l.next = right.next; + return left.next; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.java" index a037bb1..918b444 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.java" @@ -5,7 +5,7 @@ import java.util.List; /** - * 83. 删除排序链表中的重复元素 + * 82. 删除排序链表中的重复元素 II * * @author Zhang Peng * @since 2020-06-09 @@ -13,19 +13,19 @@ public class 删除排序链表中的重复元素II { public static void main(String[] args) { - // ListNode head = ListUtil.buildList(1, 2, 3, 3, 4, 4, 5); - // System.out.println(ListUtil.toList(head)); - // ListNode result = deleteDuplicates2(head); - // List list = ListUtil.toList(result); - // System.out.println(list); - // Assertions.assertArrayEquals(new Integer[] { 1, 2, 5 }, list.toArray(new Integer[0])); - // - // ListNode head2 = ListUtil.buildList(1, 1, 1, 2, 3); - // System.out.println(ListUtil.toList(head2)); - // ListNode result2 = deleteDuplicates2(head2); - // List list2 = ListUtil.toList(result2); - // System.out.println(list2); - // Assertions.assertArrayEquals(new Integer[] { 2, 3 }, list2.toArray(new Integer[0])); + ListNode head = ListUtil.buildList(1, 2, 3, 3, 4, 4, 5); + System.out.println(ListUtil.toList(head)); + ListNode result = deleteDuplicates2(head); + List list = ListUtil.toList(result); + System.out.println(list); + Assertions.assertArrayEquals(new Integer[] { 1, 2, 5 }, list.toArray(new Integer[0])); + + ListNode head2 = ListUtil.buildList(1, 1, 1, 2, 3); + System.out.println(ListUtil.toList(head2)); + ListNode result2 = deleteDuplicates2(head2); + List list2 = ListUtil.toList(result2); + System.out.println(list2); + Assertions.assertArrayEquals(new Integer[] { 2, 3 }, list2.toArray(new Integer[0])); ListNode head3 = ListUtil.buildList(1, 2, 2); System.out.println(ListUtil.toList(head3)); @@ -36,42 +36,54 @@ public static void main(String[] args) { } public static ListNode deleteDuplicates(ListNode head) { - ListNode dupList = new ListNode(101); - ListNode nodupList = new ListNode(101); - - ListNode dup = dupList, nodup = nodupList; - ListNode cur = head; - while (cur != null) { - if ((cur.next != null && cur.val == cur.next.val) || cur.val == dup.val) { - dup.next = cur; - dup = dup.next; + if (head == null) { + return null; + } + boolean flag = false; + ListNode dummy = new ListNode(101); + dummy.next = head; + ListNode pre = dummy, begin = head, end = head.next; + while (end != null) { + if (begin.val == end.val) { + flag = true; + end = end.next; } else { - nodup.next = cur; - nodup = nodup.next; + if (flag) { + pre.next = end; + begin = end; + end = end.next; + flag = false; + } else { + pre = pre.next; + begin = begin.next; + end = end.next; + } } - cur = cur.next; - dup.next = null; - nodup.next = null; } - return nodupList.next; + if (flag) { pre.next = end; } + return dummy.next; } public static ListNode deleteDuplicates2(ListNode head) { + if (head == null) { + return null; + } + ListNode dupList = new ListNode(101); ListNode nodupList = new ListNode(101); - ListNode dup = dupList, nodup = nodupList; - ListNode p = head; + ListNode pDup = dupList, pNoDup = nodupList, p = head; while (p != null) { - if ((p.next != null && p.val == p.next.val) || p.val == dup.val) { - dup.next = p; - dup = dup.next; + if (p.next != null && p.next.val == p.val || p.val == pDup.val) { + pDup.next = p; + pDup = pDup.next; } else { - nodup.next = p; - nodup = nodup.next; + pNoDup.next = p; + pNoDup = pNoDup.next; } + p = p.next; - dup.next = null; - nodup.next = null; + pDup.next = null; + pNoDup.next = null; } return nodupList.next; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" index 6e656a6..3719b6c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" @@ -65,7 +65,7 @@ public void remove(ListNode node) { * 删除首个值为 value 的节点 * * @param value 数据值 - * @return {@link io.github.dunwu.algorithm.list.单链表示例.ListNode} + * @return {@link ListNode} */ public E removeFirst(E value) { ListNode prev = this.head; @@ -124,7 +124,7 @@ public void clear() { * 从头开始查找,一旦发现有数值与查找值相等的节点,直接返回此节点。如果遍历结束,表明未找到节点,返回 null。 * * @param value 数据值 - * @return {@link io.github.dunwu.algorithm.list.单链表示例.ListNode} + * @return {@link ListNode} */ public ListNode find(E value) { ListNode node = this.head.next; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" index 6923236..d861475 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" @@ -15,24 +15,31 @@ public class 反转链表II { public static void main(String[] args) { ListNode head = ListUtil.buildList(1, 2, 3, 4, 5); System.out.println(ListUtil.toList(head)); - ListNode result = reverseList(head, 2, 4); + ListNode result = reverseBetween2(head, 2, 4); List list = ListUtil.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 1, 4, 3, 2, 5 }, list.toArray(new Integer[0])); } - /** - * 借助栈来实现,时间复杂度:O(2N) - */ - public static ListNode reverseList(ListNode head, int m, int n) { - if (m == 1) { - return reverseN(head, n); + public static ListNode reverseBetween(ListNode head, int left, int right) { + if (left == 1) { + return reverseN(head, right); } - ListNode cur = head; - for (int i = 1; i < m - 1; i++) { - cur = cur.next; + // 找到第 m 个节点的前驱 + ListNode pre = head; + for (int i = 1; i < left - 1; i++) { + pre = pre.next; } - cur.next = reverseN(cur.next, n - m + 1); + // 从第 m 个节点开始反转 + pre.next = reverseN(pre.next, right - left + 1); + return head; + } + + public static ListNode reverseBetween2(ListNode head, int left, int right) { + if (left == 1) { + return reverseN(head, right); + } + head.next = reverseBetween2(head.next, left - 1, right - 1); return head; } @@ -40,17 +47,22 @@ public static ListNode reverseN(ListNode head, int n) { if (head == null || head.next == null) { return head; } - ListNode pre = null, cur = head; - while (cur != null && n > 0) { - ListNode next = cur.next; + ListNode pre, cur, nxt; + pre = null; + cur = head; + nxt = head.next; + while (n > 0) { cur.next = pre; pre = cur; - cur = next; + cur = nxt; + if (nxt != null) { + nxt = nxt.next; + } n--; } - if (head != null) { - head.next = cur; - } + // 此时的 cur 是第 n + 1 个节点,head 是反转后的尾结点 + head.next = cur; + // 此时的 pre 是反转后的头结点 return pre; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" similarity index 62% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" index af0644a..03fe20e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\346\216\222\345\272\217\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" @@ -3,27 +3,28 @@ import org.junit.jupiter.api.Assertions; import java.util.List; +import java.util.PriorityQueue; /** - * 23. 合并K个排序链表 + * 23. 合并 K 个升序链表 * * @author Zhang Peng * @since 2020-06-09 */ -public class 合并K个排序链表 { +public class 合并K个升序链表 { public static void main(String[] args) { ListNode head1 = ListUtil.buildList(1, 4, 5); ListNode head2 = ListUtil.buildList(1, 3, 4); ListNode head3 = ListUtil.buildList(2, 6); ListNode[] array = new ListNode[] { head1, head2, head3 }; - ListNode result = mergeKLists2(array); + ListNode result = mergeKLists(array); List list = ListUtil.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 1, 1, 2, 3, 4, 4, 5, 6 }, list.toArray(new Integer[0])); ListNode[] array2 = new ListNode[] {}; - ListNode result2 = mergeKLists2(array2); + ListNode result2 = mergeKLists(array2); List list2 = ListUtil.toList(result2); System.out.println(list2); Assertions.assertArrayEquals(new Integer[] {}, list2.toArray(new Integer[0])); @@ -34,32 +35,24 @@ public static ListNode mergeKLists(ListNode[] lists) { return null; } - ListNode root = new ListNode(-1); - ListNode resultHead = root; - while (true) { - Integer minIndex = null; - Integer minVal = null; - for (int i = 0; i < lists.length; i++) { - if (lists[i] == null) { - continue; - } - - if (minVal == null || lists[i].val < minVal) { - minIndex = i; - minVal = lists[i].val; - } + ListNode dummy = new ListNode(-1); + ListNode p = dummy; + PriorityQueue queue = new PriorityQueue<>(lists.length, (a, b) -> a.val - b.val); + for (ListNode head : lists) { + if (head != null) { + queue.add(head); } + } - if (minIndex != null) { - resultHead.next = new ListNode(lists[minIndex].val); - resultHead = resultHead.next; - lists[minIndex] = lists[minIndex].next; - } else { - break; + while (!queue.isEmpty()) { + ListNode node = queue.poll(); + p.next = node; + if (node.next != null) { + queue.add(node.next); } + p = p.next; } - - return root.next; + return dummy.next; } public static ListNode mergeKLists2(ListNode[] lists) { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" index 4b24ebd..652d419 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" @@ -5,8 +5,9 @@ import java.util.List; /** + * 21. 合并两个有序链表 + * * @author Zhang Peng - * @see 合并两个有序链表 * @since 2020-06-09 */ public class 合并两个有序链表 { @@ -22,19 +23,19 @@ public static void main(String[] args) { public static ListNode mergeTwoLists(ListNode l1, ListNode l2) { ListNode dummy = new ListNode(-1); - ListNode n = dummy; + ListNode p = dummy; while (l1 != null && l2 != null) { if (l1.val <= l2.val) { - n.next = l1; + p.next = l1; l1 = l1.next; } else { - n.next = l2; + p.next = l2; l2 = l2.next; } - n = n.next; + p = p.next; } - n.next = (l1 != null) ? l1 : l2; + p.next = (l1 != null) ? l1 : l2; return dummy.next; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" index 8e3e249..d2befb6 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" @@ -3,63 +3,43 @@ import org.junit.jupiter.api.Assertions; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; /** + * 234. 回文链表 + * 面试题 02.06. 回文链表 + * * @author Zhang Peng - * @see 234. 回文链表 - * @see 面试题 02.06. 回文链表 * @since 2020-06-09 */ public class 回文链表 { public static void main(String[] args) { ListNode head = ListUtil.buildList(1, 2, 2, 1); - Assertions.assertTrue(isPalindrome2(head)); + Assertions.assertTrue(isPalindrome(head)); head = ListUtil.buildList(1, 2); - Assertions.assertFalse(isPalindrome2(head)); + Assertions.assertFalse(isPalindrome(head)); } public static boolean isPalindrome(ListNode head) { - List list = new ArrayList<>(); - ListNode node = head; - while (node != null) { - list.add(node.val); - node = node.next; + LinkedList l1 = new LinkedList<>(); + LinkedList l2 = new LinkedList<>(); + while (head != null) { + l1.offerFirst(head.val); + l2.offerFirst(head.val); + head = head.next; } - // int i = 0, j = list.size() - 1; - for (int i = 0, j = list.size() - 1; i < j; i++, j--) { - if (!list.get(i).equals(list.get(j))) { + while (!l1.isEmpty() && !l2.isEmpty()) { + Integer num1 = l1.pollFirst(); + Integer num2 = l2.pollLast(); + if (num1 != num2) { return false; } } return true; } - public static boolean isPalindrome2(ListNode head) { - ListNode left = head; - ListNode right = reverse(head); - while (left != null && right != null) { - if (left.val != right.val) { - return false; - } - left = left.next; - right = right.next; - } - return true; - } - - public static ListNode reverse(ListNode head) { - ListNode pre = null, cur = head; - while (cur != null) { - ListNode next = cur.next; - cur.next = pre; - pre = cur; - cur = next; - } - return pre; - } - } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" index 2d10a78..f1a3ffa 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" @@ -25,14 +25,17 @@ public static void main(String[] args) { } public static boolean hasCycle(ListNode head) { - if (head == null || head.next == null) return false; - ListNode slow = head, fast = head.next; + // 快慢指针初始化指向 head + ListNode slow = head, fast = head; + // 快指针走到末尾时停止 while (fast != null && fast.next != null) { + // 慢指针走一步,快指针走两步 + slow = slow.next; + fast = fast.next.next; + // 快慢指针相遇,说明含有环 if (slow == fast) { return true; } - slow = slow.next; - fast = fast.next.next; } return false; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" index ed79e53..d7d7a49 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" @@ -11,41 +11,20 @@ public class 环形链表II { public static void main(String[] args) { - // ListNode head = ListUtil.buildList(3, 2, 0, -4); - // Assertions.assertEquals(null, detectCycle(head)); + ListNode head = ListUtil.buildList(3, 2, 0, -4); + Assertions.assertEquals(null, detectCycle(head)); ListNode head2 = ListUtil.buildCycleList(1, new int[] { 3, 2, 0, -4 }); - Assertions.assertEquals(2, detectCycle2(head2).val); + Assertions.assertEquals(2, detectCycle(head2).val); ListNode head3 = ListUtil.buildCycleList(0, new int[] { 1, 2 }); - Assertions.assertEquals(1, detectCycle2(head3).val); + Assertions.assertEquals(1, detectCycle(head3).val); ListNode head4 = ListUtil.buildCycleList(1, new int[] { 1 }); - Assertions.assertEquals(null, detectCycle2(head4)); + Assertions.assertEquals(null, detectCycle(head4)); } public static ListNode detectCycle(ListNode head) { - ListNode fast = head, slow = head; - while (fast != null && fast.next != null) { - fast = fast.next.next; - slow = slow.next; - if (fast == slow) { - break; - } - } - - if (fast == null || fast.next == null) { - return null; - } - - fast = head; - while (fast != slow) { - fast = fast.next; - slow = slow.next; - } - return fast; - } - public static ListNode detectCycle2(ListNode head) { ListNode slow = head, fast = head; while (fast != null && fast.next != null) { slow = slow.next; @@ -57,8 +36,9 @@ public static ListNode detectCycle2(ListNode head) { if (fast == null || fast.next == null) { return null; } - slow = head; - while (slow != fast) { + + fast = head; + while (fast != slow) { slow = slow.next; fast = fast.next; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" index ebd64e2..e93c7f9 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" @@ -22,6 +22,11 @@ public static void main(String[] args) { buildMetPot(listA2, listB2, 3, 1); ListNode result2 = getIntersectionNode(listA2, listB2); Assertions.assertEquals(2, result2.val); + + ListNode listA3 = ListUtil.buildList(2,6,4); + ListNode listB3 = ListUtil.buildList(1,5); + ListNode result3 = getIntersectionNode(listA3, listB3); + Assertions.assertNull(result3); } public static void buildMetPot(ListNode listA, ListNode listB, int skipA, int skipB) { @@ -37,7 +42,7 @@ public static void buildMetPot(ListNode listA, ListNode listB, int skipA, int sk } public static ListNode getIntersectionNode(ListNode headA, ListNode headB) { - if (headA == null || headB == null) return null; + // pA 指向 A 链表头结点,pB 指向 B 链表头结点 ListNode pA = headA, pB = headB; while (pA != pB) { pA = pA == null ? headB : pA.next; From 115e3bb2e5057f5c6f83bd8b2ebc68965c99746c Mon Sep 17 00:00:00 2001 From: dunwu Date: Thu, 14 Aug 2025 08:16:14 +0800 Subject: [PATCH 05/21] =?UTF-8?q?feat:=20=E5=88=B7=20leetcode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 235 +++++++++++------- ...\344\270\215\345\217\257\345\217\230.java" | 41 +++ ...\344\270\215\345\217\257\345\217\230.java" | 37 +++ ...\345\272\217\346\225\260\347\273\204.java" | 15 ++ ...\347\232\204\350\203\275\345\212\233.java" | 56 +++++ ...\347\232\204\346\216\222\345\210\227.java" | 53 ++++ ...\347\272\277\346\216\222\345\272\217.java" | 62 +++++ ...\345\205\261\345\211\215\347\274\200.java" | 46 ++++ ...\347\232\204\345\271\263\346\226\271.java" | 43 ++++ ...\347\232\204\347\217\202\347\217\202.java" | 50 ++++ ...\347\275\256\347\237\251\351\230\265.java" | 37 +++ .../github/dunwu/algorithm/list/ListNode.java | 4 +- ...\345\272\217\351\223\276\350\241\250.java" | 53 +++- ...\346\261\202\346\254\241\346\225\260.java" | 31 ++- ...345\244\247\345\205\203\347\264\240I.java" | 83 +++++++ ...\345\257\271\350\267\257\345\276\204.java" | 42 ++++ ...\351\242\221\347\216\207\346\240\210.java" | 55 ++++ ...\346\234\200\345\260\217\346\240\210.java" | 76 +++--- ...346\234\200\345\260\217\346\240\2102.java" | 58 ----- ...\347\232\204\346\213\254\345\217\267.java" | 53 ++-- ...\347\216\260\351\230\237\345\210\227.java" | 69 ++--- ...\345\256\236\347\216\260\346\240\210.java" | 83 +++---- ...\345\214\226\350\267\257\345\276\204.java" | 42 ++++ ...\345\274\217\346\261\202\345\200\274.java" | 50 ++++ ...\346\216\222\351\223\276\350\241\250.java" | 61 +++++ .../dunwu/algorithm/tree/TreeUtils.java | 127 ++++------ ...\345\205\245\346\223\215\344\275\234.java" | 2 +- ...\345\205\261\347\245\226\345\205\210.java" | 4 +- ...\345\260\217\350\267\235\347\246\273.java" | 2 +- ...\346\220\234\347\264\242\346\240\221.java" | 6 +- ...\350\267\257\345\276\204\345\222\214.java" | 8 +- ...\344\270\272\351\223\276\350\241\250.java" | 44 ++++ ...\345\272\217\351\201\215\345\216\206.java" | 40 ++- ...\346\254\241\351\201\215\345\216\206.java" | 2 +- ...346\254\241\351\201\215\345\216\2062.java" | 2 +- ...\345\272\217\345\210\227\345\214\226.java" | 105 +++++--- ...\346\234\211\350\267\257\345\276\204.java" | 2 +- ...\345\244\247\346\267\261\345\272\246.java" | 74 +++--- ...\345\260\217\346\267\261\345\272\246.java" | 17 +- ...\345\205\261\347\245\226\345\205\210.java" | 2 +- ...\347\232\204\347\233\264\345\276\204.java" | 50 ++++ ...\346\254\241\351\201\215\345\216\206.java" | 2 +- ...\344\272\214\345\217\211\346\240\221.java" | 74 +++--- ...\344\272\214\345\217\211\346\240\221.java" | 70 +++--- ...\344\274\274\347\232\204\346\240\221.java" | 4 +- ...\347\202\271\346\214\207\351\222\210.java" | 33 +-- ...\344\272\214\345\217\211\346\240\221.java" | 4 +- ...\344\272\214\345\217\211\346\240\221.java" | 6 +- ...\344\272\214\345\217\211\346\240\221.java" | 51 ++++ ...\344\272\214\345\217\211\346\240\221.java" | 72 ++++++ ...\345\220\214\347\232\204\346\240\221.java" | 12 +- ...\344\272\214\345\217\211\346\240\221.java" | 60 +++-- ...\345\276\204\346\200\273\345\222\214.java" | 4 +- 53 files changed, 1675 insertions(+), 639 deletions(-) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\275\254\347\275\256\347\237\251\351\230\265.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\2102.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" diff --git a/README.md b/README.md index c43ccdc..777fed7 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ | [160. 相交链表](https://leetcode.cn/problems/intersection-of-two-linked-lists/) | 已掌握 | | [19. 删除链表的倒数第 N 个结点](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/) | 已掌握 | | [21. 合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/) | 已掌握 | -| [23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/) | 未掌握 | +| [23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/) | 已掌握 | | [86. 分隔链表](https://leetcode.cn/problems/partition-list/) | 已掌握 | | [876. 链表的中间结点](https://leetcode.cn/problems/middle-of-the-linked-list/) | 已掌握 | | [剑指 Offer 22. 链表中倒数第 k 个节点](https://leetcode.cn/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/) | 已掌握 | @@ -88,111 +88,166 @@ #### 单链表的花式反转方法汇总 -| 题目 | 掌握度 | -| ------------------------------------------------------------ | ------ | -| [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/) | 未掌握 | -| [92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/) | 不熟练 | +| 题目 | 掌握度 | +| ------------------------------------------------------------------------------ | ------ | +| [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/) | 未掌握 | +| [92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/) | 不熟练 | | [25. K 个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group/) | 不熟练 | ### 数组 #### 双指针技巧秒杀七道数组题目 -| 题目 | 掌握度 | -| ------------------------------------------------------------ | ------ | -| [26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/) | 已掌握 | -| [27. 移除元素](https://leetcode.cn/problems/remove-element/) | 已掌握 | -| [283. 移动零](https://leetcode.cn/problems/move-zeroes/) | 已掌握 | -| [704. 二分查找](https://leetcode.cn/problems/binary-search/) | 已掌握 | -| [1. 两数之和](https://leetcode.cn/problems/two-sum/) | 已掌握 | -| [167. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/) | 已掌握 | +| 题目 | 掌握度 | +| ------------------------------------------------------------------------------------------------------ | ------ | +| [26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/) | 已掌握 | +| [27. 移除元素](https://leetcode.cn/problems/remove-element/) | 已掌握 | +| [283. 移动零](https://leetcode.cn/problems/move-zeroes/) | 已掌握 | +| [704. 二分查找](https://leetcode.cn/problems/binary-search/) | 已掌握 | +| [1. 两数之和](https://leetcode.cn/problems/two-sum/) | 已掌握 | +| [167. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/) | 已掌握 | | [LCR 179. 查找总价格为目标值的两个商品](https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/) | 已掌握 | -| [LCR 006. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/kLl5u1/) | 已掌握 | -| [344. 反转字符串](https://leetcode.cn/problems/reverse-string/) | 已掌握 | -| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 未掌握 | +| [LCR 006. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/kLl5u1/) | 已掌握 | +| [344. 反转字符串](https://leetcode.cn/problems/reverse-string/) | 已掌握 | +| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 未掌握 | #### 二维数组的花式遍历技巧 +| 题目 | 掌握度 | +| ----------------------------------------------------------------- | ------ | +| [48. 旋转图像](https://leetcode.cn/problems/rotate-image/) | 未掌握 | +| [54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/) | 未掌握 | +| [59. 螺旋矩阵 II](https://leetcode.cn/problems/spiral-matrix-ii/) | 未掌握 | + +#### 数组双指针经典习题 + +| 题目 | 掌握度 | +| -------------------------------------------------------------------------------------------------------------------------- | ------ | +| [80. 删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/) | 已掌握 | +| [125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/) | 已掌握 | +| [75. 颜色分类](https://leetcode.cn/problems/sort-colors/) | 已掌握 | +| [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/) | 未掌握 | +| [977. 有序数组的平方](https://labuladong.online/algo/problem-set/array-two-pointers/#slug_squares-of-a-sorted-array) | 已掌握 | +| [1329. 将矩阵按对角线排序](https://labuladong.online/algo/problem-set/array-two-pointers/#slug_sort-the-matrix-diagonally) | 未掌握 | +| [1260. 二维网格迁移](https://leetcode.cn/problems/shift-2d-grid/) | | +| [867. 转置矩阵](https://labuladong.online/algo/problem-set/array-two-pointers/#slug_transpose-matrix) | 已掌握 | +| [14. 最长公共前缀](https://leetcode.cn/problems/longest-common-prefix/) | 已掌握 | + +#### 滑动窗口算法核心代码模板 + +| 题目 | 掌握度 | +| -------------------------------------------------------------------------- | ------ | +| [76. 最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring/) | 未掌握 | +| [567. 字符串的排列](https://leetcode.cn/problems/permutation-in-string/) | | +| | | + +#### 二分搜索 + +| 题目 | 掌握度 | +| ------------------------------------------------------------------------------------------------------ | ------ | +| [875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) | 未掌握 | +| [1011. 在 D 天内送达包裹的能力](https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/) | 未掌握 | +| [410. 分割数组的最大值](https://leetcode.cn/problems/split-array-largest-sum/) | 未掌握 | + +#### 前缀和数组 + +| 题目 | 掌握度 | +| ---------------------------------------------------------------------------------------------- | ------ | +| [303. 区域和检索 - 数组不可变](https://leetcode.cn/problems/range-sum-query-immutable/) | 不熟练 | +| [304. 二维区域和检索 - 矩阵不可变](https://leetcode.cn/problems/range-sum-query-2d-immutable/) | 未掌握 | + +#### 差分数组 + +| 题目 | 掌握度 | +| ----------------------------------------------------------------------------- | ------ | +| [1094. 拼车](https://leetcode.cn/problems/car-pooling/) | | +| [1109. 航班预订统计](https://leetcode.cn/problems/corporate-flight-bookings/) | | +| [370. 区间加法](https://leetcode.cn/problems/range-addition/) | | + +### 栈和队列 + +#### 队列实现栈以及栈实现队列 + +| 题目 | 掌握度 | +| ------------------------------------------------------------------------------- | ------ | +| [225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/) | 不熟练 | +| [232. 用栈实现队列](https://leetcode.cn/problems/implement-queue-using-stacks/) | 已掌握 | + +#### 栈的经典习题 + +| 题目 | 掌握度 | +| --------------------------------------------------------------------------------------- | ------ | +| [71. 简化路径](https://leetcode.cn/problems/simplify-path/) | 不熟练 | +| [143. 重排链表](https://leetcode.cn/problems/reorder-list/) | 已掌握 | +| [20. 有效的括号](https://leetcode.cn/problems/valid-parentheses/) | 已掌握 | +| [150. 逆波兰表达式求值](https://leetcode.cn/problems/evaluate-reverse-polish-notation/) | 已掌握 | +| [388. 文件的最长绝对路径](https://leetcode.cn/problems/longest-absolute-file-path/) | 未掌握 | +| [155. 最小栈](https://leetcode.cn/problems/min-stack/) | | +| [895. 最大频率栈](https://leetcode.cn/problems/maximum-frequency-stack/) | | + +#### 队列的经典习题 + +| 题目 | 掌握度 | +| --------------------------------------------------------------------------- | ------ | +| [933. 最近的请求次数](https://leetcode.cn/problems/number-of-recent-calls/) | 不熟练 | +| [622. 设计循环队列](https://leetcode.cn/problems/design-circular-queue/) | | +| | | +| | | +| | | +| | | +| | | + +#### 单调栈算法模板 + +| 题目 | 掌握度 | +| ------------------------------------------------------------------------------- | ------ | +| [496. 下一个更大元素 I](https://leetcode.cn/problems/next-greater-element-i/) | | +| [503. 下一个更大元素 II](https://leetcode.cn/problems/next-greater-element-ii/) | | +| [739. 每日温度](https://leetcode.cn/problems/daily-temperatures/) | | +| [剑指 Offer II 038. 每日温度](https://leetcode.cn/problems/iIQa4I/) | | + +### 二叉树 + +#### 二叉树系列算法核心纲领 + | 题目 | 掌握度 | | ------------------------------------------------------------ | ------ | -| [48. 旋转图像](https://leetcode.cn/problems/rotate-image/) | 未掌握 | -| [54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/) | 未掌握 | -| [59. 螺旋矩阵 II](https://leetcode.cn/problems/spiral-matrix-ii/) | 未掌握 | +| [104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) | 已掌握 | +| [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/) | 已掌握 | +| [543. 二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree/) | | +| [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/) | | +| [116. 填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) | 未掌握 | +| [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/) | 已掌握 | +| [105. 从前序与中序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) | 不熟练 | +| [106. 从中序与后序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) | 不熟练 | +| [654. 最大二叉树](https://leetcode.cn/problems/maximum-binary-tree/) | 已掌握 | +| [889. 根据前序和后序遍历构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-postorder-traversal/) | | +| [297. 二叉树的序列化与反序列化](https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/) | 未掌握 | + +### 动态规划 -#### 【练习】数组双指针经典习题 +| 题目 | 掌握度 | +| ------------------------------------------------------------ | ------ | +| [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | | +| [509. 斐波那契数](https://leetcode.cn/problems/fibonacci-number/) | | +| | | +| | | +| | | +| | | +| | | + +### 贪心算法 | 题目 | 掌握度 | | ------------------------------------------------------------ | ------ | -| [80. 删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/) | 已掌握 | -| [125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/) | 已掌握 | -| [75. 颜色分类](https://leetcode.cn/problems/sort-colors/) | 已掌握 | -| [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/) | | - -### 栈 - -- [三合一](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/三合一.java) -- [基本计算器](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/基本计算器.java) -- [最小栈](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/最小栈.java) -- [最小栈 2](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/最小栈2.java) -- [有效的括号](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/有效的括号.java) -- [栈排序](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/栈排序.java) -- [棒球比赛](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/棒球比赛.java) -- [比较含退格的字符串](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/比较含退格的字符串.java) -- [用栈实现队列](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/用栈实现队列.java) -- [用队列实现栈](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/用队列实现栈.java) - -### 队列 - -- [动态扩容数组实现的队列](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/动态扩容数组实现的队列.java) -- [数组实现的队列](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/数组实现的队列.java) -- [最近的请求次数](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/最近的请求次数.java) -- [设计循环队列](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/设计循环队列.java) -- [链表实现的队列](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/链表实现的队列.java) - -### 字符串 - -- [二进制求和](https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/AddBinary.java) -- [实现 strStr()](https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/ImplementStrstr.java) -- [最长公共前缀](https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/LongestCommonPrefix.java) -- [反转字符串](https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/ReverseString.java) -- [反转字符串中的单词](https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/ReverseWordsInAString.java) -- [反转字符串中的单词 III](https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/ReverseWordsInAString3.java) - -### 树 - -- [N 叉树的最大深度](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/N叉树的最大深度.java) - -#### 二叉树 - -- [二叉树中的最大路径和](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树中的最大路径和.java) -- [二叉树的中序遍历](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的中序遍历.java) -- [二叉树的前序遍历](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的前序遍历.java) -- [二叉树的后序遍历](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的后序遍历.java) -- [二叉树的层次遍历](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的层次遍历.java) -- [二叉树的层次遍历 2](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的层次遍历2.java) -- [二叉树的序列化与反序列化](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的序列化与反序列化.java) -- [二叉树的所有路径](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的所有路径.java) -- [二叉树的最大深度](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的最大深度.java) -- [二叉树的最小深度](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的最小深度.java) -- [二叉树的最近公共祖先](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的最近公共祖先.java) -- [二叉树的锯齿形层次遍历](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的锯齿形层次遍历.java) -- [从先序遍历还原二叉树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/从先序遍历还原二叉树.java) -- [叶子相似的树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/叶子相似的树.java) -- [填充每个节点的下一个右侧节点指针](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/填充每个节点的下一个右侧节点指针.java) -- [填充每个节点的下一个右侧节点指针 II](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/填充每个节点的下一个右侧节点指针II.java) -- [对称二叉树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/对称二叉树.java) -- [平衡二叉树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/平衡二叉树.java) -- [相同的树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/相同的树.java) -- [翻转二叉树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/翻转二叉树.java) -- [路径总和](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/路径总和.java) - -#### 二叉搜索树 - -- [二叉搜索树中的插入操作](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/二叉搜索树中的插入操作.java) -- [二叉搜索树的最近公共祖先](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/二叉搜索树的最近公共祖先.java) -- [二叉搜索树节点最小距离](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/二叉搜索树节点最小距离.java) -- [将有序数组转换为二叉搜索树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/将有序数组转换为二叉搜索树.java) -- [验证二叉搜索树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/验证二叉搜索树.java) +| [55. 跳跃游戏](https://leetcode.cn/problems/jump-game/) | | +| [45. 跳跃游戏 II](https://leetcode.cn/problems/jump-game-ii/) | | + +### 分治算法 + +| 题目 | 掌握度 | +| --------------------------------------------------------------------------- | ------ | +| [23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/) | 已掌握 | ## 📚 资料 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" new file mode 100644 index 0000000..7c67582 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" @@ -0,0 +1,41 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * 303. 区域和检索 - 数组不可变 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 二维区域和检索_矩阵不可变 { + + public static void main(String[] args) { + NumMatrix numMatrix = new NumMatrix(new int[][] { + { 3, 0, 1, 4, 2 }, { 5, 6, 3, 2, 1 }, { 1, 2, 0, 1, 5 }, { 4, 1, 0, 1, 7 }, { 1, 0, 3, 0, 5 } + }); + Assertions.assertEquals(8, numMatrix.sumRegion(2, 1, 4, 3)); + } + + static class NumMatrix { + + private int[][] preSum; + + public NumMatrix(int[][] matrix) { + int row = matrix.length; + int col = matrix[0].length; + preSum = new int[row + 1][col + 1]; + for (int i = 1; i <= row; i++) { + for (int j = 1; j <= col; j++) { + preSum[i][j] = preSum[i - 1][j] + preSum[i][j - 1] + matrix[i - 1][j - 1] - preSum[i - 1][j - 1]; + } + } + } + + public int sumRegion(int row1, int col1, int row2, int col2) { + return preSum[row2 + 1][col2 + 1] - preSum[row1][col2 + 1] - preSum[row2 + 1][col1] + preSum[row1][col1]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" new file mode 100644 index 0000000..da25066 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" @@ -0,0 +1,37 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * 303. 区域和检索 - 数组不可变 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 区域和检索_数组不可变 { + + public static void main(String[] args) { + NumArray numArray = new NumArray(new int[] { -2, 0, 3, -5, 2, -1 }); + Assertions.assertEquals(1, numArray.sumRange(0, 2)); + Assertions.assertEquals(-1, numArray.sumRange(2, 5)); + Assertions.assertEquals(-3, numArray.sumRange(0, 5)); + } + + static class NumArray { + + private int[] preSum; + + public NumArray(int[] nums) { + preSum = new int[nums.length + 1]; + for (int i = 1; i <= nums.length; i++) { + preSum[i] = preSum[i - 1] + nums[i - 1]; + } + } + + public int sumRange(int left, int right) { + return preSum[right + 1] - preSum[left]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" index 0e6c6ad..2688a8f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" @@ -32,6 +32,21 @@ public static void main(String[] args) throws InvocationTargetException, Illegal } public static void merge(int[] nums1, int m, int[] nums2, int n) { + int i = m - 1, j = n - 1; + int p = m + n - 1; + while (i >= 0 && j >= 0) { + if (nums1[i] > nums2[j]) { + nums1[p--] = nums1[i--]; + } else { + nums1[p--] = nums2[j--]; + } + } + while (j >= 0) { + nums1[p--] = nums2[j--]; + } + } + + public static void merge2(int[] nums1, int m, int[] nums2, int n) { PriorityQueue pq = new PriorityQueue<>((a, b) -> a - b); for (int i = 0; i < m; i++) { pq.offer(nums1[i]); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" new file mode 100644 index 0000000..647c1bf --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" @@ -0,0 +1,56 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +import java.lang.reflect.InvocationTargetException; + +/** + * 1011. 在 D 天内送达包裹的能力 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 在D天内送达包裹的能力 { + + public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { + Assertions.assertEquals(15, shipWithinDays(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 5)); + Assertions.assertEquals(6, shipWithinDays(new int[] { 3, 2, 2, 4, 1, 4 }, 3)); + Assertions.assertEquals(3, shipWithinDays(new int[] { 1, 2, 3, 1, 1 }, 4)); + } + + public static int shipWithinDays(int[] weights, int days) { + int left = 0, right = 1; + while (left <= right) { + int mid = left + (right - left) / 2; + if (f(weights, mid) == days) { + // 搜索左侧边界,则需要收缩右侧边界 + right = mid; + } else if (f(weights, mid) < days) { + // 需要让 f(x) 的返回值大一些 + right = mid; + } else if (f(weights, mid) > days) { + // 需要让 f(x) 的返回值小一些 + left = mid + 1; + } + } + return left; + } + + public static long f(int[] weights, int x) { + long days = 0; + for (int i = 0; i < weights.length; ) { + int cap = x; + while (i < weights.length) { + if (cap < weights[i]) { + break; + } else { + cap -= weights[i]; + } + i++; + } + days++; + } + return days; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" new file mode 100644 index 0000000..2017474 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" @@ -0,0 +1,53 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; +import java.util.Map; + +/** + * 567. 字符串的排列 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 字符串的排列 { + + public static void main(String[] args) { + Assertions.assertTrue(checkInclusion("ab", "eidbaooo")); + Assertions.assertFalse(checkInclusion("ab", "eidboaoo")); + } + + public static boolean checkInclusion(String t, String s) { + + // 定义 window, need + Map need = new HashMap<>(); + Map window = new HashMap<>(); + for (char c : s.toCharArray()) { + need.put(c, need.getOrDefault(c, 0) + 1); + } + + int valid = 0; + int left = 0, right = 0; + while (right < s.length()) { + + // 2. right++,窗口右扩,直到满足条件 + + // 移入窗口的字符 + char c = s.charAt(right); + // 扩大窗口 + right++; + // 进行窗口内数据的一系列更新 + if (need.containsKey(c)) { + window.put(c, window.getOrDefault(c, 0) + 1); + if (window.get(c).equals(need.get(c))) { + valid++; + } + } + + + } + return false; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" new file mode 100644 index 0000000..10f2eee --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" @@ -0,0 +1,62 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 1329. 将矩阵按对角线排序 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 将矩阵按对角线排序 { + + public static void main(String[] args) { + int[][] input1 = { { 3, 3, 1, 1 }, { 2, 2, 1, 2 }, { 1, 1, 1, 2 } }; + int[][] expected1 = { { 1, 1, 1, 1 }, { 1, 2, 2, 2 }, { 1, 2, 3, 3 } }; + int[][] output1 = diagonalSort(input1); + Assertions.assertArrayEquals(expected1, output1); + + int[][] input2 = { { 11, 25, 66, 1, 69, 7 }, { 23, 55, 17, 45, 15, 52 }, { 75, 31, 36, 44, 58, 8 }, + { 22, 27, 33, 25, 68, 4 }, { 84, 28, 14, 11, 5, 50 } }; + int[][] expected2 = { { 5, 17, 4, 1, 52, 7 }, { 11, 11, 25, 45, 8, 69 }, { 14, 23, 25, 44, 58, 15 }, + { 22, 27, 31, 36, 50, 66 }, { 84, 28, 75, 33, 55, 68 } }; + int[][] output2 = diagonalSort(input2); + Assertions.assertArrayEquals(expected2, output2); + } + + public static int[][] diagonalSort(int[][] mat) { + Map> map = new HashMap<>(); + int m = mat.length; + int n = mat[0].length; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + int diff = i - j; + if (!map.containsKey(diff)) { + map.put(diff, new ArrayList<>()); + } + map.get(diff).add(mat[i][j]); + } + } + + map.forEach((diff, list) -> { + Collections.sort(list); + }); + + int[][] result = new int[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + int diff = i - j; + List list = map.get(diff); + result[i][j] = list.remove(0); + } + } + return result; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" new file mode 100644 index 0000000..e93cdaf --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" @@ -0,0 +1,46 @@ + + +import org.junit.jupiter.api.Assertions; + +/** + * 14. 最长公共前缀 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 最长公共前缀 { + + public static void main(String[] args) { + String[] input1 = { "flower", "flow", "flight" }; + String expect1 = "fl"; + String output1 = longestCommonPrefix(input1); + Assertions.assertEquals(expect1, output1); + + String[] input2 = { "dog","racecar","car" }; + String expect2 = ""; + String output2 = longestCommonPrefix(input2); + Assertions.assertEquals(expect2, output2); + } + + public static String longestCommonPrefix(String[] strs) { + if (strs == null || strs.length == 0) return ""; + int p = 0; + int len = strs.length; + while (true) { + if (strs[0].length() <= p) { + break; + } + char c = strs[0].charAt(p); + int i = 1; + while (i < len && p < strs[i].length() && strs[i].charAt(p) == c) { + i++; + } + if (i < len) { + break; + } + p++; + } + return strs[0].substring(0, p); + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" new file mode 100644 index 0000000..02f5277 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" @@ -0,0 +1,43 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * 977. 有序数组的平方 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 有序数组的平方 { + + public static void main(String[] args) { + int[] input1 = { -4, -1, 0, 3, 10 }; + int[] expect1 = { 0, 1, 9, 16, 100 }; + int[] output1 = sortedSquares(input1); + Assertions.assertArrayEquals(expect1, output1); + + int[] input2 = { -7, -3, 2, 3, 11 }; + int[] expect2 = { 4, 9, 9, 49, 121 }; + int[] output2 = sortedSquares(input2); + Assertions.assertArrayEquals(expect2, output2); + } + + public static int[] sortedSquares(int[] nums) { + int len = nums.length; + int left = 0, right = len - 1; + int p = len - 1; + int[] output = new int[len]; + while (left <= right) { + if (Math.abs(nums[left]) > Math.abs(nums[right])) { + output[p] = nums[left] * nums[left]; + left++; + } else { + output[p] = nums[right] * nums[right]; + right--; + } + p--; + } + return output; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" new file mode 100644 index 0000000..73246ee --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" @@ -0,0 +1,50 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +import java.lang.reflect.InvocationTargetException; + +/** + * 875. 爱吃香蕉的珂珂 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 爱吃香蕉的珂珂 { + + public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { + Assertions.assertEquals(4, minEatingSpeed(new int[] { 3, 6, 7, 11 }, 8)); + Assertions.assertEquals(30, minEatingSpeed(new int[] { 30, 11, 23, 4, 20 }, 5)); + Assertions.assertEquals(23, minEatingSpeed(new int[] { 30, 11, 23, 4, 20 }, 6)); + } + + public static int minEatingSpeed(int[] piles, int h) { + int left = 1, right = 1000000000 + 1; + while (left < right) { + int mid = left + (right - left) / 2; + if (f(piles, mid) == h) { + // 搜索左侧边界,则需要收缩右侧边界 + right = mid; + } else if (f(piles, mid) < h) { + // 需要让 f(x) 的返回值大一些 + right = mid; + } else if (f(piles, mid) > h) { + // 需要让 f(x) 的返回值小一些 + left = mid + 1; + } + } + return left; + } + + public static long f(int[] arr, int x) { + long hours = 0; + for (int j : arr) { + hours += j / x; + if (j % x > 0) { + hours++; + } + } + return hours; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\275\254\347\275\256\347\237\251\351\230\265.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\275\254\347\275\256\347\237\251\351\230\265.java" new file mode 100644 index 0000000..c01dc98 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\275\254\347\275\256\347\237\251\351\230\265.java" @@ -0,0 +1,37 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +/** + * 1329. 将矩阵按对角线排序 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 转置矩阵 { + + public static void main(String[] args) { + int[][] input1 = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + int[][] expect1 = { { 1, 4, 7 }, { 2, 5, 8 }, { 3, 6, 9 } }; + int[][] output1 = transpose(input1); + Assertions.assertArrayEquals(expect1, output1); + + int[][] input2 = { { 1, 4, 7 }, { 2, 5, 8 }, { 3, 6, 9 } }; + int[][] expect2 = { { 1, 4, 7 }, { 2, 5, 8 }, { 3, 6, 9 } }; + int[][] output2 = transpose(input2); + Assertions.assertArrayEquals(expect2, output2); + } + + public static int[][] transpose(int[][] matrix) { + int m = matrix.length; + int n = matrix[0].length; + int[][] result = new int[n][m]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + result[i][j] = matrix[j][i]; + } + } + return result; + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListNode.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListNode.java index fc8db7f..86ef30e 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListNode.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListNode.java @@ -4,8 +4,8 @@ public final class ListNode { - int val; - ListNode next; + public int val; + public ListNode next; ListNode(int val) { this.val = val; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" index 03fe20e..2dfe1d3 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" @@ -18,13 +18,13 @@ public static void main(String[] args) { ListNode head2 = ListUtil.buildList(1, 3, 4); ListNode head3 = ListUtil.buildList(2, 6); ListNode[] array = new ListNode[] { head1, head2, head3 }; - ListNode result = mergeKLists(array); + ListNode result = mergeKLists3(array); List list = ListUtil.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 1, 1, 2, 3, 4, 4, 5, 6 }, list.toArray(new Integer[0])); ListNode[] array2 = new ListNode[] {}; - ListNode result2 = mergeKLists(array2); + ListNode result2 = mergeKLists3(array2); List list2 = ListUtil.toList(result2); System.out.println(list2); Assertions.assertArrayEquals(new Integer[] {}, list2.toArray(new Integer[0])); @@ -55,15 +55,58 @@ public static ListNode mergeKLists(ListNode[] lists) { return dummy.next; } + /** + * 效率不高 + */ public static ListNode mergeKLists2(ListNode[] lists) { if (lists == null || lists.length == 0) { return null; } - ListNode result = lists[0]; + // 把 k 个有序链表都合并到 lists[0] 上 + ListNode resList = lists[0]; for (int i = 1; i < lists.length; i++) { - result = 合并两个有序链表.mergeTwoLists(result, lists[i]); + resList = merge2List(resList, lists[i]); } - return result; + return resList; + } + + public static ListNode merge2List(ListNode l1, ListNode l2) { + ListNode dummy = new ListNode(-1); + ListNode p = dummy, p1 = l1, p2 = l2; + while (p1 != null && p2 != null) { + if (p1.val <= p2.val) { + p.next = p1; + p1 = p1.next; + } else { + p.next = p2; + p2 = p2.next; + } + p = p.next; + } + if (p1 != null) { + p.next = p1; + } + if (p2 != null) { + p.next = p2; + } + return dummy.next; + } + + public static ListNode mergeKLists3(ListNode[] lists) { + if (lists == null || lists.length == 0) { + return null; + } + return mergeKLists3(lists, 0, lists.length - 1); + } + + public static ListNode mergeKLists3(ListNode[] lists, int start, int end) { + if (start == end) { + return lists[start]; + } + int mid = (start + end) / 2; + ListNode left = mergeKLists3(lists, start, mid); + ListNode right = mergeKLists3(lists, mid + 1, end); + return merge2List(left, right); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" index ee1d7e7..dc69777 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" @@ -4,22 +4,35 @@ import java.util.Queue; /** + * 933. 最近的请求次数 + * * @author Zhang Peng - * @see 933. 最近的请求次数 * @since 2020-06-10 */ public class 最近的请求次数 { - Queue queue; - - public 最近的请求次数() { - queue = new LinkedList<>(); + public static void main(String[] args) { + RecentCounter recentCounter = new RecentCounter(); + recentCounter.ping(1); + recentCounter.ping(100); } - public int ping(int t) { - queue.add(t); - while (queue.peek() < t - 3000) { queue.poll(); } - return queue.size(); + static class RecentCounter { + + Queue q = new LinkedList<>(); + + public RecentCounter() { + + } + + public int ping(int t) { + q.offer(t); + while (q.peek() < t - 3000) { + q.poll(); + } + return q.size(); + } + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" new file mode 100644 index 0000000..d95976b --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" @@ -0,0 +1,83 @@ +package io.github.dunwu.algorithm.stack; + +import org.junit.jupiter.api.Assertions; + +import java.util.Deque; +import java.util.LinkedList; +import java.util.Stack; + +/** + * 496. 下一个更大元素 I + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 下一个更大元素I { + + public static void main(String[] args) { + int[] output1 = nextGreaterElement(new int[] { 4, 1, 2 }, new int[] { 1, 3, 4, 2 }); + int[] expect1 = new int[] { -1, 3, -1 }; + Assertions.assertArrayEquals(expect1, output1); + + int[] output2 = nextGreaterElement(new int[] { 2, 4 }, new int[] { 1, 2, 3, 4 }); + int[] expect2 = new int[] { 3, -1 }; + Assertions.assertArrayEquals(expect2, output2); + } + + public static int[] nextGreaterElement(int[] nums1, int[] nums2) { + int[] result = new int[nums1.length]; + for (int i = 0; i < nums1.length; i++) { + int val = nums1[i]; + int pos = Integer.MAX_VALUE; + result[i] = -1; + for (int j = 0; j < nums2.length; j++) { + if (val == nums2[j]) { + pos = j; + continue; + } + if (pos < j && val < nums2[j]) { + result[i] = nums2[j]; + break; + } + } + } + return result; + } + + public static int[] nextGreaterElement2(int[] nums1, int[] nums2) { + int[] result = new int[nums1.length]; + for (int i = 0; i < nums1.length; i++) { + int val = nums1[i]; + int pos = Integer.MAX_VALUE; + result[i] = -1; + for (int j = 0; j < nums2.length; j++) { + if (val == nums2[j]) { + pos = j; + continue; + } + if (pos < j && val < nums2[j]) { + result[i] = nums2[j]; + break; + } + } + } + return result; + } + + // 计算 nums 中每个元素的下一个更大元素 + public static int[] nextGreaterElement(int[] nums) { + int n = nums.length; + int[] res = new int[n]; + Stack s = new Stack<>(); + for (int i = n - 1; i >= 0; i--) { + while (!s.isEmpty() && s.peek() > nums[i]) { + s.pop(); + } + // nums[i] 身后的下一个更大元素 + res[i] = s.isEmpty() ? -1 : s.peek(); + s.push(nums[i]); + } + return res; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" new file mode 100644 index 0000000..b7377df --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" @@ -0,0 +1,42 @@ +package io.github.dunwu.algorithm.stack; + +import org.junit.jupiter.api.Assertions; + +import java.util.Deque; +import java.util.LinkedList; + +/** + * 150. 逆波兰表达式求值 + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 文件的最长绝对路径 { + + public static void main(String[] args) { + Assertions.assertEquals(20, lengthLongestPath("dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext")); + } + + public static int lengthLongestPath(String input) { + // 这个栈存储之前的父路径。实际上这里只用存父路径的长度就够了,这个优化留给你吧 + Deque stack = new LinkedList<>(); + int maxLen = 0; + for (String part : input.split("\n")) { + int level = part.lastIndexOf("\t") + 1; + // 让栈中只保留当前目录的父路径 + while (level < stack.size()) { + stack.removeLast(); + } + stack.addLast(part.substring(level)); + // 如果是文件,就计算路径长度 + if (part.contains(".")) { + int sum = stack.stream().mapToInt(String::length).sum(); + // 加上父路径的分隔符 + sum += stack.size() - 1; + maxLen = Math.max(maxLen, sum); + } + } + return maxLen; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" new file mode 100644 index 0000000..cc7c33d --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" @@ -0,0 +1,55 @@ +package io.github.dunwu.algorithm.stack; + +import io.github.dunwu.algorithm.list.ListNode; +import io.github.dunwu.algorithm.list.ListUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.List; +import java.util.Stack; + +/** + * 143. 重排链表 + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 最大频率栈 { + + public static void main(String[] args) { + ListNode input = ListUtil.buildList(1, 2, 3, 4); + reorderList(input); + List list = ListUtil.toList(input); + System.out.println(list); + Assertions.assertArrayEquals(new Integer[] { 1, 4, 2, 3 }, list.toArray()); + } + + public static void reorderList(ListNode head) { + + if (head == null || head.next == null) { + return; + } + + ListNode p = head; + int total = 0; + Stack stack = new Stack<>(); + while (p != null) { + stack.push(p); + total++; + p = p.next; + } + + p = head; + int cnt = 0; + while (p != null && cnt < total) { + if (cnt % 2 == 0) { + ListNode node = stack.pop(); + node.next = p.next; + p.next = node; + } + p = p.next; + cnt++; + } + p.next = null; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" index 9a4f5ac..0edb40f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" @@ -1,6 +1,10 @@ package io.github.dunwu.algorithm.stack; +import org.junit.jupiter.api.Assertions; + import java.util.LinkedList; +import java.util.Queue; +import java.util.Stack; /** * @see 面试题 03.02. 栈的最小值 @@ -8,56 +12,52 @@ public class 最小栈 { public static void main(String[] args) { - 最小栈 stack = new 最小栈(); - stack.push(9); - stack.push(2); - stack.push(5); - stack.push(6); - stack.push(3); - stack.push(1); - System.out.println("min = " + stack.getMin()); - System.out.println("pop " + stack.pop()); - System.out.println("pop " + stack.pop()); - System.out.println("pop " + stack.pop()); + MinStack minStack = new MinStack(); + minStack.push(-2); + minStack.push(0); + minStack.push(-3); + Assertions.assertEquals(-3, minStack.getMin()); + minStack.pop(); + Assertions.assertEquals(0, minStack.top()); + Assertions.assertEquals(-2, minStack.getMin()); } - private final LinkedList stack; - private final LinkedList minStack; + static class MinStack { - public 最小栈() { - stack = new LinkedList<>(); - minStack = new LinkedList<>(); - } + Stack stack = new Stack<>(); + Stack minStack = new Stack<>(); + + public MinStack() { + + } - public void push(int x) { - if (!minStack.isEmpty()) { - Integer first = minStack.getFirst(); - if (x < first) { - minStack.push(x); + public void push(int val) { + stack.push(val); + if (minStack.isEmpty()) { + minStack.push(val); + } else { + Integer lastMin = minStack.peek(); + if (val <= lastMin) { + minStack.push(val); + } else { + minStack.push(lastMin); + } } - stack.push(x); } - } - public int pop() { - int top = stack.pop(); - int val = minStack.peek() ; - if (val == val) { + public int pop() { minStack.pop(); + return stack.pop(); } - return val; - } - public int top() { - return stack.getFirst(); - } + public int top() { + return stack.peek(); + } - public int getMin() { - if (minStack.isEmpty()) { - return -1; - } else { - return minStack.getFirst(); + public int getMin() { + return minStack.peek(); } + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\2102.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\2102.java" deleted file mode 100644 index f96f802..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\2102.java" +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import java.util.LinkedList; - -/** - * @author Zhang Peng - * @since 2020-01-18 - */ -public class 最小栈2 { - - // 数据栈 - private LinkedList data; - - // 辅助栈 - private LinkedList helper; - - /** - * initialize your data structure here. - */ - public 最小栈2() { - data = new LinkedList<>(); - helper = new LinkedList<>(); - } - - // 思路 1:数据栈和辅助栈在任何时候都同步 - public void push(int x) { - // 数据栈和辅助栈一定会增加元素 - data.push(x); - if (helper.isEmpty() || helper.peek() >= x) { - helper.push(x); - } else { - helper.push(helper.peek()); - } - } - - public void pop() { - // 两个栈都得 pop - if (!data.isEmpty()) { - helper.pop(); - data.pop(); - } - } - - public int top() { - if (!data.isEmpty()) { - return data.peek(); - } - throw new RuntimeException("栈中元素为空,此操作非法"); - } - - public int getMin() { - if (!helper.isEmpty()) { - return helper.peek(); - } - throw new RuntimeException("栈中元素为空,此操作非法"); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" index b4fb51a..142efac 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" @@ -2,8 +2,11 @@ import org.junit.jupiter.api.Assertions; +import java.util.Stack; + /** - * @see 20. 有效的括号 + * 20. 有效的括号 + * * @author Zhang Peng * @since 2020-06-09 */ @@ -14,40 +17,38 @@ public static void main(String[] args) { Assertions.assertTrue(isValid("{[]}")); Assertions.assertFalse(isValid("([)]")); Assertions.assertFalse(isValid("([)")); + Assertions.assertFalse(isValid("((")); + Assertions.assertTrue(isValid("(())")); } public static boolean isValid(String s) { - if (s == null) { - return true; - } - - int length = s.length(); - if (length == 0) return true; - if (length % 2 != 0) return false; - - GenericStack stack = new GenericStack<>(); + if (s == null || s.length() <= 1) { return false; } + Stack left = new Stack<>(); for (char c : s.toCharArray()) { - Character top = stack.peek(); - if (top == null) { - stack.push(c); - continue; - } - - if (top == '(' && c == ')') { - stack.pop(); - } else if (top == '[' && c == ']') { - stack.pop(); - } else if (top == '{' && c == '}') { - stack.pop(); + if (c == '(' || c == '{' || c == '[') { + // 字符 c 是左括号,入栈 + left.push(c); } else { - stack.push(c); + // 字符 c 是右括号 + if (!left.isEmpty() && left.peek() == leftChar(c)) { + left.pop(); + } else { + // 和最近的左括号不匹配 + return false; + } } } + // 是否还有左括号未匹配 + return left.isEmpty(); + } - if (stack.getSize() == 0) { - return true; + public static char leftChar(char c) { + if (c == ')') { + return '('; + } else if (c == '}') { + return '{'; } - return false; + return '['; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" index c340e5b..2c674a5 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" @@ -1,55 +1,56 @@ package io.github.dunwu.algorithm.stack; +import org.junit.jupiter.api.Assertions; + import java.util.LinkedList; /** - * @see 232. 用栈实现队列 + * 232. 用栈实现队列 + * + * @author Zhang Peng + * @since 2020-01-18 */ public class 用栈实现队列 { public static void main(String[] args) { - 用栈实现队列 queue = new 用栈实现队列(); - queue.push(1); - queue.push(2); - System.out.println(queue.peek()); // 返回 1 - System.out.println(queue.pop()); // 返回 1 - System.out.println(queue.empty()); // 返回 false + MyStack queue = new MyStack(); + int max = 10; + for (int i = 1; i <= max; i++) { + queue.push(i); + } + for (int i = 1; i <= max; i++) { + Assertions.assertEquals(i, queue.peek()); + Assertions.assertEquals(i, queue.pop()); + } } - private LinkedList stack1; - private LinkedList stack2; + static class MyStack { - /** Initialize your data structure here. */ - public 用栈实现队列() { - stack1 = new LinkedList<>(); - stack2 = new LinkedList<>(); - } + private LinkedList s1 = new LinkedList<>(); + private LinkedList s2 = new LinkedList<>(); - /** Push element x to the back of queue. */ - public void push(int x) { - stack1.push(x); - } + public void push(int x) { + s1.push(x); + } - /** Removes the element from in front of queue and returns that element. */ - public int pop() { - peek(); - return stack2.pop(); - } + public int pop() { + peek(); + return s2.pop(); + } - /** Get the front element. */ - public int peek() { - if (stack2.size() > 0) { - return stack2.peek(); + public int peek() { + if (s2.isEmpty()) { + while (!s1.isEmpty()) { + s2.push(s1.pop()); + } + } + return s2.peek(); } - while (!stack1.isEmpty()) { - stack2.push(stack1.pop()); + + public boolean empty() { + return s1.isEmpty() && s2.isEmpty(); } - return stack2.peek(); - } - /** Returns whether the queue is empty. */ - public boolean empty() { - return stack1.isEmpty() && stack2.isEmpty(); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" index c350aec..d6c3ab8 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" @@ -1,63 +1,62 @@ package io.github.dunwu.algorithm.stack; +import org.junit.jupiter.api.Assertions; + import java.util.LinkedList; import java.util.Queue; /** - * 基于队列实现的栈 + * 225. 用队列实现栈 * * @author Zhang Peng - * @see 225. 用队列实现栈 * @since 2020-01-18 */ -public class 用队列实现栈 { +public class 用队列实现栈 { public static void main(String[] args) { - 用队列实现栈 stack = new 用队列实现栈<>(); - stack.push(1); - stack.push(2); - System.out.println(stack.pop()); - System.out.println(stack.pop()); + int max = 10; + MyStack stack = new MyStack(); + for (int i = 1; i <= max; i++) { + stack.push(i); + } + for (int i = 1; i <= max; i++) { + Assertions.assertEquals(max - i + 1, stack.top()); + Assertions.assertEquals(max - i + 1, stack.pop()); + } } - private Queue q1 = new LinkedList<>(); - - /** - * Initialize your data structure here. - */ - public 用队列实现栈() { } - - /** - * Push element x onto stack. - */ - public void push(T x) { - q1.add(x); - int sz = q1.size(); - while (sz > 1) { - q1.add(q1.remove()); - sz--; + static class MyStack { + + int top = -1; + Queue queue = new LinkedList<>(); + + public MyStack() { } + + public void push(int x) { + top = x; + queue.offer(x); } - } - /** - * Removes the element on top of the stack and returns that element. - */ - public T pop() { - return q1.poll(); - } + public int pop() { + int size = queue.size(); + while (size > 2) { + queue.offer(queue.poll()); + size--; + } + // 倒数第 2 个值作为 top + top = queue.poll(); + queue.offer(top); + return queue.poll(); + } - /** - * Get the top element. - */ - public T top() { - return q1.peek(); - } + public int top() { + return top; + } + + public boolean empty() { + return queue.isEmpty(); + } - /** - * Returns whether the stack is empty. - */ - public boolean empty() { - return q1.isEmpty(); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" new file mode 100644 index 0000000..c4f6b36 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" @@ -0,0 +1,42 @@ +package io.github.dunwu.algorithm.stack; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 71. 简化路径 + * + * @author Zhang Peng + * @since 2025-08-08 + */ +public class 简化路径 { + + public static void main(String[] args) { + Assertions.assertEquals("/home", simplifyPath("/home/")); + Assertions.assertEquals("/home/foo", simplifyPath("/home//foo/")); + Assertions.assertEquals("/home/user/Pictures", simplifyPath("/home/user/Documents/../Pictures")); + Assertions.assertEquals("/", simplifyPath("/../")); + } + + public static String simplifyPath(String path) { + String[] parts = path.split("/"); + Stack stack = new Stack<>(); + for (String part : parts) { + if (part.isEmpty() || part.equals(".")) continue; + if (part.equals("..")) { + if (!stack.isEmpty()) { + stack.pop(); + } + } else { + stack.push(part); + } + } + String res = ""; + while (!stack.isEmpty()) { + res = "/" + stack.pop() + res; + } + return res.isEmpty() ? "/" : res; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" new file mode 100644 index 0000000..252871f --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" @@ -0,0 +1,50 @@ +package io.github.dunwu.algorithm.stack; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 150. 逆波兰表达式求值 + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 逆波兰表达式求值 { + + public static void main(String[] args) { + Assertions.assertEquals(9, evalRPN(new String[] { "2", "1", "+", "3", "*" })); + Assertions.assertEquals(6, evalRPN(new String[] { "4", "13", "5", "/", "+" })); + Assertions.assertEquals(22, + evalRPN(new String[] { "10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+" })); + } + + public static int evalRPN(String[] tokens) { + if (tokens == null || tokens.length == 0) return 0; + Stack stack = new Stack<>(); + for (String token : tokens) { + if ("+-*/".contains(token)) { + Integer op2 = stack.pop(); + Integer op1 = stack.pop(); + switch (token) { + case "+": + stack.push(op1 + op2); + break; + case "-": + stack.push(op1 - op2); + break; + case "*": + stack.push(op1 * op2); + break; + default: + stack.push(op1 / op2); + break; + } + } else { + stack.push(Integer.parseInt(token)); + } + } + return stack.pop(); + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" new file mode 100644 index 0000000..361f95e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" @@ -0,0 +1,61 @@ +package io.github.dunwu.algorithm.stack; + +import io.github.dunwu.algorithm.list.ListNode; +import io.github.dunwu.algorithm.list.ListUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.List; +import java.util.Stack; + +/** + * 143. 重排链表 + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 重排链表 { + + public static void main(String[] args) { + ListNode input = ListUtil.buildList(1, 2, 3, 4); + reorderList(input); + List list = ListUtil.toList(input); + System.out.println(list); + Assertions.assertArrayEquals(new Integer[] { 1, 4, 2, 3 }, list.toArray()); + + ListNode input2 = ListUtil.buildList(1, 2, 3, 4, 5); + reorderList(input2); + List list2 = ListUtil.toList(input2); + System.out.println(list2); + Assertions.assertArrayEquals(new Integer[] { 1, 5, 2, 4, 3 }, list2.toArray()); + } + + public static void reorderList(ListNode head) { + + if (head == null || head.next == null) { + return; + } + + ListNode p = head; + int total = 0; + Stack stack = new Stack<>(); + while (p != null) { + stack.push(p); + total++; + p = p.next; + } + + p = head; + int cnt = 0; + while (p != null && cnt < total) { + if (cnt % 2 == 0) { + ListNode node = stack.pop(); + node.next = p.next; + p.next = node; + } + p = p.next; + cnt++; + } + p.next = null; + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeUtils.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeUtils.java index 2395dbf..a3c623d 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeUtils.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeUtils.java @@ -8,10 +8,13 @@ */ public class TreeUtils { - public static TreeNode buildTree(Integer[] array) { + static final String SEP = ","; + static final String NULL = "null"; + + public static TreeNode buildTree(Integer... arr) { List list = new ArrayList<>(); - for (Integer value : array) { + for (Integer value : arr) { // 创建结点,每一个结点的左结点和右结点为null TreeNode node; if (value == null) { @@ -26,7 +29,7 @@ public static TreeNode buildTree(Integer[] array) { // 构建二叉树 if (list.size() > 0) { // i表示的是根节点的索引,从0开始 - for (int i = 0; i < array.length / 2 - 1; i++) { + for (int i = 0; i < arr.length / 2 - 1; i++) { if (list.get(2 * i + 1) != null) { // 左结点 list.get(i).left = list.get(2 * i + 1); @@ -37,13 +40,15 @@ public static TreeNode buildTree(Integer[] array) { } } // 判断最后一个根结点:因为最后一个根结点可能没有右结点,所以单独拿出来处理 - int lastIndex = array.length / 2 - 1; - - // 左结点 - list.get(lastIndex).left = list.get(lastIndex * 2 + 1); - // 右结点,如果数组的长度为奇数才有右结点 - if (array.length % 2 == 1) { - list.get(lastIndex).right = list.get(lastIndex * 2 + 2); + int lastIndex = arr.length / 2 - 1; + + if (list.get(lastIndex) != null) { + // 左结点 + list.get(lastIndex).left = list.get(lastIndex * 2 + 1); + // 右结点,如果数组的长度为奇数才有右结点 + if (arr.length % 2 == 1) { + list.get(lastIndex).right = list.get(lastIndex * 2 + 2); + } } return list.get(0); @@ -52,12 +57,8 @@ public static TreeNode buildTree(Integer[] array) { } } - public static TreeNode asTree(Integer... array) { - return buildTree(array); - } - public static TreeNode find(TreeNode root, int val) { - if (root == null || root.val == val) { return root;} + if (root == null || root.val == val) { return root; } TreeNode left = find(root.left, val); if (left != null) return left; return find(root.right, val); @@ -130,83 +131,55 @@ public static List toBfsValueList(TreeNode root) { return list.subList(0, last + 1); } - public static String rserialize(TreeNode root, String str) { - if (root == null) { - str += "null,"; - } else { - str += str.valueOf(root.val) + ","; - str = rserialize(root.left, str); - str = rserialize(root.right, str); - } - return str; - } - public static String serialize(TreeNode root) { - String text = rserialize(root, ""); - while (text.endsWith("null,")) { - int index = text.lastIndexOf("null,"); - text = text.substring(0, index); + StringBuilder sb = new StringBuilder(); + serializePreOrder(root, sb); + int size = sb.length(); + int pos = sb.lastIndexOf(SEP); + if (pos == size - 1) { + sb.deleteCharAt(pos); } - if (text.endsWith(",")) { - text = text.substring(0, text.length() - 1); - } - return text; + return sb.toString(); } - public static TreeNode rdeserialize(List list) { - List nodes = new ArrayList<>(); - - for (String value : list) { - // 创建结点,每一个结点的左结点和右结点为null - TreeNode node; - if (value == null || value.equalsIgnoreCase("null")) { - node = null; - } else { - node = new TreeNode(Integer.parseInt(value), null, null); - } - // list中存着每一个结点 - nodes.add(node); + static void serializePreOrder(TreeNode root, StringBuilder sb) { + if (root == null) { + sb.append(NULL).append(SEP); + return; } - // 构建二叉树 - if (nodes.size() > 0) { - // i表示的是根节点的索引,从0开始 - for (int i = 0; i < list.size() / 2 - 1; i++) { - if (nodes.get(2 * i + 1) != null) { - // 左结点 - nodes.get(i).left = nodes.get(2 * i + 1); - } - if (nodes.get(2 * i + 2) != null) { - // 右结点 - nodes.get(i).right = nodes.get(2 * i + 2); - } - } - // 判断最后一个根结点:因为最后一个根结点可能没有右结点,所以单独拿出来处理 - int lastIndex = list.size() / 2 - 1; + // 前序处理 + sb.append(root.val).append(SEP); - // 左结点 - nodes.get(lastIndex).left = nodes.get(lastIndex * 2 + 1); - // 右结点,如果数组的长度为奇数才有右结点 - if (list.size() % 2 == 1) { - nodes.get(lastIndex).right = nodes.get(lastIndex * 2 + 2); - } + serializePreOrder(root.left, sb); + serializePreOrder(root.right, sb); + } - return nodes.get(0); - } else { - return null; + public static TreeNode deserialize(String data) { + // 将字符串转化成列表 + LinkedList nodes = new LinkedList<>(); + for (String s : data.split(SEP)) { + nodes.addLast(s); } + return deserializePreOrder(nodes); } - public static TreeNode deserialize(String data) { - data = data.substring(1, data.length() - 1); - String[] nums = data.split(","); - List list = new LinkedList<>(Arrays.asList(nums)); - return rdeserialize(list); + static TreeNode deserializePreOrder(LinkedList nodes) { + if (nodes.isEmpty()) return null; + + String first = nodes.removeFirst(); + if (first.equals(NULL)) return null; + TreeNode root = new TreeNode(Integer.parseInt(first)); + + root.left = deserializePreOrder(nodes); + root.right = deserializePreOrder(nodes); + + return root; } public static void main(String[] args) { Integer[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - TreeNode head = TreeUtils.asTree(array); + TreeNode head = TreeUtils.buildTree(array); toBfsList(head); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" index 528305b..0e7ce8e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" @@ -13,7 +13,7 @@ public class 二叉搜索树中的插入操作 { public static void main(String[] args) { - TreeNode tree = TreeUtils.asTree(4, 2, 7, 1, 3); + TreeNode tree = TreeUtils.buildTree(4, 2, 7, 1, 3); insertIntoBST(tree, 5); List treeNodes = TreeUtils.toBfsList(tree); System.out.println(treeNodes); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" index 95f3b32..a37fa7d 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" @@ -14,7 +14,7 @@ public class 二叉搜索树的最近公共祖先 { public static void main(String[] args) { - TreeNode root = TreeUtils.asTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); + TreeNode root = TreeUtils.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); TreeNode p = TreeUtils.find(root, 2); TreeNode q = TreeUtils.find(root, 8); // TreeNode treeNode = lowestCommonAncestor(root, p, q); @@ -23,7 +23,7 @@ public static void main(String[] args) { Assertions.assertEquals(6, treeNode.val); System.out.println("公共祖先节点 = " + treeNode.val); - TreeNode root2 = TreeUtils.asTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); + TreeNode root2 = TreeUtils.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); TreeNode p2 = TreeUtils.find(root2, 2); TreeNode q2 = TreeUtils.find(root2, 4); // TreeNode treeNode2 = lowestCommonAncestor(root2, p2, q2); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" index b543c50..1fb0c28 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" @@ -36,7 +36,7 @@ public class 二叉搜索树节点最小距离 { public static void main(String[] args) { - TreeNode tree = TreeUtils.asTree(4, 2, 6, 1, 3, null, null); + TreeNode tree = TreeUtils.buildTree(4, 2, 6, 1, 3, null, null); System.out.println("result = " + minDiffInBST2(tree)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" index 1974f3a..6a2fe32 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" @@ -16,9 +16,9 @@ public class 验证二叉搜索树 { public static void main(String[] args) { - TreeNode root = TreeUtils.asTree(2, 1, 3); - TreeNode root2 = TreeUtils.asTree(5, 1, 4, null, null, 3, 6); - TreeNode root3 = TreeUtils.asTree(1, 1); + TreeNode root = TreeUtils.buildTree(2, 1, 3); + TreeNode root2 = TreeUtils.buildTree(5, 1, 4, null, null, 3, 6); + TreeNode root3 = TreeUtils.buildTree(1, 1); Assertions.assertTrue(isValidBST(root)); Assertions.assertFalse(isValidBST(root2)); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" index 748279f..2ae0cb5 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" @@ -13,13 +13,13 @@ public class 二叉树中的最大路径和 { public static void main(String[] args) { 二叉树中的最大路径和 demo = new 二叉树中的最大路径和(); - TreeNode tree = TreeUtils.asTree(1, 2, 3); + TreeNode tree = TreeUtils.buildTree(1, 2, 3); Assertions.assertEquals(6, demo.maxPathSum(tree)); - TreeNode tree2 = TreeUtils.asTree(-10, 9, 20, null, null, 15, 7); + TreeNode tree2 = TreeUtils.buildTree(-10, 9, 20, null, null, 15, 7); Assertions.assertEquals(42, demo.maxPathSum(tree2)); - TreeNode tree3 = TreeUtils.asTree(2, -1); + TreeNode tree3 = TreeUtils.buildTree(2, -1); Assertions.assertEquals(2, demo.maxPathSum(tree3)); - TreeNode tree4 = TreeUtils.asTree(-2, -1); + TreeNode tree4 = TreeUtils.buildTree(-2, -1); Assertions.assertEquals(-1, demo.maxPathSum(tree4)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" new file mode 100644 index 0000000..f4740e1 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" @@ -0,0 +1,44 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 114. 二叉树展开为链表 + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 二叉树展开为链表 { + + public static void main(String[] args) { + TreeNode root = TreeUtils.buildTree(1, 2, 5, 3, 4, null, 6); + flatten(root); + System.out.println("args = " + Arrays.toString(args)); + } + + public static void flatten(TreeNode root) { + traverse(root); + } + + static void traverse(TreeNode root) { + if (root == null) { return ; } + traverse(root.left); + traverse(root.right); + TreeNode left = root.left; + TreeNode right = root.right; + + root.left = null; + root.right = left; + + TreeNode p = root; + while (p.right != null) { + p = p.right; + } + p.right = right; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" index d368ddf..8d47be0 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" @@ -8,29 +8,49 @@ import java.util.List; /** + * 144. 二叉树的前序遍历 + * * @author Zhang Peng - * @since 2020-07-06 + * @date 2025-08-11 */ public class 二叉树的前序遍历 { public static void main(String[] args) { - TreeNode tree = TreeUtils.buildTree(new Integer[] { 1, null, 2, 3 }); + TreeNode tree = TreeUtils.buildTree(1, null, 2, 3); List list = preorderTraversal(tree); Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, list.toArray(new Integer[0])); } + static List res = new ArrayList<>(); + + /** + * 遍历思路的递归 + */ public static List preorderTraversal(TreeNode root) { - List list = new ArrayList<>(); - if (root == null) return list; - backtrack(root, list); - return list; + traverse(root); + return res; } - public static void backtrack(TreeNode root, List list) { + public static void traverse(TreeNode root) { if (root == null) return; - list.add(root.val); - if (root.left != null) backtrack(root.left, list); - if (root.right != null) backtrack(root.right, list); + res.add(root.val); + traverse(root.left); + traverse(root.right); + } + + /** + * 分解思路的递归 + */ + public static List preorderTraversal2(TreeNode root) { + List res = new ArrayList<>(); + if (root == null) return res; + // 前序遍历的结果,root.val 在第一个 + res.add(root.val); + // 利用函数定义,后面接着左子树的前序遍历结果 + res.addAll(preorderTraversal(root.left)); + // 利用函数定义,最后接着右子树的前序遍历结果 + res.addAll(preorderTraversal(root.right)); + return res; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" index c690a6a..ef1090b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" @@ -14,7 +14,7 @@ public class 二叉树的层次遍历 { public static void main(String[] args) { - TreeNode tree = TreeUtils.asTree(3, 9, 20, null, null, 15, 7); + TreeNode tree = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); List> resultList = levelOrder(tree); List> expectList = new LinkedList<>(); expectList.add(Arrays.asList(3)); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" index 1bc152a..4f729a1 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" @@ -37,7 +37,7 @@ public class 二叉树的层次遍历2 { public static void main(String[] args) { - TreeNode tree = TreeUtils.asTree(3, 9, 20, null, null, 15, 7); + TreeNode tree = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); List> resultList = levelOrderBottom(tree); List> expectList = new LinkedList<>(); expectList.add(Arrays.asList(15, 7)); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" index f194694..af0c364 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" @@ -1,10 +1,9 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; -import java.util.Arrays; import java.util.LinkedList; -import java.util.List; /** * @author Zhang Peng @@ -13,55 +12,89 @@ public class 二叉树的序列化与反序列化 { public static void main(String[] args) { - TreeNode tree = deserialize("[1,2,3,null,null,4,5]"); - System.out.println("args = " + serialize(tree)); + // String input = "1,2,null,4,null,null,3,null,null"; + String input2 = "null,null,null,4,2,null,null,3,1"; + TreeNode tree = deserialize(input2); + Assertions.assertEquals(input2, serialize(tree)); } - public static String rserialize(TreeNode root, String str) { - if (root == null) { - str += "null,"; - } else { - str += str.valueOf(root.val) + ","; - str = rserialize(root.left, str); - str = rserialize(root.right, str); - } - return str; - } + static final String SEP = ","; + static final String NULL = "null"; public static String serialize(TreeNode root) { - String text = rserialize(root, ""); - while (text.endsWith("null,")) { - int index = text.lastIndexOf("null,"); - text = text.substring(0, index); + StringBuilder sb = new StringBuilder(); + serializePostOrder(root, sb); + int size = sb.length(); + int pos = sb.lastIndexOf(SEP); + if (pos == size - 1) { + sb.deleteCharAt(pos); } - if (text.endsWith(",")) { - text = text.substring(0, text.length() - 1); + return sb.toString(); + } + + static void serializePreOrder(TreeNode root, StringBuilder sb) { + if (root == null) { + sb.append(NULL).append(SEP); + return; } - return text; + + // 前序处理 + sb.append(root.val).append(SEP); + + serializePreOrder(root.left, sb); + serializePreOrder(root.right, sb); } - public static TreeNode rdeserialize(List list) { - if (list == null || list.size() == 0) { - return null; + static void serializePostOrder(TreeNode root, StringBuilder sb) { + if (root == null) { + sb.append(NULL).append(SEP); + return; } - if (list.get(0).equalsIgnoreCase("null")) { - list.remove(0); - return null; + + serializePostOrder(root.left, sb); + serializePostOrder(root.right, sb); + + // 后序处理 + sb.append(root.val).append(SEP); + } + + public static TreeNode deserialize(String data) { + // 将字符串转化成列表 + LinkedList nodes = new LinkedList<>(); + for (String s : data.split(SEP)) { + nodes.addLast(s); } + return deserializePostOrder(nodes); + } + + static TreeNode deserializePreOrder(LinkedList nodes) { + if (nodes.isEmpty()) return null; + + // ****** 前序位置 ******** + // 列表最左侧就是根节点 + String first = nodes.removeFirst(); + if (first.equals(NULL)) return null; + TreeNode root = new TreeNode(Integer.parseInt(first)); + + // ********************* - TreeNode root = new TreeNode(Integer.valueOf(list.get(0))); - list.remove(0); - root.left = rdeserialize(list); - root.right = rdeserialize(list); + root.left = deserializePreOrder(nodes); + root.right = deserializePreOrder(nodes); return root; } - public static TreeNode deserialize(String data) { - data = data.substring(1, data.length() - 1); - String[] nums = data.split(","); - List list = new LinkedList(Arrays.asList(nums)); - return rdeserialize(list); + static TreeNode deserializePostOrder(LinkedList nodes) { + if (nodes.isEmpty()) return null; + + String last = nodes.removeLast(); + if (last.equals(NULL)) return null; + TreeNode root = new TreeNode(Integer.parseInt(last)); + + root.right = deserializePostOrder(nodes); + root.left = deserializePostOrder(nodes); + + return root; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" index 483939b..da425df 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" @@ -36,7 +36,7 @@ public class 二叉树的所有路径 { public static void main(String[] args) { - TreeNode tree = TreeUtils.asTree(1, 2, 3, 5); + TreeNode tree = TreeUtils.buildTree(1, 2, 3, 5); System.out.println("result = " + binaryTreePaths(tree)); Assertions.assertArrayEquals(Arrays.asList("1->2->5", "1->3").toArray(), binaryTreePaths(tree).toArray(new String[0])); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" index fea75ee..78dcb15 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" @@ -4,52 +4,58 @@ import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; -import java.util.LinkedList; -import java.util.Queue; - /** - * 104. 二叉树的最大深度 算法实现 + * 104. 二叉树的最大深度 * - * @see 104. 二叉树的最大深度 + * @author Zhang Peng + * @date 2025-08-11 */ public class 二叉树的最大深度 { public static void main(String[] args) { TreeNode tree = TreeUtils.deserialize("[3,9,20,null,null,15,7]"); - System.out.println("result = " + maxDepthInDFS(tree)); - Assertions.assertEquals(3, maxDepthInDFS(tree)); - Assertions.assertEquals(3, maxDepthInBFS(tree)); + Assertions.assertEquals(3, maxDepth(tree)); + Assertions.assertEquals(3, maxDepth2(tree)); } - // 基于 DFS 实现 - // 时间复杂度 O(N) - public static int maxDepthInDFS(TreeNode root) { - if (root == null) return 0; - return 1 + Math.max(maxDepthInDFS(root.left), maxDepthInDFS(root.right)); + // 分解递归 + public static int maxDepth(TreeNode root) { + if (root == null) { return 0; } + + // 利用定义,计算左右子树的最大深度 + int leftMax = maxDepth(root.left); + int rightMax = maxDepth(root.right); + + // 根据左右子树的最大深度推出原二叉树的最大深度 + // 整棵树的最大深度等于左右子树的最大深度取最大值, + // 然后再加上根节点自己 + return 1 + Math.max(leftMax, rightMax); } - // 基于 BFS 实现 - // 逐层扫描,只要每层有节点,层级数+1 - // 时间复杂度 O(N) - public static int maxDepthInBFS(TreeNode root) { - - if (root == null) return 0; - - int level = 0; - Queue queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - level++; - int size = queue.size(); - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - if (node == null) continue; - if (node.left != null) queue.add(node.left); - if (node.right != null) queue.add(node.right); - } - } + // 遍历递归 + + public static int depth = 0; + public static int max = 0; - return level; + public static int maxDepth2(TreeNode root) { + traverse(root); + return max; + } + + public static void traverse(TreeNode root) { + if (root == null) return; + + // 前序遍历位置(进入节点)增加深度 + depth++; + // 遍历到叶子节点时记录最大深度 + if (root.left == null && root.right == null) { + System.out.println("root = " + root.val + ", depth = " + depth); + max = Math.max(max, depth); + } + traverse(root.left); + traverse(root.right); + // 后序遍历位置(离开节点)减少深度 + depth--; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" index a2333fb..43057ee 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" @@ -34,7 +34,7 @@ public class 二叉树的最小深度 { public static void main(String[] args) { - TreeNode tree = TreeUtils.asTree(3, 9, 20, null, null, 15, 7); + TreeNode tree = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); System.out.println("result = " + minDepthInDFS(tree)); Assertions.assertEquals(2, minDepthInDFS(tree)); Assertions.assertEquals(2, minDepthInBFS(tree)); @@ -53,27 +53,22 @@ public static int minDepthInDFS(TreeNode root) { // 时间复杂度 O(N) public static int minDepthInBFS(TreeNode root) { if (root == null) return 0; - int level = 0; - int min = -1; + int depth = 0; + int min = Integer.MAX_VALUE; Queue queue = new LinkedList<>(); queue.offer(root); while (!queue.isEmpty()) { - level++; + depth++; int size = queue.size(); - for (int i = 0; i < size; i++) { + while (size-- > 0) { TreeNode node = queue.poll(); if (node.left == null && node.right == null) { - if (min == -1) { - min = level; - } else { - min = Math.min(min, level); - } + min = Math.min(min, depth); } if (node.left != null) queue.offer(node.left); if (node.right != null) queue.offer(node.right); } } - return min; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" index da64616..c94761e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" @@ -13,7 +13,7 @@ public class 二叉树的最近公共祖先 { public static void main(String[] args) { - TreeNode root = TreeUtils.asTree(3, 5, 1, 6, 2, 0, 8, null, null, 7, 4); + TreeNode root = TreeUtils.buildTree(3, 5, 1, 6, 2, 0, 8, null, null, 7, 4); TreeNode p = TreeUtils.find(root, 5); TreeNode q = TreeUtils.find(root, 1); TreeNode treeNode = lowestCommonAncestor(root, p, q); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" new file mode 100644 index 0000000..4853958 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" @@ -0,0 +1,50 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.List; + +/** + * 543. 二叉树的直径 + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 二叉树的直径 { + + public static void main(String[] args) { + TreeNode tree = TreeUtils.buildTree(new Integer[] { 1, 2, 3, 4, 5 }); + Assertions.assertEquals(3, diameterOfBinaryTree(tree)); + + TreeNode tree2 = TreeUtils.buildTree(new Integer[] { 1, 2 }); + Assertions.assertEquals(1, diameterOfBinaryTree(tree2)); + } + + static int max = Integer.MIN_VALUE; + + public static int diameterOfBinaryTree(TreeNode root) { + if (root == null) return 0; + traverse(root); + return max; + } + + public static void traverse(TreeNode root) { + if (root == null) return; + int left = maxDepth(root.left); + int right = maxDepth(root.right); + max = Math.max(max, left + right); + traverse(root.left); + traverse(root.right); + } + + public static int maxDepth(TreeNode root) { + if (root == null) return 0; + int left = maxDepth(root.left); + int right = maxDepth(root.right); + return Math.max(left, right) + 1; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" index 7bd0b78..689d269 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" @@ -33,7 +33,7 @@ public class 二叉树的锯齿形层次遍历 { public static void main(String[] args) { - TreeNode tree = TreeUtils.asTree(3, 9, 20, null, null, 15, 7); + TreeNode tree = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); List> resultList = zigzagLevelOrder(tree); System.out.println(resultList); List> expectList = new LinkedList<>(); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" index 78bf624..280d97e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" @@ -10,62 +10,50 @@ import java.util.Map; /** + * 106. + * 从中序与后序遍历序列构造二叉树 + * * @author Zhang Peng - * @since 2020-07-07 + * @date 2025-08-11 */ public class 从中序与后序遍历序列构造二叉树 { public static void main(String[] args) { - int[] postorder = { 9, 15, 7, 20, 3 }; - int[] inorder = { 9, 3, 15, 20, 7 }; - 从中序与后序遍历序列构造二叉树 demo = new 从中序与后序遍历序列构造二叉树(); - TreeNode root = demo.buildTree(inorder, postorder); - List list = TreeUtils.toBfsValueList(root); + TreeNode output1 = buildTree(new int[] { 9, 3, 15, 20, 7 }, new int[] { 9, 15, 7, 20, 3 }); + List list = TreeUtils.toBfsValueList(output1); System.out.println(list); Assertions.assertArrayEquals(Arrays.asList(3, 9, 20, null, null, 15, 7).toArray(), list.toArray()); } - private Map map; + static Map map; - public TreeNode backtrack(int[] postorder, int[] inorder, int postLeft, int postRight, int inLeft, int inRight) { - if (postLeft > postRight) return null; - - // 后序遍历中的最后一个节点就是根节点 - // 在中序遍历中定位根节点 - int inRoot = map.get(postorder[postRight]); - - // 先把根节点建立出来 - TreeNode root = new TreeNode(postorder[postRight]); - - // 得到右子树中的节点数目 - int rightTreeSize = inRight - inRoot; - - // System.out.printf("左子树:postLeft = %s, postRight = %s, inLeft = %s, inRight = %s\n", - // postorder[postLeft], postorder[postRight - rightTreeSize - 1], inorder[inLeft], inorder[inRoot - 1]); - // System.out.printf("右子树:postLeft = %s, postRight = %s, inLeft = %s, inRight = %s\n", - // postorder[postRight - rightTreeSize], postorder[postRight - 1], inorder[inRoot + 1], inorder[inRight]); - - // 递归地构造左子树,并连接到根节点 - // 先序遍历中「从 左边界+1 开始的 leftTreeSize」个元素就对应了 - // 中序遍历中「从 左边界 开始到 根节点定位-1」的元素 - root.left = backtrack(postorder, inorder, postLeft, postRight - rightTreeSize - 1, inLeft, inRoot - 1); - - // 递归地构造右子树,并连接到根节点 - // 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了 - // 中序遍历中「从 根节点定位+1 到 右边界」的元素 - root.right = backtrack(postorder, inorder, postRight - rightTreeSize, postRight - 1, inRoot + 1, inRight); - - return root; + public static TreeNode buildTree(int[] inorder, int[] postorder) { + if (inorder.length == 0 || postorder.length == 0) { + return null; + } + map = new HashMap<>(inorder.length); + for (int i = 0; i < inorder.length; i++) { + map.put(inorder[i], i); + } + return build(inorder, 0, inorder.length - 1, + postorder, 0, postorder.length - 1); } - public TreeNode buildTree(int[] inorder, int[] postorder) { - if (postorder == null || inorder == null) { return null;} - int n = inorder.length; - map = new HashMap<>(n); - for (int i = 0; i < n; i++) { - map.put(inorder[i], i); + public static TreeNode build(int[] inorder, int inBegin, int inEnd, + int[] postorder, int postBegin, int postEnd) { + if (inBegin > inEnd || postBegin > postEnd) { + return null; } - return backtrack(postorder, inorder, 0, n - 1, 0, n - 1); + int rootVal = postorder[postEnd]; + int rootPos = map.get(rootVal); + int leftSize = rootPos - inBegin; + + TreeNode root = new TreeNode(rootVal); + root.left = build(inorder, inBegin, rootPos - 1, + postorder, postBegin, postBegin + leftSize - 1); + root.right = build(inorder, rootPos + 1, inEnd, + postorder, postBegin + leftSize, postEnd - 1); + return root; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" index ec1944b..6f56230 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" @@ -10,60 +10,54 @@ import java.util.Map; /** + * 105. 从前序与中序遍历序列构造二叉树 + * * @author Zhang Peng - * @since 2020-07-07 + * @date 2025-08-11 */ public class 从前序与中序遍历序列构造二叉树 { public static void main(String[] args) { - int[] preorder = { 3, 9, 20, 15, 7 }; - int[] inorder = { 9, 3, 15, 20, 7 }; - 从前序与中序遍历序列构造二叉树 demo = new 从前序与中序遍历序列构造二叉树(); - TreeNode root = demo.buildTree(preorder, inorder); - List list = TreeUtils.toBfsValueList(root); + TreeNode output1 = buildTree(new int[] { 3, 9, 20, 15, 7 }, new int[] { 9, 3, 15, 20, 7 }); + List list = TreeUtils.toBfsValueList(output1); System.out.println(list); Assertions.assertArrayEquals(Arrays.asList(3, 9, 20, null, null, 15, 7).toArray(), list.toArray()); + + TreeNode output2 = buildTree(new int[] { -1 }, new int[] { -1 }); + List list2 = TreeUtils.toBfsValueList(output2); + System.out.println(list2); + Assertions.assertArrayEquals(Arrays.asList(-1).toArray(), list2.toArray()); } - // 中序遍历结构,key 是值,value 是索引 - private Map map; + // 存储 inorder 中值到索引的映射 + static HashMap map = new HashMap<>(); - public TreeNode backtrack(int[] preorder, int preLeft, int preRight, int inLeft, int inRight) { - if (preLeft > preRight) { + public static TreeNode buildTree(int[] preorder, int[] inorder) { + if (preorder == null || inorder == null + || preorder.length == 0 || inorder.length == 0) { return null; } + for (int i = 0; i < inorder.length; i++) { + map.put(inorder[i], i); + } - // 前序遍历中的第一个节点就是根节点 - // 在中序遍历中定位根节点 - int inRoot = map.get(preorder[preLeft]); - - // 先把根节点建立出来 - TreeNode root = new TreeNode(preorder[preLeft]); - - // 得到左子树中的节点数目 - int leftTreeSize = inRoot - inLeft; - - // 递归地构造左子树,并连接到根节点 - // 先序遍历中「从 左边界+1 开始的 leftTreeSize」个元素就对应了 - // 中序遍历中「从 左边界 开始到 根节点定位-1」的元素 - root.left = backtrack(preorder, preLeft + 1, preLeft + leftTreeSize, inLeft, inRoot - 1); - - // 递归地构造右子树,并连接到根节点 - // 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了 - // 中序遍历中「从 根节点定位+1 到 右边界」的元素 - root.right = backtrack(preorder, preLeft + leftTreeSize + 1, preRight, inRoot + 1, inRight); - return root; + return build(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1); } - public TreeNode buildTree(int[] preorder, int[] inorder) { - if (preorder == null || inorder == null) { return null;} - int n = preorder.length; - // 构造哈希映射,帮助我们快速定位根节点 - map = new HashMap<>(n); - for (int i = 0; i < n; i++) { - map.put(inorder[i], i); + public static TreeNode build(int[] preorder, int preBegin, int preEnd, + int[] inorder, int inBegin, int inEnd) { + if (preBegin > preEnd || inBegin > inEnd) { + return null; } - return backtrack(preorder, 0, n - 1, 0, n - 1); + int rootVal = preorder[preBegin]; + int rootInIndex = map.get(rootVal); + int inLeftLen = rootInIndex - inBegin; + TreeNode root = new TreeNode(rootVal); + root.left = build(preorder, preBegin + 1, preBegin + inLeftLen, + inorder, inBegin, rootInIndex - 1); + root.right = build(preorder, preBegin + inLeftLen + 1, preEnd, + inorder, rootInIndex + 1, inEnd); + return root; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" index d6e0219..33a3db7 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" @@ -32,8 +32,8 @@ public class 叶子相似的树 { public static void main(String[] args) { - TreeNode tree1 = TreeUtils.asTree(3, 5, 1, 6, 2, 9, 8, null, null, 7, 4); - TreeNode tree2 = TreeUtils.asTree(3, 5, 1, 6, 7, 4, 2, null, null, null, null, null, null, 9, 8); + TreeNode tree1 = TreeUtils.buildTree(3, 5, 1, 6, 2, 9, 8, null, null, 7, 4); + TreeNode tree2 = TreeUtils.buildTree(3, 5, 1, 6, 7, 4, 2, null, null, null, null, null, null, 9, 8); Assertions.assertTrue(leafSimilar(tree1, tree2)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" index 65d625a..c5a5773 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" @@ -1,37 +1,25 @@ package io.github.dunwu.algorithm.tree.btree; -import java.util.LinkedList; - /** + * 116. 填充每个节点的下一个右侧节点指针 + * * @author Zhang Peng - * @since 2020-07-06 + * @date 2025-08-11 */ public class 填充每个节点的下一个右侧节点指针 { public Node connect(Node root) { if (root == null) return null; - bfs(root); + traverse(root.left, root.right); return root; } - /** - * 基于 BFS 实现二叉树层次遍历。关键在于使用一个队列存储 - */ - public void bfs(Node root) { - LinkedList queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - int size = queue.size(); - for (int i = 1; i < size; i++) { - queue.get(i - 1).next = queue.get(i); - } - - for (int i = 0; i < size; i++) { - Node node = queue.poll(); - if (node.left != null) queue.offer(node.left); - if (node.right != null) queue.offer(node.right); - } - } + public void traverse(Node n1, Node n2) { + if (n1 == null || n2 == null) return; + n1.next = n2; + traverse(n1.left, n1.right); + traverse(n2.left, n2.right); + traverse(n1.right, n2.left); } private static class Node { @@ -57,5 +45,4 @@ public String toString() { } } - } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" index a87d430..45a6822 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" @@ -31,10 +31,10 @@ public class 对称二叉树 { public static void main(String[] args) { - TreeNode tree = TreeUtils.asTree(1, 2, 2, 3, 4, 4, 3); + TreeNode tree = TreeUtils.buildTree(1, 2, 2, 3, 4, 4, 3); System.out.println("result = " + isSymmetric(tree)); - tree = TreeUtils.asTree(1, 2, 2, null, 3, null, 3); + tree = TreeUtils.buildTree(1, 2, 2, null, 3, null, 3); System.out.println("result = " + isSymmetric(tree)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" index 1a16951..270cdf0 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" @@ -11,9 +11,9 @@ public class 平衡二叉树 { public static void main(String[] args) { - TreeNode tree = TreeUtils.asTree(3, 9, 20, null, null, 15, 7); - TreeNode tree2 = TreeUtils.asTree(1, 2, 2, 3, 3, null, null, 4, 4); - TreeNode tree3 = TreeUtils.asTree(null); + TreeNode tree = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); + TreeNode tree2 = TreeUtils.buildTree(1, 2, 2, 3, 3, null, null, 4, 4); + TreeNode tree3 = TreeUtils.buildTree(null); 平衡二叉树 demo = new 平衡二叉树(); Assertions.assertTrue(demo.isBalanced(tree)); Assertions.assertFalse(demo.isBalanced(tree2)); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" new file mode 100644 index 0000000..696a747 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" @@ -0,0 +1,51 @@ +package io.github.dunwu.algorithm.tree.btree; + +import cn.hutool.json.JSONUtil; +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.List; + +/** + * 654. 最大二叉树 + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 最大二叉树 { + + public static void main(String[] args) { + TreeNode output = constructMaximumBinaryTree(new int[] { 3, 2, 1, 6, 0, 5 }); + List outputList = TreeUtils.toBfsValueList(output); + Assertions.assertArrayEquals(new Integer[] { 6, 3, 5, null, 2, 0, null, null, 1 }, outputList.toArray()); + + TreeNode root = constructMaximumBinaryTree(new int[] { 3, 2, 1 }); + List list = TreeUtils.toBfsValueList(root); + Assertions.assertArrayEquals(new Integer[] { 3, null, 2, null, 1 }, list.toArray()); + } + + public static TreeNode constructMaximumBinaryTree(int[] nums) { + return traverse(nums, 0, nums.length - 1); + } + + public static TreeNode traverse(int[] nums, int left, int right) { + if (nums == null || nums.length == 0) return null; + if (left > right) return null; + + int pos = left, max = Integer.MIN_VALUE; + for (int i = left; i <= right; i++) { + if (nums[i] > max) { + max = nums[i]; + pos = i; + } + } + + TreeNode root = new TreeNode(max); + root.left = traverse(nums, left, pos - 1); + root.right = traverse(nums, pos + 1, right); + return root; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" new file mode 100644 index 0000000..821f2f2 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" @@ -0,0 +1,72 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +/** + * 106. + * 从中序与后序遍历序列构造二叉树 + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 根据前序和后序遍历构造二叉树 { + + public static void main(String[] args) { + TreeNode output1 = constructFromPrePost(new int[] { 1, 2, 4, 5, 3, 6, 7 }, new int[] { 4, 5, 2, 6, 7, 3, 1 }); + List list = TreeUtils.toBfsValueList(output1); + System.out.println(list); + Assertions.assertArrayEquals(Arrays.asList(1, 2, 3, 4, 5, 6, 7).toArray(), list.toArray()); + } + + // 存储 postorder 中值到索引的映射 + static HashMap map = new HashMap<>(); + + public static TreeNode constructFromPrePost(int[] preorder, int[] postorder) { + for (int i = 0; i < postorder.length; i++) { + map.put(postorder[i], i); + } + return build(preorder, 0, preorder.length - 1, + postorder, 0, postorder.length - 1); + } + + // 定义:根据 preorder[preBegin..preEnd] 和 postorder[postBegin..postEnd] + // 构建二叉树,并返回根节点。 + static TreeNode build(int[] preorder, int preBegin, int preEnd, + int[] postorder, int postBegin, int postEnd) { + if (preBegin > preEnd) { + return null; + } + if (preBegin == preEnd) { + return new TreeNode(preorder[preBegin]); + } + + // root 节点对应的值就是前序遍历数组的第一个元素 + int rootVal = preorder[preBegin]; + // root.left 的值是前序遍历第二个元素 + // 通过前序和后序遍历构造二叉树的关键在于通过左子树的根节点 + // 确定 preorder 和 postorder 中左右子树的元素区间 + int nextRootVal = preorder[preBegin + 1]; + // leftRootVal 在后序遍历数组中的索引 + int nextRootPos = map.get(nextRootVal); + // 左子树的元素个数 + int leftSize = nextRootPos - postBegin + 1; + + // 先构造出当前根节点 + TreeNode root = new TreeNode(rootVal); + + // 递归构造左右子树 + // 根据左子树的根节点索引和元素个数推导左右子树的索引边界 + root.left = build(preorder, preBegin + 1, preBegin + leftSize, + postorder, postBegin, nextRootPos); + root.right = build(preorder, preBegin + leftSize + 1, preEnd, + postorder, nextRootPos + 1, postEnd - 1); + return root; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\233\270\345\220\214\347\232\204\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\233\270\345\220\214\347\232\204\346\240\221.java" index 405373a..96b00c6 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\233\270\345\220\214\347\232\204\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\233\270\345\220\214\347\232\204\346\240\221.java" @@ -46,16 +46,16 @@ public class 相同的树 { public static void main(String[] args) { - TreeNode tree1 = TreeUtils.asTree(1, 2, 3); - TreeNode tree2 = TreeUtils.asTree(1, 2, 3); + TreeNode tree1 = TreeUtils.buildTree(1, 2, 3); + TreeNode tree2 = TreeUtils.buildTree(1, 2, 3); System.out.println("result = " + isSameTree(tree1, tree2)); - tree1 = TreeUtils.asTree(1, 2); - tree2 = TreeUtils.asTree(1, 2, 3); + tree1 = TreeUtils.buildTree(1, 2); + tree2 = TreeUtils.buildTree(1, 2, 3); System.out.println("result = " + isSameTree(tree1, tree2)); - tree1 = TreeUtils.asTree(1, 2, 1); - tree2 = TreeUtils.asTree(1, 1, 2); + tree1 = TreeUtils.buildTree(1, 2, 1); + tree2 = TreeUtils.buildTree(1, 1, 2); System.out.println("result = " + isSameTree(tree1, tree2)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" index 8328d06..b7cc361 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" @@ -4,49 +4,45 @@ import io.github.dunwu.algorithm.tree.TreeUtils; /** - * 翻转二叉树 算法实现 + * 226. 翻转二叉树 * - *

- * 翻转一棵二叉树。
- *
- * 示例:
- *
- * 输入:
- *
- *      4
- *    /   \
- *   2     7
- *  / \   / \
- * 1   3 6   9
- * 输出:
- *
- *      4
- *    /   \
- *   7     2
- *  / \   / \
- * 9   6 3   1
- * 备注:
- * 这个问题是受到 Max Howell 的 原问题 启发的 :
- * 
- * - * @see 翻转二叉树 + * @author Zhang Peng + * @date 2025-08-11 */ public class 翻转二叉树 { public static void main(String[] args) { - TreeNode tree = TreeUtils.asTree(4, 2, 7, 1, 3, 6, 9); - System.out.println("result = " + invertTree(tree)); + TreeNode tree = TreeUtils.buildTree(4, 2, 7, 1, 3, 6, 9); + System.out.println("result = " + invertTree2(tree)); } + /** + * 分解递归 + */ public static TreeNode invertTree(TreeNode root) { - if (root == null) { return null; } - - TreeNode right = invertTree(root.right); + if (root == null) return null; TreeNode left = invertTree(root.left); - - root.left = right; + TreeNode right = invertTree(root.right); root.right = left; + root.left = right; + return root; + } + + /** + * 遍历递归 + */ + public static TreeNode invertTree2(TreeNode root) { + traverse(root); return root; } + public static void traverse(TreeNode root) { + if (root == null) return; + TreeNode tmp = root.left; + root.left = root.right; + root.right = tmp; + traverse(root.left); + traverse(root.right); + } + } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" index 28cc9b1..edf8641 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" @@ -31,9 +31,9 @@ public class 路径总和 { public static void main(String[] args) { TreeNode - tree = TreeUtils.asTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, null, null, 1); + tree = TreeUtils.buildTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, null, null, 1); Assertions.assertTrue(hasPathSum(tree, 22)); - TreeNode tree2 = TreeUtils.asTree(1, 2); + TreeNode tree2 = TreeUtils.buildTree(1, 2); Assertions.assertFalse(hasPathSum(tree2, 1)); } From ecefd754f64d0cf2ee2a1c20a8cb8da7f19d0354 Mon Sep 17 00:00:00 2001 From: dunwu Date: Mon, 18 Aug 2025 07:08:01 +0800 Subject: [PATCH 06/21] =?UTF-8?q?feat:=20=E5=88=B7=20leetcode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 81 +++++++++++------ .../array/\344\270\221\346\225\260I.java" | 2 +- .../array/\344\270\221\346\225\260II.java" | 2 +- .../array/\344\270\221\346\225\260III.java" | 2 +- ...\345\210\266\346\261\202\345\222\214.java" | 2 +- ...\347\233\226\345\255\220\344\270\262.java" | 2 +- ...\345\257\271\346\225\260\345\255\227.java" | 2 +- ...\344\270\252\345\225\206\345\223\201.java" | 2 +- ...\347\272\247\344\270\221\346\225\260.java" | 2 +- ...46\225\260\347\233\270\345\212\240II.java" | 2 +- ...50\275\254\351\223\276\350\241\250II.java" | 2 +- ...45\275\242\351\223\276\350\241\250II.java" | 2 +- ...\344\270\252\350\212\202\347\202\271.java" | 4 +- .../dunwu/algorithm/tree/TreeUtils.java | 91 ++++++++----------- ...\345\205\245\346\223\215\344\275\234.java" | 2 +- ...\346\226\207\350\267\257\345\276\204.java" | 70 ++++++++++++++ ...\344\270\272\351\223\276\350\241\250.java" | 57 ++++++++---- ...\345\272\217\351\201\215\345\216\206.java" | 42 +++++++-- ...\345\272\217\351\201\215\345\216\206.java" | 70 ++++++++------ ...\345\217\263\350\247\206\345\233\276.java" | 60 ++++++++++++ ...\345\272\217\351\201\215\345\216\206.java" | 47 ++++++++-- ...\346\254\241\351\201\215\345\216\206.java" | 72 ++++++++++----- ...346\254\241\351\201\215\345\216\2062.java" | 87 +++++++++--------- ...\346\234\211\350\267\257\345\276\204.java" | 71 +++++++-------- ...\345\244\247\346\267\261\345\272\246.java" | 50 +++------- ...\345\260\217\346\267\261\345\272\246.java" | 74 ++++----------- ...\347\232\204\347\233\264\345\276\204.java" | 48 +++++----- ...\346\254\241\351\201\215\345\216\206.java" | 6 +- ...\344\272\214\345\217\211\346\240\221.java" | 53 ++++++----- ...\344\272\214\345\217\211\346\240\221.java" | 2 +- ...\344\272\214\345\217\211\346\240\221.java" | 62 +++++++------ ...\345\255\227\347\254\246\344\270\262.java" | 64 +++++++++++++ ...\346\225\260\344\271\213\345\222\214.java" | 53 +++++++++++ ...\345\212\240\344\270\200\350\241\214.java" | 80 ++++++++++++++++ ...\347\202\271\346\214\207\351\222\210.java" | 69 +++++++++----- ...347\202\271\346\214\207\351\222\2102.java" | 69 ++++++++++++++ ...47\202\271\346\214\207\351\222\210II.java" | 61 ------------- ...\347\202\271\344\270\252\346\225\260.java" | 39 ++++++++ ...\345\255\220\344\271\213\345\222\214.java" | 51 +++++++++++ ...\344\272\214\345\217\211\346\240\221.java" | 6 +- ...\344\272\214\345\217\211\346\240\221.java" | 70 ++++++-------- ...\345\255\227\344\271\213\345\222\214.java" | 65 +++++++++++++ ...\345\272\217\345\210\227\345\214\226.java" | 52 +++++++++++ 43 files changed, 1176 insertions(+), 574 deletions(-) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210II.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" diff --git a/README.md b/README.md index 777fed7..cc061c8 100644 --- a/README.md +++ b/README.md @@ -208,39 +208,68 @@ ### 二叉树 -#### 二叉树系列算法核心纲领 - -| 题目 | 掌握度 | -| ------------------------------------------------------------ | ------ | -| [104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) | 已掌握 | -| [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/) | 已掌握 | -| [543. 二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree/) | | -| [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/) | | -| [116. 填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) | 未掌握 | -| [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/) | 已掌握 | -| [105. 从前序与中序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) | 不熟练 | -| [106. 从中序与后序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) | 不熟练 | -| [654. 最大二叉树](https://leetcode.cn/problems/maximum-binary-tree/) | 已掌握 | -| [889. 根据前序和后序遍历构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-postorder-traversal/) | | -| [297. 二叉树的序列化与反序列化](https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/) | 未掌握 | +#### 基础 + +| 题目 | 掌握度 | +| ------------------------------------------------------------------------------------------------------------------------ | ------ | +| [104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) | 已掌握 | +| [111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/) | 已掌握 | +| [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/) | 已掌握 | +| [94. 二叉树的中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal/) | 已掌握 | +| [145. 二叉树的后序遍历](https://leetcode.cn/problems/binary-tree-postorder-traversal/) | 已掌握 | +| [102. 二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal/) | 不熟练 | +| [107. 二叉树的层序遍历 II](https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/) | 已掌握 | +| [543. 二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree/) | 未掌握 | +| [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/) | 已掌握 | +| [116. 填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) | 已掌握 | +| [117. 填充每个节点的下一个右侧节点指针 II](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/) | 已掌握 | +| [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/) | 已掌握 | +| [654. 最大二叉树](https://leetcode.cn/problems/maximum-binary-tree/) | 已掌握 | +| [297. 二叉树的序列化与反序列化](https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/) | 未掌握 | +| [222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/) | 已掌握 | + +#### 用「遍历」思维解题 + +| 题目 | 掌握度 | +| ----------------------------------------------------------------------------------------------------------------------------------------------- | ------ | +| [257. 二叉树的所有路径](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_binary-tree-paths) | 未掌握 | +| [129. 求根节点到叶节点数字之和](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_sum-root-to-leaf-numbers) | 已掌握 | +| [199. 二叉树的右视图](https://leetcode.cn/problems/binary-tree-right-side-view/) | 已掌握 | +| [988. 从叶结点开始的最小字符串](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_smallest-string-starting-from-leaf) | 已掌握 | +| [1022. 从根到叶的二进制数之和](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_sum-of-root-to-leaf-binary-numbers) | 已掌握 | +| [1457. 二叉树中的伪回文路径](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_pseudo-palindromic-paths-in-a-binary-tree) | 已掌握 | +| [404. 左叶子之和](https://leetcode.cn/problems/sum-of-left-leaves/) | 已掌握 | +| [623. 在二叉树中增加一行](https://leetcode.cn/problems/add-one-row-to-tree/) | 已掌握 | + +#### 用「分解」思维解题 + +| 题目 | 掌握度 | +| ------------------------------------------------------------------------------------------------------------------------------- | ------ | +| [105. 从前序与中序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) | 已掌握 | +| [106. 从中序与后序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) | 已掌握 | +| [889. 根据前序和后序遍历构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-postorder-traversal/) | 已掌握 | +| [331. 验证二叉树的前序序列化](https://leetcode.cn/problems/verify-preorder-serialization-of-a-binary-tree/) | | +| [894. 所有可能的真二叉树](https://leetcode.cn/problems/all-possible-full-binary-trees/) | | +| [998. 最大二叉树 II](https://leetcode.cn/problems/maximum-binary-tree-ii/) | | +| [1110. 删点成林](https://leetcode.cn/problems/delete-nodes-and-return-forest/) | | ### 动态规划 -| 题目 | 掌握度 | -| ------------------------------------------------------------ | ------ | -| [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | | +| 题目 | 掌握度 | +| ----------------------------------------------------------------- | ------ | +| [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | | | [509. 斐波那契数](https://leetcode.cn/problems/fibonacci-number/) | | -| | | -| | | -| | | -| | | -| | | +| | | +| | | +| | | +| | | +| | | ### 贪心算法 -| 题目 | 掌握度 | -| ------------------------------------------------------------ | ------ | -| [55. 跳跃游戏](https://leetcode.cn/problems/jump-game/) | | +| 题目 | 掌握度 | +| ------------------------------------------------------------- | ------ | +| [55. 跳跃游戏](https://leetcode.cn/problems/jump-game/) | | | [45. 跳跃游戏 II](https://leetcode.cn/problems/jump-game-ii/) | | ### 分治算法 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" index 9fa6302..d0799ec 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" @@ -6,7 +6,7 @@ import java.util.Set; /** - * 263. 丑数 + * 263. 丑数 * * @author Zhang Peng * @date 2025-01-24 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260II.java" index 8033c89..84b657f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260II.java" @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Assertions; /** - * 264. 丑数II + * 264. 丑数II * * @author Zhang Peng * @date 2025-01-24 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260III.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260III.java" index 27434b8..49101b6 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260III.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260III.java" @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Assertions; /** - * 264. 丑数II + * 264. 丑数II * * @author Zhang Peng * @date 2025-01-24 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" index e2fff7c..95857bf 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Assertions; /** - * 67. 二进制求和 + * 67. 二进制求和 * * @author Zhang Peng * @date 2025-01-21 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" index d6109b5..6c38c24 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" @@ -6,7 +6,7 @@ import java.util.HashMap; /** - * 76. 最小覆盖子串 + * 76. 最小覆盖子串 * * @author Zhang Peng * @date 2025-01-10 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" index 8581d0a..2fe2f75 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" @@ -9,7 +9,7 @@ import java.util.TreeMap; /** - * 373. 查找和最小的 K 对数字 + * 373. 查找和最小的 K 对数字 * * @author Zhang Peng * @date 2025-01-21 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" index 9386473..02e6f8f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" @@ -6,7 +6,7 @@ import java.util.Map; /** - * LCR 179. 查找总价格为目标值的两个商品 + * LCR 179. 查找总价格为目标值的两个商品 * * @author Zhang Peng * @date 2025-01-13 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" index c372b91..b9b257a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Assertions; /** - * 313. 超级丑数 + * 313. 超级丑数 * * @author Zhang Peng * @date 2025-01-24 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" index 35fb871..029cc7f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" @@ -6,7 +6,7 @@ import java.util.List; /** - * LCR 025. 两数相加II + * LCR 025. 两数相加II * * @author Zhang Peng * @date 2025-01-21 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" index d861475..4d389de 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" @@ -5,7 +5,7 @@ import java.util.List; /** - * 92. 反转链表 II + * 92. 反转链表 II * * @author Zhang Peng * @date 2025-01-20 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" index d7d7a49..888ba13 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Assertions; /** - * 142. 环形链表 II + * 142. 环形链表 II * * @author Zhang Peng * @since 2020-07-08 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" index fcd5f98..d2725ab 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" @@ -3,8 +3,8 @@ import org.junit.jupiter.api.Assertions; /** - * 面试题 02. 返回倒数第 k 个节点 - * LCR 140. 训练计划 II + * 面试题 02. 返回倒数第 k 个节点 + * LCR 140. 训练计划 II * * @author Zhang Peng * @since 2020-06-09 diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeUtils.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeUtils.java index a3c623d..149adf3 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeUtils.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeUtils.java @@ -8,53 +8,36 @@ */ public class TreeUtils { - static final String SEP = ","; - static final String NULL = "null"; + public static TreeNode buildTree(Integer... values) { - public static TreeNode buildTree(Integer... arr) { - List list = new ArrayList<>(); - - for (Integer value : arr) { - // 创建结点,每一个结点的左结点和右结点为null - TreeNode node; - if (value == null) { - node = null; - } else { - node = new TreeNode(value, null, null); - } - // list中存着每一个结点 - list.add(node); + if (values == null || values.length == 0 || values[0] == null) { + return null; } - // 构建二叉树 - if (list.size() > 0) { - // i表示的是根节点的索引,从0开始 - for (int i = 0; i < arr.length / 2 - 1; i++) { - if (list.get(2 * i + 1) != null) { - // 左结点 - list.get(i).left = list.get(2 * i + 1); - } - if (list.get(2 * i + 2) != null) { - // 右结点 - list.get(i).right = list.get(2 * i + 2); - } - } - // 判断最后一个根结点:因为最后一个根结点可能没有右结点,所以单独拿出来处理 - int lastIndex = arr.length / 2 - 1; - - if (list.get(lastIndex) != null) { - // 左结点 - list.get(lastIndex).left = list.get(lastIndex * 2 + 1); - // 右结点,如果数组的长度为奇数才有右结点 - if (arr.length % 2 == 1) { - list.get(lastIndex).right = list.get(lastIndex * 2 + 2); - } + Queue queue = new LinkedList<>(); + TreeNode root = new TreeNode(values[0]); + queue.offer(root); + + int i = 1; + while (!queue.isEmpty() && i < values.length) { + TreeNode current = queue.poll(); + + // 处理左子节点 + if (i < values.length && values[i] != null) { + current.left = new TreeNode(values[i]); + queue.offer(current.left); } + i++; - return list.get(0); - } else { - return null; + // 处理右子节点 + if (i < values.length && values[i] != null) { + current.right = new TreeNode(values[i]); + queue.offer(current.right); + } + i++; } + + return root; } public static TreeNode find(TreeNode root, int val) { @@ -78,7 +61,7 @@ public static void depthOrderTraverse(TreeNode root) { } } - public static List toBfsList(TreeNode root) { + public static List toList(TreeNode root) { List list = new ArrayList<>(); if (root == null) { return list; @@ -102,7 +85,7 @@ public static List toBfsList(TreeNode root) { return list.subList(0, last + 1); } - public static List toBfsValueList(TreeNode root) { + public static List toValueList(TreeNode root) { List list = new ArrayList<>(); if (root == null) { return list; @@ -131,9 +114,9 @@ public static List toBfsValueList(TreeNode root) { return list.subList(0, last + 1); } - public static String serialize(TreeNode root) { + public static String serialize(TreeNode root, String NULL, String SEP) { StringBuilder sb = new StringBuilder(); - serializePreOrder(root, sb); + serializePreOrder(root, sb, NULL, SEP); int size = sb.length(); int pos = sb.lastIndexOf(SEP); if (pos == size - 1) { @@ -142,7 +125,7 @@ public static String serialize(TreeNode root) { return sb.toString(); } - static void serializePreOrder(TreeNode root, StringBuilder sb) { + static void serializePreOrder(TreeNode root, StringBuilder sb, String NULL, String SEP) { if (root == null) { sb.append(NULL).append(SEP); return; @@ -151,28 +134,28 @@ static void serializePreOrder(TreeNode root, StringBuilder sb) { // 前序处理 sb.append(root.val).append(SEP); - serializePreOrder(root.left, sb); - serializePreOrder(root.right, sb); + serializePreOrder(root.left, sb, NULL, SEP); + serializePreOrder(root.right, sb, NULL, SEP); } - public static TreeNode deserialize(String data) { + public static TreeNode deserialize(String data, String SEP, String NULL) { // 将字符串转化成列表 LinkedList nodes = new LinkedList<>(); for (String s : data.split(SEP)) { nodes.addLast(s); } - return deserializePreOrder(nodes); + return deserializePreOrder(nodes, NULL); } - static TreeNode deserializePreOrder(LinkedList nodes) { + static TreeNode deserializePreOrder(LinkedList nodes, String NULL) { if (nodes.isEmpty()) return null; String first = nodes.removeFirst(); if (first.equals(NULL)) return null; TreeNode root = new TreeNode(Integer.parseInt(first)); - root.left = deserializePreOrder(nodes); - root.right = deserializePreOrder(nodes); + root.left = deserializePreOrder(nodes, NULL); + root.right = deserializePreOrder(nodes, NULL); return root; } @@ -180,7 +163,7 @@ static TreeNode deserializePreOrder(LinkedList nodes) { public static void main(String[] args) { Integer[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; TreeNode head = TreeUtils.buildTree(array); - toBfsList(head); + toList(head); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" index 0e7ce8e..27f8d70 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" @@ -15,7 +15,7 @@ public class 二叉搜索树中的插入操作 { public static void main(String[] args) { TreeNode tree = TreeUtils.buildTree(4, 2, 7, 1, 3); insertIntoBST(tree, 5); - List treeNodes = TreeUtils.toBfsList(tree); + List treeNodes = TreeUtils.toList(tree); System.out.println(treeNodes); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" new file mode 100644 index 0000000..0bb7acf --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" @@ -0,0 +1,70 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +/** + * 1457. 二叉树中的伪回文路径 + * + * @author Zhang Peng + * @date 2025-08-15 + */ +public class 二叉树中的伪回文路径 { + + public static void main(String[] args) { + Assertions.assertEquals(2, + new Solution().pseudoPalindromicPaths(TreeUtils.buildTree(2, 3, 1, 3, 1, null, 1))); + Assertions.assertEquals(1, + new Solution().pseudoPalindromicPaths(TreeUtils.buildTree(2, 1, 1, 1, 3, null, null, null, null, null, 1))); + } + + static class Solution { + + int num = 0; + LinkedList paths = new LinkedList<>(); + + public int pseudoPalindromicPaths(TreeNode root) { + traverse(root); + return num; + } + + public void traverse(TreeNode root) { + if (root == null) { return; } + + paths.addLast(root.val); + if (root.left == null && root.right == null) { + // System.out.println("paths: " + paths); + if (isPalindromic(paths)) { + num++; + } + } else { + traverse(root.left); + traverse(root.right); + } + paths.removeLast(); + } + + public boolean isPalindromic(LinkedList paths) { + if (paths.isEmpty()) { return false; } + if (paths.size() == 1) { return true; } + Map counter = new HashMap<>(paths.size()); + for (Integer path : paths) { + counter.compute(path, (k, v) -> v == null ? 1 : v + 1); + } + int oddNum = 0; + for (Integer v : counter.values()) { + if (v % 2 != 0) { + oddNum++; + } + } + return oddNum < 2; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" index f4740e1..d80d421 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" @@ -4,7 +4,7 @@ import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; -import java.util.Arrays; +import java.util.List; /** * 114. 二叉树展开为链表 @@ -15,30 +15,49 @@ public class 二叉树展开为链表 { public static void main(String[] args) { - TreeNode root = TreeUtils.buildTree(1, 2, 5, 3, 4, null, 6); - flatten(root); - System.out.println("args = " + Arrays.toString(args)); - } - public static void flatten(TreeNode root) { - traverse(root); + Solution s = new Solution(); + + TreeNode root = TreeUtils.buildTree(1, 2, 5, 3, 4, null, 6); + s.flatten(root); + List list = TreeUtils.toValueList(root); + Assertions.assertArrayEquals(new Integer[] { 1, null, 2, null, 3, null, 4, null, 5, null, 6 }, + list.toArray(new Integer[0])); + + TreeNode root2 = TreeUtils.buildTree(0); + s.flatten(root2); + List list2 = TreeUtils.toValueList(root2); + Assertions.assertArrayEquals(new Integer[] { 0 }, + list2.toArray(new Integer[0])); + + TreeNode root3 = TreeUtils.buildTree(); + s.flatten(root3); + List list3 = TreeUtils.toValueList(root3); + Assertions.assertArrayEquals(new Integer[] {}, + list3.toArray(new Integer[0])); } - static void traverse(TreeNode root) { - if (root == null) { return ; } - traverse(root.left); - traverse(root.right); - TreeNode left = root.left; - TreeNode right = root.right; + static class Solution { - root.left = null; - root.right = left; + public void flatten(TreeNode root) { + traverse(root); + } - TreeNode p = root; - while (p.right != null) { - p = p.right; + void traverse(TreeNode root) { + if (root == null) { return; } + traverse(root.left); + traverse(root.right); + if (root.left == null) { return; } + TreeNode right = root.right; + root.right = root.left; + TreeNode p = root.left; + while (p.right != null) { + p = p.right; + } + p.right = right; + root.left = null; } - p.right = right; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" index fc5581f..9607c61 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" @@ -1,28 +1,50 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; import java.util.ArrayList; import java.util.List; /** + * 94. 二叉树的中序遍历 + * * @author Zhang Peng * @since 2020-07-06 */ public class 二叉树的中序遍历 { - public static List inorderTraversal(TreeNode root) { - List list = new ArrayList<>(); - if (root == null) return list; - backtrack(root, list); - return list; + public static void main(String[] args) { + Solution s1 = new Solution(); + TreeNode root = TreeUtils.buildTree(1, null, 2, 3); + Assertions.assertArrayEquals(new Integer[] { 1, 3, 2 }, s1.inorderTraversal(root).toArray(new Integer[0])); + + Solution s2 = new Solution(); + TreeNode root2 = TreeUtils.buildTree(); + Assertions.assertArrayEquals(new Integer[] {}, s2.inorderTraversal(root2).toArray(new Integer[0])); + + Solution s3 = new Solution(); + TreeNode root3 = TreeUtils.buildTree(1); + Assertions.assertArrayEquals(new Integer[] { 1 }, s3.inorderTraversal(root3).toArray(new Integer[0])); } - public static void backtrack(TreeNode root, List list) { - if (root == null) return; - if (root.left != null) backtrack(root.left, list); - list.add(root.val); - if (root.right != null) backtrack(root.right, list); + private static class Solution { + + List values = new ArrayList<>(); + + public List inorderTraversal(TreeNode root) { + traverse(root); + return values; + } + + public void traverse(TreeNode root) { + if (root == null) return; + traverse(root.left); + values.add(root.val); + traverse(root.right); + } + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" index 8d47be0..7063228 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" @@ -16,41 +16,53 @@ public class 二叉树的前序遍历 { public static void main(String[] args) { - TreeNode tree = TreeUtils.buildTree(1, null, 2, 3); - List list = preorderTraversal(tree); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, list.toArray(new Integer[0])); - } + Solution s1 = new Solution(); + TreeNode root = TreeUtils.buildTree(1, null, 2, 3); + Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, s1.preorderTraversal(root).toArray(new Integer[0])); - static List res = new ArrayList<>(); + Solution s2 = new Solution(); + TreeNode root2 = TreeUtils.buildTree(); + Assertions.assertArrayEquals(new Integer[] {}, s2.preorderTraversal(root2).toArray(new Integer[0])); - /** - * 遍历思路的递归 - */ - public static List preorderTraversal(TreeNode root) { - traverse(root); - return res; + Solution s3 = new Solution(); + TreeNode root3 = TreeUtils.buildTree(1); + Assertions.assertArrayEquals(new Integer[] { 1 }, s3.preorderTraversal(root3).toArray(new Integer[0])); } - public static void traverse(TreeNode root) { - if (root == null) return; - res.add(root.val); - traverse(root.left); - traverse(root.right); - } + private static class Solution { - /** - * 分解思路的递归 - */ - public static List preorderTraversal2(TreeNode root) { List res = new ArrayList<>(); - if (root == null) return res; - // 前序遍历的结果,root.val 在第一个 - res.add(root.val); - // 利用函数定义,后面接着左子树的前序遍历结果 - res.addAll(preorderTraversal(root.left)); - // 利用函数定义,最后接着右子树的前序遍历结果 - res.addAll(preorderTraversal(root.right)); - return res; + + /** + * 遍历思路的递归 + */ + public List preorderTraversal(TreeNode root) { + traverse(root); + return res; + } + + public void traverse(TreeNode root) { + if (root == null) return; + res.add(root.val); + traverse(root.left); + traverse(root.right); + } + + /** + * 分解思路的递归 + */ + public List preorderTraversal2(TreeNode root) { + List res = new ArrayList<>(); + if (root == null) return res; + // 前序遍历的结果,root.val 在第一个 + res.add(root.val); + // 利用函数定义,后面接着左子树的前序遍历结果 + res.addAll(preorderTraversal(root.left)); + // 利用函数定义,最后接着右子树的前序遍历结果 + res.addAll(preorderTraversal(root.right)); + return res; + } + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" new file mode 100644 index 0000000..a3f7593 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" @@ -0,0 +1,60 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * 求根节点到叶节点数字之和 + * + * @author Zhang Peng + * @date 2025-08-15 + */ +public class 二叉树的右视图 { + + public static void main(String[] args) { + Assertions.assertArrayEquals(new Integer[] { 1, 3, 4 }, + new Solution().rightSideView(TreeUtils.buildTree(1, 2, 3, null, 5, null, 4)).toArray(new Integer[0])); + + Assertions.assertArrayEquals(new Integer[] { 1, 3, 4, 5 }, + new Solution().rightSideView(TreeUtils.buildTree(1, 2, 3, 4, null, null, null, 5)).toArray(new Integer[0])); + } + + static class Solution { + + public List rightSideView(TreeNode root) { + if (root == null) { + return new ArrayList<>(); + } + + List res = new LinkedList<>(); + LinkedList q = new LinkedList<>(); + q.offer(root); + + while (!q.isEmpty()) { + int size = q.size(); + TreeNode node = null; + for (int i = 0; i < size; i++) { + node = q.poll(); + if (node.left != null) { + q.offer(node.left); + } + if (node.right != null) { + q.offer(node.right); + } + } + if (node != null) { + res.add(node.val); + } + } + + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" index 742464c..320c3ab 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" @@ -1,28 +1,55 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; import java.util.ArrayList; import java.util.List; /** + * 145. 二叉树的后序遍历 + * * @author Zhang Peng * @since 2020-07-06 */ public class 二叉树的后序遍历 { - public List postorderTraversal(TreeNode root) { - List list = new ArrayList<>(); - if (root == null) return list; - backtrack(root, list); - return list; + public static void main(String[] args) { + Solution s1 = new Solution(); + TreeNode root = TreeUtils.buildTree(1, null, 2, 3); + Assertions.assertArrayEquals(new Integer[] { 3, 2, 1 }, s1.postorderTraversal(root).toArray(new Integer[0])); + + Solution s2 = new Solution(); + TreeNode root2 = TreeUtils.buildTree(); + Assertions.assertArrayEquals(new Integer[] {}, s2.postorderTraversal(root2).toArray(new Integer[0])); + + Solution s3 = new Solution(); + TreeNode root3 = TreeUtils.buildTree(1); + Assertions.assertArrayEquals(new Integer[] { 1 }, s3.postorderTraversal(root3).toArray(new Integer[0])); + + Solution s4 = new Solution(); + TreeNode root4 = TreeUtils.buildTree(1, 2, 3, 4, 5, null, 8, null, null, 6, 7, 9); + Assertions.assertArrayEquals(new Integer[] { 4, 6, 7, 5, 2, 9, 8, 3, 1 }, + s4.postorderTraversal(root4).toArray(new Integer[0])); } - public static void backtrack(TreeNode root, List list) { - if (root == null) return; - if (root.left != null) backtrack(root.left, list); - if (root.right != null) backtrack(root.right, list); - list.add(root.val); + private static class Solution { + + List values = new ArrayList<>(); + + public List postorderTraversal(TreeNode root) { + traverse(root); + return values; + } + + public void traverse(TreeNode root) { + if (root == null) return; + traverse(root.left); + traverse(root.right); + values.add(root.val); + } + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" index ef1090b..17d1a25 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" @@ -4,47 +4,71 @@ import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; /** + * 二叉树的层次遍历 + * * @author Zhang Peng - * @see 二叉树的层次遍历 * @since 2020-06-18 */ public class 二叉树的层次遍历 { public static void main(String[] args) { - TreeNode tree = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); - List> resultList = levelOrder(tree); + Solution s = new Solution(); + TreeNode root = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); List> expectList = new LinkedList<>(); expectList.add(Arrays.asList(3)); expectList.add(Arrays.asList(9, 20)); expectList.add(Arrays.asList(15, 7)); - Assertions.assertArrayEquals(expectList.toArray(), resultList.toArray()); + Assertions.assertArrayEquals(expectList.toArray(), s.levelOrder(root).toArray()); + + Solution s2 = new Solution(); + TreeNode root2 = TreeUtils.buildTree(1); + List> expectList2 = new LinkedList<>(); + expectList2.add(Arrays.asList(1)); + Assertions.assertArrayEquals(expectList2.toArray(), s2.levelOrder(root2).toArray()); + + Solution s3 = new Solution(); + TreeNode root3 = TreeUtils.buildTree(); + Assertions.assertArrayEquals(new LinkedList<>().toArray(), s3.levelOrder(root3).toArray()); } - /** - * 基于 BFS 实现二叉树层次遍历。关键在于使用一个队列存储 - */ - public static List> levelOrder(TreeNode root) { - List> result = new ArrayList<>(); - if (root == null) return result; - - Queue queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - int size = queue.size(); - List list = new ArrayList<>(); - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - if (node.left != null) queue.offer(node.left); - if (node.right != null) queue.offer(node.right); - list.add(node.val); + static class Solution { + + public List> levelOrder(TreeNode root) { + if (root == null) { + return new ArrayList(); + } + List> result = new LinkedList<>(); + LinkedList queue = new LinkedList<>(); + queue.add(root); + int level = 1; + while (!queue.isEmpty()) { + int n = queue.size(); + System.out.printf("\nLevel[%s]: ", level); + List curLevelNodes = new LinkedList<>(); + for (int i = 0; i < n; i++) { + TreeNode node = queue.poll(); + System.out.printf("%s, ", node); + curLevelNodes.add(node.val); + if (node.left != null) { + queue.add(node.left); + } + if (node.right != null) { + queue.add(node.right); + } + } + level++; + result.add(curLevelNodes); } - result.add(list); + System.out.println(); + return result; } - return result; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" index 4f729a1..317a43a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" @@ -4,68 +4,71 @@ import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; /** - * 二叉树的层次遍历 II 算法实现 + * 二叉树的层次遍历 II * - *
- * 给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
- *
- * 例如:
- * 给定二叉树 [3,9,20,null,null,15,7],
- *
- *     3
- *    / \
- *   9  20
- *     /  \
- *    15   7
- * 返回其自底向上的层次遍历为:
- *
- * [
- *   [15,7],
- *   [9,20],
- *   [3]
- * ]
- * 
- * - * @see 二叉树的层次遍历 II + * @author Zhang Peng + * @since 2020-06-18 */ public class 二叉树的层次遍历2 { public static void main(String[] args) { - TreeNode tree = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); - List> resultList = levelOrderBottom(tree); + Solution s = new Solution(); + TreeNode root = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); List> expectList = new LinkedList<>(); expectList.add(Arrays.asList(15, 7)); expectList.add(Arrays.asList(9, 20)); expectList.add(Arrays.asList(3)); - Assertions.assertArrayEquals(expectList.toArray(), resultList.toArray()); + Assertions.assertArrayEquals(expectList.toArray(), s.levelOrderBottom(root).toArray()); + + Solution s2 = new Solution(); + TreeNode root2 = TreeUtils.buildTree(1); + List> expectList2 = new LinkedList<>(); + expectList2.add(Arrays.asList(1)); + Assertions.assertArrayEquals(expectList2.toArray(), s2.levelOrderBottom(root2).toArray()); + + Solution s3 = new Solution(); + TreeNode root3 = TreeUtils.buildTree(); + Assertions.assertArrayEquals(new LinkedList<>().toArray(), s3.levelOrderBottom(root3).toArray()); } - public static List> levelOrderBottom(TreeNode root) { - List> result = new LinkedList<>(); - LinkedList queue = new LinkedList<>(); - if (root == null) return result; - queue.offer(root); - while (!queue.isEmpty()) { - int size = queue.size(); - List list = new LinkedList<>(); - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - if (node != null) { - list.add(node.val); - if (node.left != null) queue.add(node.left); - if (node.right != null) queue.add(node.right); + static class Solution { + + public List> levelOrderBottom(TreeNode root) { + + if (root == null) { + return new ArrayList(); + } + + LinkedList queue = new LinkedList<>(); + List> result = new LinkedList<>(); + queue.add(root); + + while (!queue.isEmpty()) { + int size = queue.size(); + List currentLevel = new LinkedList<>(); + result.add(currentLevel); + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + currentLevel.add(node.val); + if (node.left != null) { + queue.offer(node.left); + } + if (node.right != null) { + queue.offer(node.right); + } } } - result.add(list); + Collections.reverse(result); + return result; } - Collections.reverse(result); - return result; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" index da425df..ff1108e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" @@ -7,57 +7,54 @@ import java.util.Arrays; import java.util.LinkedList; import java.util.List; +import java.util.stream.Collectors; /** - * 二叉树的所有路径 算法实现 + * 二叉树的所有路径 * - *
- * 给定一个二叉树,返回所有从根节点到叶子节点的路径。
- *
- * 说明: 叶子节点是指没有子节点的节点。
- *
- * 示例:
- *
- * 输入:
- *
- *    1
- *  /   \
- * 2     3
- *  \
- *   5
- *
- * 输出: ["1->2->5", "1->3"]
- *
- * 解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3
- * 
- * - * @see 二叉树的所有路径 + * @author Zhang Peng + * @since 2025-08-15 */ public class 二叉树的所有路径 { public static void main(String[] args) { + + Solution s = new Solution(); TreeNode tree = TreeUtils.buildTree(1, 2, 3, 5); - System.out.println("result = " + binaryTreePaths(tree)); + List list = s.binaryTreePaths(tree); Assertions.assertArrayEquals(Arrays.asList("1->2->5", "1->3").toArray(), - binaryTreePaths(tree).toArray(new String[0])); + list.toArray(new String[0])); } - public static List binaryTreePaths(TreeNode root) { + static class Solution { + + LinkedList nodes = new LinkedList<>(); List paths = new LinkedList<>(); - recordPath(root, "", paths); - return paths; - } - private static void recordPath(TreeNode node, String path, List paths) { - if (node == null) return; - path += node.val; - if (node.left == null && node.right == null) { - paths.add(path); - } else { - path += "->"; - recordPath(node.left, path, paths); - recordPath(node.right, path, paths); + public List binaryTreePaths(TreeNode root) { + traverse(root); + return paths; } + + public void traverse(TreeNode root) { + if (root == null) { + return; + } + + if (root.left == null && root.right == null) { + nodes.addLast(String.valueOf(root.val)); + String path = String.join("->", nodes.toArray(new String[0])); + paths.add(path); + nodes.removeLast(); + return; + } + + nodes.addLast(String.valueOf(root.val)); + traverse(root.left); + traverse(root.right); + nodes.removeLast(); + } + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" index 78dcb15..fbe08e6 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" @@ -13,49 +13,23 @@ public class 二叉树的最大深度 { public static void main(String[] args) { - TreeNode tree = TreeUtils.deserialize("[3,9,20,null,null,15,7]"); - Assertions.assertEquals(3, maxDepth(tree)); - Assertions.assertEquals(3, maxDepth2(tree)); - } - - // 分解递归 - public static int maxDepth(TreeNode root) { - if (root == null) { return 0; } - - // 利用定义,计算左右子树的最大深度 - int leftMax = maxDepth(root.left); - int rightMax = maxDepth(root.right); - - // 根据左右子树的最大深度推出原二叉树的最大深度 - // 整棵树的最大深度等于左右子树的最大深度取最大值, - // 然后再加上根节点自己 - return 1 + Math.max(leftMax, rightMax); - } - - // 遍历递归 + Solution s = new Solution(); + TreeNode root = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); + Assertions.assertEquals(3, s.maxDepth(root)); - public static int depth = 0; - public static int max = 0; - - public static int maxDepth2(TreeNode root) { - traverse(root); - return max; + TreeNode root2 = TreeUtils.buildTree(1, null, 2); + Assertions.assertEquals(2, s.maxDepth(root2)); } - public static void traverse(TreeNode root) { - if (root == null) return; + static class Solution { - // 前序遍历位置(进入节点)增加深度 - depth++; - // 遍历到叶子节点时记录最大深度 - if (root.left == null && root.right == null) { - System.out.println("root = " + root.val + ", depth = " + depth); - max = Math.max(max, depth); + public int maxDepth(TreeNode root) { + if (root == null) { return 0; } + int left = maxDepth(root.left); + int right = maxDepth(root.right); + return Math.max(left, right) + 1; } - traverse(root.left); - traverse(root.right); - // 后序遍历位置(离开节点)减少深度 - depth--; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" index 43057ee..c8374b4 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" @@ -4,72 +4,34 @@ import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; -import java.util.LinkedList; -import java.util.Queue; - /** - * 二叉树的最小深度 算法实现 - * - *
- * 给定一个二叉树,找出其最小深度。
- *
- * 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
- *
- * 说明: 叶子节点是指没有子节点的节点。
- *
- * 示例:
- *
- * 给定二叉树 [3,9,20,null,null,15,7],
+ * 二叉树的最小深度
  *
- *     3
- *    / \
- *   9  20
- *     /  \
- *    15   7
- * 返回它的最小深度  2.
- * 
- * - * @see 二叉树的最小深度 + * @author Zhang Peng + * @date 2025-08-11 */ public class 二叉树的最小深度 { public static void main(String[] args) { - TreeNode tree = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); - System.out.println("result = " + minDepthInDFS(tree)); - Assertions.assertEquals(2, minDepthInDFS(tree)); - Assertions.assertEquals(2, minDepthInBFS(tree)); - } + Solution s = new Solution(); + + TreeNode root = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); + Assertions.assertEquals(2, s.minDepth(root)); - // 基于 DFS 实现 - // 时间复杂度 O(N) - public static int minDepthInDFS(TreeNode root) { - if (root == null) return 0; - if (root.left == null) return 1 + minDepthInDFS(root.right); - if (root.right == null) return 1 + minDepthInDFS(root.left); - return 1 + Math.min(minDepthInDFS(root.left), minDepthInDFS(root.right)); + TreeNode root2 = TreeUtils.buildTree(2, null, 3, null, 4, null, 5, null, 6); + Assertions.assertEquals(5, s.minDepth(root2)); } - // 基于 BFS 实现 - // 时间复杂度 O(N) - public static int minDepthInBFS(TreeNode root) { - if (root == null) return 0; - int depth = 0; - int min = Integer.MAX_VALUE; - Queue queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - depth++; - int size = queue.size(); - while (size-- > 0) { - TreeNode node = queue.poll(); - if (node.left == null && node.right == null) { - min = Math.min(min, depth); - } - if (node.left != null) queue.offer(node.left); - if (node.right != null) queue.offer(node.right); - } + static class Solution { + + public int minDepth(TreeNode root) { + if (root == null) { return 0; } + int left = minDepth(root.left); + int right = minDepth(root.right); + if (root.left == null || root.right == null) { return left + right + 1; } + return Math.min(left, right) + 1; } - return min; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" index 4853958..09624b0 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" @@ -4,9 +4,6 @@ import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; -import java.util.ArrayList; -import java.util.List; - /** * 543. 二叉树的直径 * @@ -16,35 +13,34 @@ public class 二叉树的直径 { public static void main(String[] args) { - TreeNode tree = TreeUtils.buildTree(new Integer[] { 1, 2, 3, 4, 5 }); - Assertions.assertEquals(3, diameterOfBinaryTree(tree)); + Solution s = new Solution(); + TreeNode root = TreeUtils.buildTree(1, 2, 3, 4, 5); + Assertions.assertEquals(3, s.diameterOfBinaryTree(root)); - TreeNode tree2 = TreeUtils.buildTree(new Integer[] { 1, 2 }); - Assertions.assertEquals(1, diameterOfBinaryTree(tree2)); + Solution s2 = new Solution(); + TreeNode root2 = TreeUtils.buildTree(1, 2); + Assertions.assertEquals(1, s2.diameterOfBinaryTree(root2)); } - static int max = Integer.MIN_VALUE; + static class Solution { - public static int diameterOfBinaryTree(TreeNode root) { - if (root == null) return 0; - traverse(root); - return max; - } + private int max = 0; - public static void traverse(TreeNode root) { - if (root == null) return; - int left = maxDepth(root.left); - int right = maxDepth(root.right); - max = Math.max(max, left + right); - traverse(root.left); - traverse(root.right); - } + public int diameterOfBinaryTree(TreeNode root) { + if (root == null) { return 0; } + maxDepth(root); + return max; + } + + public int maxDepth(TreeNode root) { + if (root == null) { return 0; } + int left = maxDepth(root.left); + int right = maxDepth(root.right); + int temp = left + right; + max = Math.max(max, temp); + return Math.max(left, right) + 1; + } - public static int maxDepth(TreeNode root) { - if (root == null) return 0; - int left = maxDepth(root.left); - int right = maxDepth(root.right); - return Math.max(left, right) + 1; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" index 689d269..52bdb3f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" @@ -4,7 +4,11 @@ import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; /** * 103. 二叉树的锯齿形层次遍历 算法实现 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" index 280d97e..d642dcd 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" @@ -19,41 +19,40 @@ public class 从中序与后序遍历序列构造二叉树 { public static void main(String[] args) { - TreeNode output1 = buildTree(new int[] { 9, 3, 15, 20, 7 }, new int[] { 9, 15, 7, 20, 3 }); - List list = TreeUtils.toBfsValueList(output1); + Solution s = new Solution(); + TreeNode output1 = s.buildTree(new int[] { 9, 3, 15, 20, 7 }, new int[] { 9, 15, 7, 20, 3 }); + List list = TreeUtils.toValueList(output1); System.out.println(list); Assertions.assertArrayEquals(Arrays.asList(3, 9, 20, null, null, 15, 7).toArray(), list.toArray()); } - static Map map; + static class Solution { - public static TreeNode buildTree(int[] inorder, int[] postorder) { - if (inorder.length == 0 || postorder.length == 0) { - return null; - } - map = new HashMap<>(inorder.length); - for (int i = 0; i < inorder.length; i++) { - map.put(inorder[i], i); + Map map = new HashMap<>(); + + public TreeNode buildTree(int[] inorder, int[] postorder) { + if (inorder == null || postorder == null) { return null; } + for (int i = 0; i < inorder.length; i++) { + map.put(inorder[i], i); + } + return build(inorder, 0, inorder.length - 1, + postorder, 0, postorder.length - 1); } - return build(inorder, 0, inorder.length - 1, - postorder, 0, postorder.length - 1); - } - public static TreeNode build(int[] inorder, int inBegin, int inEnd, - int[] postorder, int postBegin, int postEnd) { - if (inBegin > inEnd || postBegin > postEnd) { - return null; + public TreeNode build(int[] inorder, int inBegin, int inEnd, + int[] postorder, int postBegin, int postEnd) { + if (postBegin > postEnd) { return null; } + int rootVal = postorder[postEnd]; + int rootPos = map.get(rootVal); + int leftSize = rootPos - inBegin; + TreeNode root = new TreeNode(rootVal); + root.left = build(inorder, inBegin, rootPos - 1, + postorder, postBegin, postBegin + leftSize - 1); + root.right = build(inorder, rootPos + 1, inEnd, + postorder, postBegin + leftSize, postEnd - 1); + return root; } - int rootVal = postorder[postEnd]; - int rootPos = map.get(rootVal); - int leftSize = rootPos - inBegin; - - TreeNode root = new TreeNode(rootVal); - root.left = build(inorder, inBegin, rootPos - 1, - postorder, postBegin, postBegin + leftSize - 1); - root.right = build(inorder, rootPos + 1, inEnd, - postorder, postBegin + leftSize, postEnd - 1); - return root; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\205\210\345\272\217\351\201\215\345\216\206\350\277\230\345\216\237\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\205\210\345\272\217\351\201\215\345\216\206\350\277\230\345\216\237\344\272\214\345\217\211\346\240\221.java" index 74a4935..1ff3498 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\205\210\345\272\217\351\201\215\345\216\206\350\277\230\345\216\237\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\205\210\345\272\217\351\201\215\345\216\206\350\277\230\345\216\237\344\272\214\345\217\211\346\240\221.java" @@ -13,7 +13,7 @@ public class 从先序遍历还原二叉树 { public static void main(String[] args) { TreeNode result = recoverFromPreorder("1-2--3--4-5--6--7"); - System.out.println(TreeUtils.toBfsList(result)); + System.out.println(TreeUtils.toList(result)); } public static TreeNode recoverFromPreorder(String S) { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" index 6f56230..8786b74 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" @@ -10,7 +10,8 @@ import java.util.Map; /** - * 105. 从前序与中序遍历序列构造二叉树 + * 105. + * 从前序与中序遍历序列构造二叉树 * * @author Zhang Peng * @date 2025-08-11 @@ -18,46 +19,47 @@ public class 从前序与中序遍历序列构造二叉树 { public static void main(String[] args) { - TreeNode output1 = buildTree(new int[] { 3, 9, 20, 15, 7 }, new int[] { 9, 3, 15, 20, 7 }); - List list = TreeUtils.toBfsValueList(output1); + + Solution s = new Solution(); + + TreeNode output1 = s.buildTree(new int[] { 3, 9, 20, 15, 7 }, new int[] { 9, 3, 15, 20, 7 }); + List list = TreeUtils.toValueList(output1); System.out.println(list); Assertions.assertArrayEquals(Arrays.asList(3, 9, 20, null, null, 15, 7).toArray(), list.toArray()); - TreeNode output2 = buildTree(new int[] { -1 }, new int[] { -1 }); - List list2 = TreeUtils.toBfsValueList(output2); + TreeNode output2 = s.buildTree(new int[] { -1 }, new int[] { -1 }); + List list2 = TreeUtils.toValueList(output2); System.out.println(list2); Assertions.assertArrayEquals(Arrays.asList(-1).toArray(), list2.toArray()); } - // 存储 inorder 中值到索引的映射 - static HashMap map = new HashMap<>(); + static class Solution { - public static TreeNode buildTree(int[] preorder, int[] inorder) { - if (preorder == null || inorder == null - || preorder.length == 0 || inorder.length == 0) { - return null; - } - for (int i = 0; i < inorder.length; i++) { - map.put(inorder[i], i); - } + Map map = new HashMap<>(); - return build(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1); - } + public TreeNode buildTree(int[] preorder, int[] inorder) { + if (preorder == null || inorder == null) { return null; } + for (int i = 0; i < inorder.length; i++) { + map.put(inorder[i], i); + } + return build(preorder, 0, preorder.length - 1, + inorder, 0, inorder.length - 1); + } - public static TreeNode build(int[] preorder, int preBegin, int preEnd, - int[] inorder, int inBegin, int inEnd) { - if (preBegin > preEnd || inBegin > inEnd) { - return null; + public TreeNode build(int[] preorder, int preBegin, int preEnd, + int[] inorder, int inBegin, int inEnd) { + if (preBegin > preEnd) { return null; } + int rootVal = preorder[preBegin]; + int rootPos = map.get(rootVal); + int leftSize = rootPos - inBegin; + TreeNode root = new TreeNode(rootVal); + root.left = build(preorder, preBegin + 1, preBegin + leftSize, + inorder, inBegin, rootPos - 1); + root.right = build(preorder, preBegin + leftSize + 1, preEnd, + inorder, rootPos + 1, inEnd); + return root; } - int rootVal = preorder[preBegin]; - int rootInIndex = map.get(rootVal); - int inLeftLen = rootInIndex - inBegin; - TreeNode root = new TreeNode(rootVal); - root.left = build(preorder, preBegin + 1, preBegin + inLeftLen, - inorder, inBegin, rootInIndex - 1); - root.right = build(preorder, preBegin + inLeftLen + 1, preEnd, - inorder, rootInIndex + 1, inEnd); - return root; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" new file mode 100644 index 0000000..1903eb0 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" @@ -0,0 +1,64 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * 988. 从叶结点开始的最小字符串 + * + * @author Zhang Peng + * @date 2025-08-15 + */ +public class 从叶结点开始的最小字符串 { + + public static void main(String[] args) { + Assertions.assertEquals("dba", + new Solution().smallestFromLeaf(TreeUtils.buildTree(0, 1, 2, 3, 4, 3, 4))); + Assertions.assertEquals("adz", + new Solution().smallestFromLeaf(TreeUtils.buildTree(25, 1, 3, 1, 3, 0, 2))); + Assertions.assertEquals("abc", + new Solution().smallestFromLeaf(TreeUtils.buildTree(2, 2, 1, null, 1, 0, null, 0))); + } + + static class Solution { + + String max = null; + LinkedList paths = new LinkedList<>(); + + public String smallestFromLeaf(TreeNode root) { + traverse(root); + return max; + } + + public void traverse(TreeNode root) { + if (root == null) { return; } + + char c = (char) (root.val + 'a'); + paths.addLast(c); + if (root.left == null && root.right == null) { + StringBuilder sb = new StringBuilder(); + for (int i = paths.size() - 1; i >= 0; i--) { + sb.append(paths.get(i)); + } + if (max == null) { + max = sb.toString(); + } else { + if (max.compareTo(sb.toString()) > 0) { + max = sb.toString(); + } + } + } else { + traverse(root.left); + traverse(root.right); + } + paths.removeLast(); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" new file mode 100644 index 0000000..c3a5904 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" @@ -0,0 +1,53 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 1022. 从根到叶的二进制数之和 + * + * @author Zhang Peng + * @date 2025-08-15 + */ +public class 从根到叶的二进制数之和 { + + public static void main(String[] args) { + Assertions.assertEquals(22, + new Solution().sumRootToLeaf(TreeUtils.buildTree(1, 0, 1, 0, 1, 0, 1))); + Assertions.assertEquals(0, + new Solution().sumRootToLeaf(TreeUtils.buildTree(0))); + } + + static class Solution { + + int sum = 0; + LinkedList paths = new LinkedList<>(); + + public int sumRootToLeaf(TreeNode root) { + traverse(root); + return sum; + } + + public void traverse(TreeNode root) { + if (root == null) { return; } + + paths.addLast(root.val); + if (root.left == null && root.right == null) { + int num = 0; + for (Integer value : paths) { + num = num * 2 + value; + } + sum += num; + } else { + traverse(root.left); + traverse(root.right); + } + paths.removeLast(); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" new file mode 100644 index 0000000..2ba9f3a --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" @@ -0,0 +1,80 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * 623. 在二叉树中增加一行 + * + * @author Zhang Peng + * @date 2025-08-15 + */ +public class 在二叉树中增加一行 { + + public static void main(String[] args) { + TreeNode root = TreeUtils.buildTree(4, 2, 6, 3, 1, 5); + TreeNode newRoot = new Solution().addOneRow(root, 1, 2); + List list = TreeUtils.toValueList(newRoot); + Assertions.assertArrayEquals(new Integer[] { 4, 1, 1, 2, null, null, 6, 3, 1, 5 }, list.toArray()); + + TreeNode root2 = TreeUtils.buildTree(4, 2, 6, 3, 1, 5); + TreeNode newRoot2 = new Solution().addOneRow(root2, 1, 1); + List list2 = TreeUtils.toValueList(newRoot2); + Assertions.assertArrayEquals(new Integer[] { 1, 4, null, 2, 6, 3, 1, 5 }, list2.toArray()); + } + + static class Solution { + + public TreeNode addOneRow(TreeNode root, int val, int depth) { + if (root == null) { return root; } + if (depth == 1) { + TreeNode newRoot = new TreeNode(val); + newRoot.left = root; + return newRoot; + } + LinkedList q = new LinkedList<>(); + int level = 1; + q.offer(root); + while (!q.isEmpty()) { + + int size = q.size(); + if (level == depth - 1) { + for (int i = 0; i < size; i++) { + TreeNode node = q.poll(); + TreeNode left = node.left; + node.left = new TreeNode(val); + node.left.left = left; + + TreeNode right = node.right; + node.right = new TreeNode(val); + node.right.right = right; + } + break; + } + + // 层序遍历 + for (int i = 0; i < size; i++) { + TreeNode node = q.poll(); + if (node.left != null) { + q.offer(node.left); + } + if (node.right != null) { + q.offer(node.right); + } + } + + level++; + } + return root; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" index c5a5773..4612d4c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" @@ -1,5 +1,11 @@ package io.github.dunwu.algorithm.tree.btree; +import cn.hutool.json.JSONUtil; +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; + +import java.util.LinkedList; + /** * 116. 填充每个节点的下一个右侧节点指针 * @@ -8,41 +14,56 @@ */ public class 填充每个节点的下一个右侧节点指针 { - public Node connect(Node root) { - if (root == null) return null; - traverse(root.left, root.right); - return root; + public static void main(String[] args) { + Solution s = new Solution(); + TreeNode treeNode = TreeUtils.buildTree(1, 2, 3, 4, 5, 6, 7); + Node root = JSONUtil.toBean(JSONUtil.toJsonStr(treeNode), Node.class); + s.connect(root); + System.out.println(root); } - public void traverse(Node n1, Node n2) { - if (n1 == null || n2 == null) return; - n1.next = n2; - traverse(n1.left, n1.right); - traverse(n2.left, n2.right); - traverse(n1.right, n2.left); + static class Solution { + + public Node connect(Node root) { + if (root == null) return null; + traverse(root); + return root; + } + + public void traverse(Node root) { + if (root == null) return; + LinkedList q = new LinkedList<>(); + q.offer(root); + + while (!q.isEmpty()) { + int size = q.size(); + Node prev = null; + for (int i = 0; i < size; i++) { + Node cur = q.poll(); + if (prev != null) { prev.next = cur; } + if (cur.left != null) q.offer(cur.left); + if (cur.right != null) q.offer(cur.right); + prev = cur; + } + } + } + } - private static class Node { + static class Node extends TreeNode { - public int val; + public Node next; public Node left; public Node right; - public Node next; - - public Node(int val) { this.val = val; } - public Node(int val, Node left, Node right) { - this.val = val; - this.left = left; - this.right = right; + public Node(int val) { + super(val); } - @Override - public String toString() { - return "Node{" + - "val=" + val + - '}'; + public Node(int val, TreeNode left, TreeNode right) { + super(val, left, right); } } + } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" new file mode 100644 index 0000000..69a1bd6 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" @@ -0,0 +1,69 @@ +package io.github.dunwu.algorithm.tree.btree; + +import cn.hutool.json.JSONUtil; +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; + +import java.util.LinkedList; + +/** + * 117. 填充每个节点的下一个右侧节点指针 II + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 填充每个节点的下一个右侧节点指针2 { + + public static void main(String[] args) { + Solution s = new Solution(); + TreeNode treeNode = TreeUtils.buildTree(1, 2, 3, 4, 5, null, 7); + Node root = JSONUtil.toBean(JSONUtil.toJsonStr(treeNode), Node.class); + s.connect(root); + System.out.println(root); + } + + static class Solution { + + public Node connect(Node root) { + if (root == null) return null; + traverse(root); + return root; + } + + public void traverse(Node root) { + if (root == null) return; + LinkedList q = new LinkedList<>(); + q.offer(root); + + while (!q.isEmpty()) { + int size = q.size(); + Node prev = null; + for (int i = 0; i < size; i++) { + Node cur = q.poll(); + if (prev != null) { prev.next = cur; } + if (cur.left != null) q.offer(cur.left); + if (cur.right != null) q.offer(cur.right); + prev = cur; + } + } + } + + } + + static class Node extends TreeNode { + + public Node next; + public Node left; + public Node right; + + public Node(int val) { + super(val); + } + + public Node(int val, TreeNode left, TreeNode right) { + super(val, left, right); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210II.java" deleted file mode 100644 index 04f2e67..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210II.java" +++ /dev/null @@ -1,61 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import java.util.LinkedList; - -/** - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 填充每个节点的下一个右侧节点指针II { - - public Node connect(Node root) { - if (root == null) return null; - bfs(root); - return root; - } - - /** - * 基于 BFS 实现二叉树层次遍历。关键在于使用一个队列存储 - */ - public void bfs(Node root) { - LinkedList queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - int size = queue.size(); - for (int i = 1; i < size; i++) { - queue.get(i - 1).next = queue.get(i); - } - - for (int i = 0; i < size; i++) { - Node node = queue.poll(); - if (node.left != null) queue.offer(node.left); - if (node.right != null) queue.offer(node.right); - } - } - } - - private static class Node { - - public int val; - public Node left; - public Node right; - public Node next; - - public Node(int val) { this.val = val; } - - public Node(int val, Node left, Node right) { - this.val = val; - this.left = left; - this.right = right; - } - - @Override - public String toString() { - return "Node{" + - "val=" + val + - '}'; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" new file mode 100644 index 0000000..382e6e9 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" @@ -0,0 +1,39 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +/** + * 222. 完全二叉树的节点个数 + * + * @author Zhang Peng + * @since 2020-07-06 + */ +public class 完全二叉树的节点个数 { + + public static void main(String[] args) { + Solution s = new Solution(); + + TreeNode root = TreeUtils.buildTree(1, 2, 3, 4, 5, 6); + Assertions.assertEquals(6, s.countNodes(root)); + + TreeNode root2 = TreeUtils.buildTree(); + Assertions.assertEquals(0, s.countNodes(root2)); + + TreeNode root3 = TreeUtils.buildTree(1); + Assertions.assertEquals(1, s.countNodes(root3)); + } + + static class Solution { + + public int countNodes(TreeNode root) { + if (root == null) { return 0; } + int left = countNodes(root.left); + int right = countNodes(root.right); + return left + right + 1; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" new file mode 100644 index 0000000..52876ae --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" @@ -0,0 +1,51 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * 404. 左叶子之和 + * + * @author Zhang Peng + * @date 2025-08-15 + */ +public class 左叶子之和 { + + public static void main(String[] args) { + Assertions.assertEquals(24, + new Solution().sumOfLeftLeaves(TreeUtils.buildTree(3, 9, 20, null, null, 15, 7))); + + Assertions.assertEquals(4, + new Solution().sumOfLeftLeaves(TreeUtils.buildTree(1, 2, 3, 4, 5))); + + Assertions.assertEquals(0, + new Solution().sumOfLeftLeaves(TreeUtils.buildTree(1))); + } + + static class Solution { + + int sum = 0; + + public int sumOfLeftLeaves(TreeNode root) { + traverse(root); + return sum; + } + + public void traverse(TreeNode root) { + if (root == null) { return; } + if (root.left != null && + root.left.left == null && root.left.right == null) { + sum += root.left.val; + } + traverse(root.left); + traverse(root.right); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" index 696a747..87944f5 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" @@ -1,11 +1,9 @@ package io.github.dunwu.algorithm.tree.btree; -import cn.hutool.json.JSONUtil; import io.github.dunwu.algorithm.tree.TreeNode; import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; -import java.util.Arrays; import java.util.List; /** @@ -18,11 +16,11 @@ public class 最大二叉树 { public static void main(String[] args) { TreeNode output = constructMaximumBinaryTree(new int[] { 3, 2, 1, 6, 0, 5 }); - List outputList = TreeUtils.toBfsValueList(output); + List outputList = TreeUtils.toValueList(output); Assertions.assertArrayEquals(new Integer[] { 6, 3, 5, null, 2, 0, null, null, 1 }, outputList.toArray()); TreeNode root = constructMaximumBinaryTree(new int[] { 3, 2, 1 }); - List list = TreeUtils.toBfsValueList(root); + List list = TreeUtils.toValueList(root); Assertions.assertArrayEquals(new Integer[] { 3, null, 2, null, 1 }, list.toArray()); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" index 821f2f2..91b4a48 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" @@ -7,6 +7,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Map; /** * 106. @@ -18,55 +19,42 @@ public class 根据前序和后序遍历构造二叉树 { public static void main(String[] args) { - TreeNode output1 = constructFromPrePost(new int[] { 1, 2, 4, 5, 3, 6, 7 }, new int[] { 4, 5, 2, 6, 7, 3, 1 }); - List list = TreeUtils.toBfsValueList(output1); - System.out.println(list); + TreeNode output1 = new Solution().constructFromPrePost(new int[] { 1, 2, 4, 5, 3, 6, 7 }, + new int[] { 4, 5, 2, 6, 7, 3, 1 }); + List list = TreeUtils.toValueList(output1); + // System.out.println(list); Assertions.assertArrayEquals(Arrays.asList(1, 2, 3, 4, 5, 6, 7).toArray(), list.toArray()); } - // 存储 postorder 中值到索引的映射 - static HashMap map = new HashMap<>(); + static class Solution { - public static TreeNode constructFromPrePost(int[] preorder, int[] postorder) { - for (int i = 0; i < postorder.length; i++) { - map.put(postorder[i], i); - } - return build(preorder, 0, preorder.length - 1, - postorder, 0, postorder.length - 1); - } + Map postPosMap = new HashMap<>(); - // 定义:根据 preorder[preBegin..preEnd] 和 postorder[postBegin..postEnd] - // 构建二叉树,并返回根节点。 - static TreeNode build(int[] preorder, int preBegin, int preEnd, - int[] postorder, int postBegin, int postEnd) { - if (preBegin > preEnd) { - return null; - } - if (preBegin == preEnd) { - return new TreeNode(preorder[preBegin]); + public TreeNode constructFromPrePost(int[] preorder, int[] postorder) { + if (preorder.length == 0 || postorder.length == 0) { return null; } + for (int i = 0; i < postorder.length; i++) { + postPosMap.put(postorder[i], i); + } + return build(preorder, 0, preorder.length - 1, + postorder, 0, postorder.length - 1); } - // root 节点对应的值就是前序遍历数组的第一个元素 - int rootVal = preorder[preBegin]; - // root.left 的值是前序遍历第二个元素 - // 通过前序和后序遍历构造二叉树的关键在于通过左子树的根节点 - // 确定 preorder 和 postorder 中左右子树的元素区间 - int nextRootVal = preorder[preBegin + 1]; - // leftRootVal 在后序遍历数组中的索引 - int nextRootPos = map.get(nextRootVal); - // 左子树的元素个数 - int leftSize = nextRootPos - postBegin + 1; - - // 先构造出当前根节点 - TreeNode root = new TreeNode(rootVal); + public TreeNode build(int[] preorder, int preBegin, int preEnd, + int[] postorder, int postBegin, int postEnd) { + if (preBegin > preEnd) { return null; } + if (preBegin == preEnd) { return new TreeNode(preorder[preBegin]); } + int rootVal = preorder[preBegin]; + int nextRootVal = preorder[preBegin + 1]; + int nextRootPos = postPosMap.get(nextRootVal); + int leftSize = nextRootPos - postBegin + 1; + TreeNode root = new TreeNode(rootVal); + root.left = build(preorder, preBegin + 1, preBegin + leftSize, + postorder, postBegin, nextRootPos); + root.right = build(preorder, preBegin + leftSize + 1, preEnd, + postorder, nextRootPos + 1, postEnd - 1); + return root; + } - // 递归构造左右子树 - // 根据左子树的根节点索引和元素个数推导左右子树的索引边界 - root.left = build(preorder, preBegin + 1, preBegin + leftSize, - postorder, postBegin, nextRootPos); - root.right = build(preorder, preBegin + leftSize + 1, preEnd, - postorder, nextRootPos + 1, postEnd - 1); - return root; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" new file mode 100644 index 0000000..f92b423 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" @@ -0,0 +1,65 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 求根节点到叶节点数字之和 + * + * @author Zhang Peng + * @date 2025-08-15 + */ +public class 求根节点到叶节点数字之和 { + + public static void main(String[] args) { + Assertions.assertEquals(25, new Solution().sumNumbers(TreeUtils.buildTree(1, 2, 3))); + Assertions.assertEquals(1026, new Solution().sumNumbers(TreeUtils.buildTree(4, 9, 0, 5, 1))); + } + + static class Solution { + + TreeNode root = null; + List nums = new LinkedList<>(); + LinkedList paths = new LinkedList<>(); + + public int sumNumbers(TreeNode root) { + this.root = root; + traverse(root); + if (nums.size() == 0) { return 0; } + return nums.stream().mapToInt(Integer::intValue).sum(); + } + + public void traverse(TreeNode node) { + if (node == null) { return; } + if (node.left == null && node.right == null) { + paths.addLast(node); + if (paths.getFirst() == this.root) { + int num = toNum(paths); + nums.add(num); + } + paths.removeLast(); + return; + } + + paths.addLast(node); + traverse(node.left); + traverse(node.right); + paths.removeLast(); + } + + public int toNum(List paths) { + if (paths.size() == 0) { return 0; } + int num = 0; + for (TreeNode node : paths) { + num = num * 10 + node.val; + } + return num; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" new file mode 100644 index 0000000..da7357e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" @@ -0,0 +1,52 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 331. 验证二叉树的前序序列化 + * + * @author Zhang Peng + * @date 2025-08-15 + */ +public class 验证二叉树的前序序列化 { + + public static void main(String[] args) { + Assertions.assertEquals(22, + new Solution().sumRootToLeaf(TreeUtils.buildTree(1, 0, 1, 0, 1, 0, 1))); + Assertions.assertEquals(0, + new Solution().sumRootToLeaf(TreeUtils.buildTree(0))); + } + + static class Solution { + + int sum = 0; + LinkedList paths = new LinkedList<>(); + + public boolean isValidSerialization(String preorder) { + + } + + public void traverse(TreeNode root) { + if (root == null) { return; } + + paths.addLast(root.val); + if (root.left == null && root.right == null) { + int num = 0; + for (Integer value : paths) { + num = num * 2 + value; + } + sum += num; + } else { + traverse(root.left); + traverse(root.right); + } + paths.removeLast(); + } + + } + +} From 2032c7ba49fbe6497952fc76c65480dd1fc85fa6 Mon Sep 17 00:00:00 2001 From: dunwu Date: Tue, 19 Aug 2025 07:45:26 +0800 Subject: [PATCH 07/21] =?UTF-8?q?feat:=20=E5=88=B7=20leetcode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\346\200\247\346\243\200\351\252\214.java" | 61 +++++++++++ ...\345\271\263\345\235\207\345\200\274.java" | 51 +++++++++ ...\345\244\247\345\256\275\345\272\246.java" | 69 ++++++++++++ ...\346\254\241\351\201\215\345\216\206.java" | 101 +++++++++--------- ...\347\202\271\346\210\220\346\236\227.java" | 58 ++++++++++ ...\346\234\200\345\244\247\345\200\274.java" | 53 +++++++++ ...\345\245\207\345\201\266\346\240\221.java" | 73 +++++++++++++ ...\347\202\271\347\232\204\345\222\214.java" | 55 ++++++++++ ...344\272\214\345\217\211\346\240\2212.java" | 47 ++++++++ ...\345\205\203\347\264\240\345\222\214.java" | 62 +++++++++++ ...\345\272\217\345\210\227\345\214\226.java" | 53 +++++---- 11 files changed, 610 insertions(+), 73 deletions(-) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\210\240\347\202\271\346\210\220\346\236\227.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\245\207\345\201\266\346\240\221.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" new file mode 100644 index 0000000..c94f788 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" @@ -0,0 +1,61 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 958. 二叉树的完全性检验 + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 二叉树的完全性检验 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.isCompleteTree(TreeUtils.buildTree(1, 2, 3, 4, 5, 6))); + Assertions.assertFalse(s.isCompleteTree(TreeUtils.buildTree(1, 2, 3, 4, 5, null, 7))); + } + + static class Solution { + + static class NodeInfo { + + public int id; + public TreeNode node; + + public NodeInfo(int id, TreeNode node) { + this.id = id; + this.node = node; + } + + } + + public boolean isCompleteTree(TreeNode root) { + + if (root == null) { return false; } + + int id = 1; + LinkedList q = new LinkedList<>(); + q.offer(new NodeInfo(id, root)); + + while (!q.isEmpty()) { + int size = q.size(); + for (int i = 0; i < size; i++) { + NodeInfo info = q.poll(); + if (info.id != id) { return false; } + if (info.node.left != null) { q.offer(new NodeInfo(id * 2, info.node.left)); } + if (info.node.right != null) { q.offer(new NodeInfo(id * 2 + 1, info.node.right)); } + id++; + } + } + return true; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" new file mode 100644 index 0000000..d66dd2d --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" @@ -0,0 +1,51 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 637. 二叉树的层平均值 + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 二叉树的层平均值 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new Double[] { 3.00000, 14.50000, 11.00000 }, + s.averageOfLevels(TreeUtils.buildTree(3, 9, 20, null, null, 15, 7)).toArray()); + Assertions.assertArrayEquals(new Double[] { 3.00000, 14.50000, 11.00000 }, + s.averageOfLevels(TreeUtils.buildTree(3, 9, 20, 15, 7)).toArray()); + } + + static class Solution { + + public List averageOfLevels(TreeNode root) { + if (root == null) { return new LinkedList<>(); } + + List res = new LinkedList<>(); + LinkedList q = new LinkedList<>(); + q.offer(root); + + while (!q.isEmpty()) { + double sum = 0; + int size = q.size(); + for (int i = 0; i < size; i++) { + TreeNode node = q.poll(); + sum += node.val; + if (node.left != null) { q.offer(node.left); } + if (node.right != null) { q.offer(node.right); } + } + res.add(sum / size); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" new file mode 100644 index 0000000..f23eff5 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" @@ -0,0 +1,69 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 104. 二叉树的最大深度 + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 二叉树的最大宽度 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(4, s.widthOfBinaryTree(TreeUtils.buildTree(1, 3, 2, 5, 3, null, 9))); + Assertions.assertEquals(7, s.widthOfBinaryTree(TreeUtils.buildTree(1, 3, 2, 5, null, null, 9, 6, null, 7))); + } + + static class Solution { + + public static class NodeInfo { + + public int id; + public TreeNode node; + + public NodeInfo(int id, TreeNode node) { + this.id = id; + this.node = node; + } + + } + + public int widthOfBinaryTree(TreeNode root) { + + int maxWidth = 0; + LinkedList q = new LinkedList<>(); + q.offer(new NodeInfo(1, root)); + + while (!q.isEmpty()) { + int size = q.size(); + int begin = 0, end = 0; + for (int i = 0; i < size; i++) { + NodeInfo cur = q.poll(); + if (i == 0) { + begin = cur.id; + } + if (i == size - 1) { + end = cur.id; + } + if (cur.node.left != null) { + q.offer(new NodeInfo(cur.id * 2, cur.node.left)); + } + if (cur.node.right != null) { + q.offer(new NodeInfo(cur.id * 2 + 1, cur.node.right)); + } + } + int width = end - begin + 1; + maxWidth = Math.max(maxWidth, width); + } + return maxWidth; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" index 52bdb3f..9d4ca7d 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" @@ -11,68 +11,65 @@ import java.util.List; /** - * 103. 二叉树的锯齿形层次遍历 算法实现 - *

- * 给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。 - *

- * 例如:给定二叉树 [3,9,20,null,null,15,7], - *

- *     3
- *    / \
- *   9  20
- *     /  \
- *    15   7
- * 
- * 返回锯齿形层次遍历如下: - *
- * [
- *   [3],
- *   [20,9],
- *   [15,7]
- * ]
- * 
+ * 103. 二叉树的锯齿形层次遍历 * - * @see 103. 二叉树的锯齿形层次遍历 + * @author Zhang Peng + * @date 2025-08-18 */ public class 二叉树的锯齿形层次遍历 { public static void main(String[] args) { - TreeNode tree = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); - List> resultList = zigzagLevelOrder(tree); - System.out.println(resultList); - List> expectList = new LinkedList<>(); - expectList.add(Arrays.asList(3)); - expectList.add(Arrays.asList(20, 9)); - expectList.add(Arrays.asList(15, 7)); - Assertions.assertArrayEquals(expectList.toArray(), resultList.toArray()); + + Solution s = new Solution(); + + TreeNode root = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); + List> expect = new LinkedList<>(); + expect.add(Arrays.asList(3)); + expect.add(Arrays.asList(20, 9)); + expect.add(Arrays.asList(15, 7)); + Assertions.assertArrayEquals(expect.toArray(), s.zigzagLevelOrder(root).toArray()); + + TreeNode root2 = TreeUtils.buildTree(1); + List> expect2 = new LinkedList<>(); + expect2.add(Arrays.asList(1)); + Assertions.assertArrayEquals(expect2.toArray(), s.zigzagLevelOrder(root2).toArray()); + + TreeNode root3 = TreeUtils.buildTree(); + List> expect3 = new LinkedList<>(); + Assertions.assertArrayEquals(expect3.toArray(), s.zigzagLevelOrder(root3).toArray()); } - public static List> zigzagLevelOrder(TreeNode root) { - List> result = new LinkedList<>(); - LinkedList queue = new LinkedList<>(); - if (root == null) return result; - queue.offer(root); - boolean reverse = false; - while (!queue.isEmpty()) { - int size = queue.size(); - List list = new ArrayList<>(); - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - if (node != null) { - list.add(node.val); - if (node.left != null) queue.offer(node.left); - if (node.right != null) queue.offer(node.right); + static class Solution { + + public List> zigzagLevelOrder(TreeNode root) { + + if (root == null) { return new LinkedList<>(); } + + LinkedList q = new LinkedList<>(); + LinkedList> res = new LinkedList<>(); + q.offer(root); + + boolean reverse = false; + while (!q.isEmpty()) { + int size = q.size(); + List cur = new LinkedList<>(); + + for (int i = 0; i < size; i++) { + TreeNode node = q.poll(); + cur.add(node.val); + if (node.left != null) { q.offer(node.left); } + if (node.right != null) { q.offer(node.right); } } + if (reverse) { + Collections.reverse(cur); + } + res.add(cur); + reverse = !reverse; } - if (reverse) { - Collections.reverse(list); - result.add(list); - } else { - result.add(list); - } - reverse = !reverse; + + return res; } - return result; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\210\240\347\202\271\346\210\220\346\236\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\210\240\347\202\271\346\210\220\346\236\227.java" new file mode 100644 index 0000000..f2e2c0e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\210\240\347\202\271\346\210\220\346\236\227.java" @@ -0,0 +1,58 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 1110. 删点成林 + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 删点成林 { + + public static void main(String[] args) { + Solution s = new Solution(); + + TreeNode input = TreeUtils.buildTree(1, 2, 3, 4, 5, 6, 7); + List output = s.delNodes(input, new int[] { 3, 5 }); + // List result1 = TreeUtils.toValueList(output); + // Assertions.assertArrayEquals(new Integer[] { 5, 4, null, 1, 3, null, null, 2 }, result1.toArray()); + + } + + static class Solution { + + List res = new LinkedList<>(); + + public List delNodes(TreeNode root, int[] to_delete) { + if (root == null) return new LinkedList<>(); + + if (isDel(root.val, to_delete)) { + if (root.left == null && root.right == null) { + root = null; + return new LinkedList<>(); + } else { + + } + } else { + res.addAll(delNodes(root.left, to_delete)); + res.addAll(delNodes(root.right, to_delete)); + } + return res; + } + + public boolean isDel(int val, int[] to_delete) { + for (int num : to_delete) { + if (val == num) return true; + } + return false; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" new file mode 100644 index 0000000..82b6964 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" @@ -0,0 +1,53 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 515. 在每个树行中找最大值 + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 在每个树行中找最大值 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new Integer[] { 1, 3, 9 }, + s.largestValues(TreeUtils.buildTree(1, 3, 2, 5, 3, null, 9)).toArray()); + Assertions.assertArrayEquals(new Integer[] { 1, 3, 9 }, + s.largestValues(TreeUtils.buildTree(1, 3)).toArray()); + } + + static class Solution { + + public List largestValues(TreeNode root) { + + if (root == null) { return new LinkedList<>(); } + + List res = new LinkedList<>(); + LinkedList q = new LinkedList<>(); + q.offer(root); + + while (!q.isEmpty()) { + int max = Integer.MIN_VALUE; + int size = q.size(); + for (int i = 0; i < size; i++) { + TreeNode node = q.poll(); + if (node == null) { continue; } + max = Math.max(max, node.val); + if (node.left != null) { q.offer(node.left); } + if (node.right != null) { q.offer(node.right); } + } + res.add(max); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\245\207\345\201\266\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\245\207\345\201\266\346\240\221.java" new file mode 100644 index 0000000..640cecd --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\245\207\345\201\266\346\240\221.java" @@ -0,0 +1,73 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 1609. 奇偶树 + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 奇偶树 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.isEvenOddTree(TreeUtils.buildTree(1, 10, 4, 3, null, 7, 9, 12, 8, 6, null, null, 2))); + Assertions.assertFalse(s.isEvenOddTree(TreeUtils.buildTree(5, 4, 2, 3, 3, 7))); + } + + static class Solution { + + public boolean isEvenOddTree(TreeNode root) { + + if (root == null) { return false; } + + LinkedList q = new LinkedList<>(); + q.offer(root); + + int depth = 0; + while (!q.isEmpty()) { + Integer lastValue = null; + int size = q.size(); + for (int i = 0; i < size; i++) { + TreeNode node = q.poll(); + if (!check(depth, node.val, lastValue)) { + return false; + } + if (node.left != null) { q.offer(node.left); } + if (node.right != null) { q.offer(node.right); } + lastValue = node.val; + } + depth++; + } + return true; + } + + public boolean check(int depth, int val, Integer lastValue) { + // 偶数下标 层上的所有节点的值都是 奇 整数,从左到右按顺序 严格递增 + // 奇数下标 层上的所有节点的值都是 偶 整数,从左到右按顺序 严格递减 + if (depth % 2 == 0) { + if (val % 2 == 0) { + return false; + } + if (lastValue != null && val <= lastValue) { + return false; + } + } else { + if (val % 2 != 0) { + return false; + } + if (lastValue != null && val >= lastValue) { + return false; + } + } + return true; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" new file mode 100644 index 0000000..42ed056 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" @@ -0,0 +1,55 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +/** + * 1302. 层数最深叶子节点的和 + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 层数最深叶子节点的和 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(15, + s.deepestLeavesSum(TreeUtils.buildTree(1, 2, 3, 4, 5, null, 6, 7, null, null, null, null, 8))); + Assertions.assertEquals(19, + s.deepestLeavesSum(TreeUtils.buildTree(6, 7, 8, 2, 7, 1, 3, 9, null, 1, 4, null, null, null, 5))); + } + + static class Solution { + + public int deepestLeavesSum(TreeNode root) { + + if (root == null) { return 0; } + + int lastLevelSum = 0; + LinkedList q = new LinkedList<>(); + q.offer(root); + + while (!q.isEmpty()) { + int sum = 0; + int size = q.size(); + for (int i = 0; i < size; i++) { + TreeNode node = q.poll(); + if (node.left == null && node.right == null) { + sum += node.val; + } + if (node.left != null) { q.offer(node.left); } + if (node.right != null) { q.offer(node.right); } + } + lastLevelSum = sum; + } + return lastLevelSum; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" new file mode 100644 index 0000000..8b0e85c --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" @@ -0,0 +1,47 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.List; + +/** + * 998. 最大二叉树 II + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 最大二叉树2 { + + public static void main(String[] args) { + Solution s = new Solution(); + + TreeNode input = TreeUtils.buildTree(4, 1, 3, null, null, 2); + TreeNode output = s.insertIntoMaxTree(input, 5); + List result1 = TreeUtils.toValueList(output); + Assertions.assertArrayEquals(new Integer[] { 5, 4, null, 1, 3, null, null, 2 }, result1.toArray()); + + TreeNode input2 = TreeUtils.buildTree(5, 2, 4, null, 1); + TreeNode output2 = s.insertIntoMaxTree(input2, 3); + List result2 = TreeUtils.toValueList(output2); + Assertions.assertArrayEquals(new Integer[] { 5, 2, 4, null, 1, null, 3 }, result2.toArray()); + } + + static class Solution { + + public TreeNode insertIntoMaxTree(TreeNode root, int val) { + if (root == null) return new TreeNode(val); + if (val > root.val) { + TreeNode node = new TreeNode(val); + node.left = root; + return node; + } else { + root.right = insertIntoMaxTree(root.right, val); + } + return root; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" new file mode 100644 index 0000000..c26f7af --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" @@ -0,0 +1,62 @@ +package io.github.dunwu.algorithm.tree.btree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import io.github.dunwu.algorithm.tree.TreeUtils; +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * 1161. 最大层内元素和 + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 最大层内元素和 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(2, + s.maxLevelSum(TreeUtils.buildTree(1, 7, 0, 7, -8, null, null))); + Assertions.assertEquals(2, + s.maxLevelSum(TreeUtils.buildTree(989, null, 10250, 98693, -89388, null, null, null, -32127))); + Assertions.assertEquals(3, + s.maxLevelSum(TreeUtils.buildTree(-100, -200, -300, -20, -5, -10, null))); + } + + static class Solution { + + public int maxLevelSum(TreeNode root) { + + if (root == null) { return 0; } + + int depth = 1; + int maxDepth = 1; + int maxSum = Integer.MIN_VALUE; + LinkedList q = new LinkedList<>(); + q.offer(root); + + while (!q.isEmpty()) { + int sum = 0; + int size = q.size(); + for (int i = 0; i < size; i++) { + TreeNode node = q.poll(); + sum += node.val; + if (node.left != null) { q.offer(node.left); } + if (node.right != null) { q.offer(node.right); } + } + if (sum > maxSum) { + maxSum = sum; + maxDepth = depth; + } + depth++; + } + return maxDepth; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" index da7357e..1662c7e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" @@ -15,36 +15,47 @@ public class 验证二叉树的前序序列化 { public static void main(String[] args) { - Assertions.assertEquals(22, - new Solution().sumRootToLeaf(TreeUtils.buildTree(1, 0, 1, 0, 1, 0, 1))); - Assertions.assertEquals(0, - new Solution().sumRootToLeaf(TreeUtils.buildTree(0))); + Assertions.assertTrue(new Solution().isValidSerialization("9,3,4,#,#,1,#,#,2,#,6,#,#")); + Assertions.assertFalse(new Solution().isValidSerialization("1,#")); + Assertions.assertFalse(new Solution().isValidSerialization("9,#,#,1")); } static class Solution { - int sum = 0; - LinkedList paths = new LinkedList<>(); + public static final String SEP = ","; + public static final String NULL = "#"; + boolean isOk = true; public boolean isValidSerialization(String preorder) { - + LinkedList nodes = new LinkedList<>(); + for (String s : preorder.split(SEP)) { + nodes.addFirst(s); + } + deserialize(nodes); + if (nodes.size() > 0) { + isOk = false; + } + return isOk; } - public void traverse(TreeNode root) { - if (root == null) { return; } - - paths.addLast(root.val); - if (root.left == null && root.right == null) { - int num = 0; - for (Integer value : paths) { - num = num * 2 + value; - } - sum += num; - } else { - traverse(root.left); - traverse(root.right); + public TreeNode deserialize(LinkedList values) { + + if (values.isEmpty()) return null; + + String value = values.removeLast(); + if (NULL.equals(value)) { + return null; + } + if (values.isEmpty() || values.size() < 2) { + isOk = false; + return null; } - paths.removeLast(); + TreeNode node = new TreeNode(Integer.parseInt(value)); + + node.left = deserialize(values); + node.right = deserialize(values); + + return node; } } From aff0a4dbe48a47f2a5a510375981eb2d836ee89e Mon Sep 17 00:00:00 2001 From: dunwu Date: Thu, 16 Oct 2025 06:30:30 +0800 Subject: [PATCH 08/21] =?UTF-8?q?feat:=20leetcode=20=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 197 ++++++++++-------- ...\345\210\206\346\237\245\346\211\276.java" | 6 +- ...\344\270\252\344\275\215\347\275\256.java" | 63 +++--- ...\347\216\260\346\254\241\346\225\260.java" | 47 +++++ ...\345\255\220\346\225\260\347\273\204.java" | 41 ++++ ...\347\232\204\346\216\222\345\210\227.java" | 75 +++++++ ...\345\244\215\345\205\203\347\264\240.java" | 35 ++++ ...45\244\215\345\205\203\347\264\240II.java" | 56 +++++ ...5\244\215\345\205\203\347\264\240III.java" | 52 +++++ ...\346\223\215\344\275\234\346\225\260.java" | 45 ++++ ...\345\274\202\344\275\215\350\257\215.java" | 70 +++++++ ...\351\225\277\345\255\220\344\270\262.java" | 56 +++++ ...\345\244\215\345\255\227\347\254\246.java" | 44 ++++ ...7\232\204\344\270\252\346\225\260III.java" | 39 ++++ ...\347\233\226\345\255\220\344\270\262.java" | 65 ++++++ ...\351\225\277\345\255\220\344\270\262.java" | 79 +++++++ ...\345\255\220\346\225\260\347\273\204.java" | 42 ++++ .../array/\344\270\221\346\225\260I.java" | 3 - ...\346\240\274\350\277\201\347\247\273.java" | 97 +++++++++ ...\345\272\217\346\225\260\347\273\204.java" | 24 ++- ...\347\232\204\346\216\222\345\210\227.java" | 53 ----- ...\345\244\215\345\205\203\347\264\240.java" | 42 ---- ...\347\272\277\346\216\222\345\272\217.java" | 42 ++-- ...\347\233\226\345\255\220\344\270\262.java" | 83 -------- ...\345\205\261\345\211\215\347\274\200.java" | 4 +- ...\346\226\207\345\255\220\344\270\262.java" | 40 ++-- ...\350\276\211\344\270\211\350\247\222.java" | 2 - ...\345\257\271\346\225\260\345\255\227.java" | 1 - ...\345\244\215\345\205\203\347\264\240.java" | 15 +- ...\350\275\254\351\223\276\350\241\250.java" | 40 ++-- ...50\275\254\351\223\276\350\241\250II.java" | 39 ++-- ...\346\226\207\351\223\276\350\241\250.java" | 29 +-- 32 files changed, 1082 insertions(+), 444 deletions(-) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\345\210\206\346\237\245\346\211\276.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\344\272\214\345\210\206\346\237\245\346\211\276.java" (85%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" (56%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\273\237\350\256\241\347\233\256\346\240\207\346\210\220\347\273\251\347\232\204\345\207\272\347\216\260\346\254\241\346\225\260.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240II.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240III.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260III.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" diff --git a/README.md b/README.md index cc061c8..b98aa37 100644 --- a/README.md +++ b/README.md @@ -64,25 +64,25 @@ | 题目 | 掌握度 | | ------------------------------------------------------------------------------------------------------------------ | ------ | -| [141. 环形链表](https://leetcode.cn/problems/linked-list-cycle/) | 已掌握 | -| [142. 环形链表 II](https://leetcode.cn/problems/linked-list-cycle-ii/) | 已掌握 | -| [160. 相交链表](https://leetcode.cn/problems/intersection-of-two-linked-lists/) | 已掌握 | -| [19. 删除链表的倒数第 N 个结点](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/) | 已掌握 | -| [21. 合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/) | 已掌握 | -| [23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/) | 已掌握 | -| [86. 分隔链表](https://leetcode.cn/problems/partition-list/) | 已掌握 | -| [876. 链表的中间结点](https://leetcode.cn/problems/middle-of-the-linked-list/) | 已掌握 | -| [剑指 Offer 22. 链表中倒数第 k 个节点](https://leetcode.cn/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/) | 已掌握 | +| [141. 环形链表](https://leetcode.cn/problems/linked-list-cycle/) | ✔️ | +| [142. 环形链表 II](https://leetcode.cn/problems/linked-list-cycle-ii/) | ✔️ | +| [160. 相交链表](https://leetcode.cn/problems/intersection-of-two-linked-lists/) | ✔️ | +| [19. 删除链表的倒数第 N 个结点](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/) | ✔️ | +| [21. 合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/) | ✔️ | +| [23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/) | ✔️ | +| [86. 分隔链表](https://leetcode.cn/problems/partition-list/) | ✔️ | +| [876. 链表的中间结点](https://leetcode.cn/problems/middle-of-the-linked-list/) | ✔️ | +| [剑指 Offer 22. 链表中倒数第 k 个节点](https://leetcode.cn/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/) | ✔️ | #### 【练习】链表双指针经典习题 | 题目 | 掌握度 | | ------------------------------------------------------------------------------------------------------ | ------ | -| [82. 删除排序链表中的重复元素 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/) | 已掌握 | -| [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | 未掌握 | -| [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | 未掌握 | -| [2. 两数相加](https://leetcode.cn/problems/add-two-numbers/) | 已掌握 | -| [445. 两数相加 II](https://leetcode.cn/problems/add-two-numbers-ii/) | 已掌握 | +| [82. 删除排序链表中的重复元素 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/) | ✔️ | +| [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | ❌ | +| [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | ❌ | +| [2. 两数相加](https://leetcode.cn/problems/add-two-numbers/) | ✔️ | +| [445. 两数相加 II](https://leetcode.cn/problems/add-two-numbers-ii/) | ✔️ | #### 如何判断回文链表 @@ -90,9 +90,9 @@ | 题目 | 掌握度 | | ------------------------------------------------------------------------------ | ------ | -| [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/) | 未掌握 | -| [92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/) | 不熟练 | -| [25. K 个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group/) | 不熟练 | +| [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/) | ❌ | +| [92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/) | ❗ | +| [25. K 个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group/) | ❗ | ### 数组 @@ -100,61 +100,78 @@ | 题目 | 掌握度 | | ------------------------------------------------------------------------------------------------------ | ------ | -| [26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/) | 已掌握 | -| [27. 移除元素](https://leetcode.cn/problems/remove-element/) | 已掌握 | -| [283. 移动零](https://leetcode.cn/problems/move-zeroes/) | 已掌握 | -| [704. 二分查找](https://leetcode.cn/problems/binary-search/) | 已掌握 | -| [1. 两数之和](https://leetcode.cn/problems/two-sum/) | 已掌握 | -| [167. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/) | 已掌握 | -| [LCR 179. 查找总价格为目标值的两个商品](https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/) | 已掌握 | -| [LCR 006. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/kLl5u1/) | 已掌握 | -| [344. 反转字符串](https://leetcode.cn/problems/reverse-string/) | 已掌握 | -| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 未掌握 | +| [26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/) | ✔️ | +| [27. 移除元素](https://leetcode.cn/problems/remove-element/) | ✔️ | +| [283. 移动零](https://leetcode.cn/problems/move-zeroes/) | ✔️ | +| [704. 二分查找](https://leetcode.cn/problems/binary-search/) | ✔️ | +| [1. 两数之和](https://leetcode.cn/problems/two-sum/) | ✔️ | +| [167. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/) | ✔️ | +| [LCR 179. 查找总价格为目标值的两个商品](https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/) | ✔️ | +| [LCR 006. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/kLl5u1/) | ✔️ | +| [344. 反转字符串](https://leetcode.cn/problems/reverse-string/) | ✔️ | +| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | ❌ | + +#### 数组双指针经典习题 + +| 题目 | 掌握度 | +| -------------------------------------------------------------------------------------------------------------------------- | ------ | +| [80. 删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/) | ✔️ | +| [125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/) | ✔️ | +| [75. 颜色分类](https://leetcode.cn/problems/sort-colors/) | ✔️ | +| [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/) | ❗ | +| [977. 有序数组的平方](https://labuladong.online/algo/problem-set/array-two-pointers/#slug_squares-of-a-sorted-array) | ✔️ | +| [1329. 将矩阵按对角线排序](https://labuladong.online/algo/problem-set/array-two-pointers/#slug_sort-the-matrix-diagonally) | ❗ | +| [1260. 二维网格迁移](https://leetcode.cn/problems/shift-2d-grid/) | ❌ | +| [867. 转置矩阵](https://labuladong.online/algo/problem-set/array-two-pointers/#slug_transpose-matrix) | ✔️ | +| [14. 最长公共前缀](https://leetcode.cn/problems/longest-common-prefix/) | ✔️ | #### 二维数组的花式遍历技巧 | 题目 | 掌握度 | | ----------------------------------------------------------------- | ------ | -| [48. 旋转图像](https://leetcode.cn/problems/rotate-image/) | 未掌握 | -| [54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/) | 未掌握 | -| [59. 螺旋矩阵 II](https://leetcode.cn/problems/spiral-matrix-ii/) | 未掌握 | +| [48. 旋转图像](https://leetcode.cn/problems/rotate-image/) | ❌ | +| [54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/) | ❌ | +| [59. 螺旋矩阵 II](https://leetcode.cn/problems/spiral-matrix-ii/) | ❌ | -#### 数组双指针经典习题 +#### 滑动窗口算法 | 题目 | 掌握度 | | -------------------------------------------------------------------------------------------------------------------------- | ------ | -| [80. 删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/) | 已掌握 | -| [125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/) | 已掌握 | -| [75. 颜色分类](https://leetcode.cn/problems/sort-colors/) | 已掌握 | -| [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/) | 未掌握 | -| [977. 有序数组的平方](https://labuladong.online/algo/problem-set/array-two-pointers/#slug_squares-of-a-sorted-array) | 已掌握 | -| [1329. 将矩阵按对角线排序](https://labuladong.online/algo/problem-set/array-two-pointers/#slug_sort-the-matrix-diagonally) | 未掌握 | -| [1260. 二维网格迁移](https://leetcode.cn/problems/shift-2d-grid/) | | -| [867. 转置矩阵](https://labuladong.online/algo/problem-set/array-two-pointers/#slug_transpose-matrix) | 已掌握 | -| [14. 最长公共前缀](https://leetcode.cn/problems/longest-common-prefix/) | 已掌握 | - -#### 滑动窗口算法核心代码模板 - -| 题目 | 掌握度 | -| -------------------------------------------------------------------------- | ------ | -| [76. 最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring/) | 未掌握 | -| [567. 字符串的排列](https://leetcode.cn/problems/permutation-in-string/) | | -| | | - -#### 二分搜索 +| [3. 无重复字符的最长子串](https://leetcode.cn/problems/longest-substring-without-repeating-characters/) | ✔️ | +| [438. 找到字符串中所有字母异位词](https://leetcode.cn/problems/find-all-anagrams-in-a-string/) | ❗ | +| [567. 字符串的排列](https://leetcode.cn/problems/permutation-in-string/) | ❗ | +| [76. 最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring/) | ❌ | +| [1658. 将 x 减到 0 的最小操作数](https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/) | ❌ | +| [713. 乘积小于 K 的子数组](https://leetcode.cn/problems/subarray-product-less-than-k/) | ❌ | +| [1004. 最大连续1的个数 III](https://leetcode.cn/problems/max-consecutive-ones-iii/) | ✔️ | +| [424. 替换后的最长重复字符](https://leetcode.cn/problems/longest-repeating-character-replacement/) | ❗ | +| [219. 存在重复元素 II](https://leetcode.cn/problems/contains-duplicate-ii/) | ❗ | +| [220. 存在重复元素 III](https://labuladong.online/algo/problem-set/sliding-window/#slug_contains-duplicate-iii) | ❌ | +| [209. 长度最小的子数组](https://leetcode.cn/problems/minimum-size-subarray-sum/) | ❌ | +| [395. 至少有 K 个重复字符的最长子串](https://leetcode.cn/problems/longest-substring-with-at-least-k-repeating-characters/) | ❌ | + +#### 二分查找算法 + +| 题目 | 掌握度 | +| :-------------------------------------------------------------------------------------------------------------------------------------- | :----- | +| [34. 在排序数组中查找元素的第一个和最后一个位置](https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/) | ❗ | +| [704. 二分查找](https://leetcode.cn/problems/binary-search/) | ✔️ | +| [LCR 172. 统计目标成绩的出现次数](https://leetcode.cn/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/) | ✔️ | + +#### 索 | 题目 | 掌握度 | | ------------------------------------------------------------------------------------------------------ | ------ | -| [875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) | 未掌握 | -| [1011. 在 D 天内送达包裹的能力](https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/) | 未掌握 | -| [410. 分割数组的最大值](https://leetcode.cn/problems/split-array-largest-sum/) | 未掌握 | +| [875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) | ❌ | +| [1011. 在 D 天内送达包裹的能力](https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/) | ❌ | +| [410. 分割数组的最大值](https://leetcode.cn/problems/split-array-largest-sum/) | ❌ | #### 前缀和数组 | 题目 | 掌握度 | | ---------------------------------------------------------------------------------------------- | ------ | -| [303. 区域和检索 - 数组不可变](https://leetcode.cn/problems/range-sum-query-immutable/) | 不熟练 | -| [304. 二维区域和检索 - 矩阵不可变](https://leetcode.cn/problems/range-sum-query-2d-immutable/) | 未掌握 | +| [303. 区域和检索 - 数组不可变](https://leetcode.cn/problems/range-sum-query-immutable/) | ❗ | +| [304. 二维区域和检索 - 矩阵不可变](https://leetcode.cn/problems/range-sum-query-2d-immutable/) | ❌ | #### 差分数组 @@ -170,18 +187,18 @@ | 题目 | 掌握度 | | ------------------------------------------------------------------------------- | ------ | -| [225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/) | 不熟练 | -| [232. 用栈实现队列](https://leetcode.cn/problems/implement-queue-using-stacks/) | 已掌握 | +| [225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/) | ❗ | +| [232. 用栈实现队列](https://leetcode.cn/problems/implement-queue-using-stacks/) | ✔️ | #### 栈的经典习题 | 题目 | 掌握度 | | --------------------------------------------------------------------------------------- | ------ | -| [71. 简化路径](https://leetcode.cn/problems/simplify-path/) | 不熟练 | -| [143. 重排链表](https://leetcode.cn/problems/reorder-list/) | 已掌握 | -| [20. 有效的括号](https://leetcode.cn/problems/valid-parentheses/) | 已掌握 | -| [150. 逆波兰表达式求值](https://leetcode.cn/problems/evaluate-reverse-polish-notation/) | 已掌握 | -| [388. 文件的最长绝对路径](https://leetcode.cn/problems/longest-absolute-file-path/) | 未掌握 | +| [71. 简化路径](https://leetcode.cn/problems/simplify-path/) | ❗ | +| [143. 重排链表](https://leetcode.cn/problems/reorder-list/) | ✔️ | +| [20. 有效的括号](https://leetcode.cn/problems/valid-parentheses/) | ✔️ | +| [150. 逆波兰表达式求值](https://leetcode.cn/problems/evaluate-reverse-polish-notation/) | ✔️ | +| [388. 文件的最长绝对路径](https://leetcode.cn/problems/longest-absolute-file-path/) | ❌ | | [155. 最小栈](https://leetcode.cn/problems/min-stack/) | | | [895. 最大频率栈](https://leetcode.cn/problems/maximum-frequency-stack/) | | @@ -189,7 +206,7 @@ | 题目 | 掌握度 | | --------------------------------------------------------------------------- | ------ | -| [933. 最近的请求次数](https://leetcode.cn/problems/number-of-recent-calls/) | 不熟练 | +| [933. 最近的请求次数](https://leetcode.cn/problems/number-of-recent-calls/) | ❗ | | [622. 设计循环队列](https://leetcode.cn/problems/design-circular-queue/) | | | | | | | | @@ -212,42 +229,42 @@ | 题目 | 掌握度 | | ------------------------------------------------------------------------------------------------------------------------ | ------ | -| [104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) | 已掌握 | -| [111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/) | 已掌握 | -| [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/) | 已掌握 | -| [94. 二叉树的中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal/) | 已掌握 | -| [145. 二叉树的后序遍历](https://leetcode.cn/problems/binary-tree-postorder-traversal/) | 已掌握 | -| [102. 二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal/) | 不熟练 | -| [107. 二叉树的层序遍历 II](https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/) | 已掌握 | -| [543. 二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree/) | 未掌握 | -| [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/) | 已掌握 | -| [116. 填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) | 已掌握 | -| [117. 填充每个节点的下一个右侧节点指针 II](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/) | 已掌握 | -| [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/) | 已掌握 | -| [654. 最大二叉树](https://leetcode.cn/problems/maximum-binary-tree/) | 已掌握 | -| [297. 二叉树的序列化与反序列化](https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/) | 未掌握 | -| [222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/) | 已掌握 | +| [104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) | ✔️ | +| [111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/) | ✔️ | +| [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/) | ✔️ | +| [94. 二叉树的中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal/) | ✔️ | +| [145. 二叉树的后序遍历](https://leetcode.cn/problems/binary-tree-postorder-traversal/) | ✔️ | +| [102. 二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal/) | ❗ | +| [107. 二叉树的层序遍历 II](https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/) | ✔️ | +| [543. 二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree/) | ❌ | +| [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/) | ✔️ | +| [116. 填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) | ✔️ | +| [117. 填充每个节点的下一个右侧节点指针 II](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/) | ✔️ | +| [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/) | ✔️ | +| [654. 最大二叉树](https://leetcode.cn/problems/maximum-binary-tree/) | ✔️ | +| [297. 二叉树的序列化与反序列化](https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/) | ❌ | +| [222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/) | ✔️ | #### 用「遍历」思维解题 | 题目 | 掌握度 | | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -| [257. 二叉树的所有路径](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_binary-tree-paths) | 未掌握 | -| [129. 求根节点到叶节点数字之和](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_sum-root-to-leaf-numbers) | 已掌握 | -| [199. 二叉树的右视图](https://leetcode.cn/problems/binary-tree-right-side-view/) | 已掌握 | -| [988. 从叶结点开始的最小字符串](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_smallest-string-starting-from-leaf) | 已掌握 | -| [1022. 从根到叶的二进制数之和](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_sum-of-root-to-leaf-binary-numbers) | 已掌握 | -| [1457. 二叉树中的伪回文路径](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_pseudo-palindromic-paths-in-a-binary-tree) | 已掌握 | -| [404. 左叶子之和](https://leetcode.cn/problems/sum-of-left-leaves/) | 已掌握 | -| [623. 在二叉树中增加一行](https://leetcode.cn/problems/add-one-row-to-tree/) | 已掌握 | +| [257. 二叉树的所有路径](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_binary-tree-paths) | ❌ | +| [129. 求根节点到叶节点数字之和](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_sum-root-to-leaf-numbers) | ✔️ | +| [199. 二叉树的右视图](https://leetcode.cn/problems/binary-tree-right-side-view/) | ✔️ | +| [988. 从叶结点开始的最小字符串](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_smallest-string-starting-from-leaf) | ✔️ | +| [1022. 从根到叶的二进制数之和](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_sum-of-root-to-leaf-binary-numbers) | ✔️ | +| [1457. 二叉树中的伪回文路径](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_pseudo-palindromic-paths-in-a-binary-tree) | ✔️ | +| [404. 左叶子之和](https://leetcode.cn/problems/sum-of-left-leaves/) | ✔️ | +| [623. 在二叉树中增加一行](https://leetcode.cn/problems/add-one-row-to-tree/) | ✔️ | #### 用「分解」思维解题 | 题目 | 掌握度 | | ------------------------------------------------------------------------------------------------------------------------------- | ------ | -| [105. 从前序与中序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) | 已掌握 | -| [106. 从中序与后序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) | 已掌握 | -| [889. 根据前序和后序遍历构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-postorder-traversal/) | 已掌握 | +| [105. 从前序与中序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) | ✔️ | +| [106. 从中序与后序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) | ✔️ | +| [889. 根据前序和后序遍历构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-postorder-traversal/) | ✔️ | | [331. 验证二叉树的前序序列化](https://leetcode.cn/problems/verify-preorder-serialization-of-a-binary-tree/) | | | [894. 所有可能的真二叉树](https://leetcode.cn/problems/all-possible-full-binary-trees/) | | | [998. 最大二叉树 II](https://leetcode.cn/problems/maximum-binary-tree-ii/) | | @@ -276,7 +293,7 @@ | 题目 | 掌握度 | | --------------------------------------------------------------------------- | ------ | -| [23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/) | 已掌握 | +| [23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/) | ✔️ | ## 📚 资料 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\345\210\206\346\237\245\346\211\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\344\272\214\345\210\206\346\237\245\346\211\276.java" similarity index 85% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\345\210\206\346\237\245\346\211\276.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\344\272\214\345\210\206\346\237\245\346\211\276.java" index 867a875..feae11a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\345\210\206\346\237\245\346\211\276.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\344\272\214\345\210\206\346\237\245\346\211\276.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.array; +package io.github.dunwu.algorithm.array.bsearch; import org.junit.jupiter.api.Assertions; @@ -19,12 +19,12 @@ public static int search(int[] nums, int target) { if (nums == null || nums.length == 0) return -1; int left = 0, right = nums.length - 1; while (left <= right) { - int mid = (left + right) / 2; + int mid = left + (right - left) / 2; if (nums[mid] == target) { return mid; } else if (nums[mid] < target) { left = mid + 1; - } else { + } else if (nums[mid] > target) { right = mid - 1; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" similarity index 56% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" index 9072d40..77a838c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" @@ -1,18 +1,21 @@ -package io.github.dunwu.algorithm.array; +package io.github.dunwu.algorithm.array.bsearch; import org.junit.jupiter.api.Assertions; /** + * 34.在排序数组中查找元素的第一个和最后一个位置 + * * @author Zhang Peng * @since 2020-06-05 */ public class 在排序数组中查找元素的第一个和最后一个位置 { public static void main(String[] args) { - Assertions.assertArrayEquals(new int[] { 3, 4 }, - searchRange(new int[] { 5, 7, 7, 8, 8, 10 }, 8)); - Assertions.assertArrayEquals(new int[] { -1, -1 }, - searchRange(new int[] { 5, 7, 7, 8, 8, 10 }, 6)); + Assertions.assertArrayEquals(new int[] { 3, 4 }, searchRange(new int[] { 5, 7, 7, 8, 8, 10 }, 8)); + Assertions.assertArrayEquals(new int[] { -1, -1 }, searchRange(new int[] { 5, 7, 7, 8, 8, 10 }, 6)); + Assertions.assertArrayEquals(new int[] { -1, -1 }, searchRange(new int[] {}, 0)); + Assertions.assertArrayEquals(new int[] { 0, 0 }, searchRange(new int[] { 1 }, 1)); Assertions.assertEquals(-1, searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 3)); Assertions.assertEquals(0, searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 5)); @@ -27,64 +30,50 @@ public static void main(String[] args) { Assertions.assertEquals(2, searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 7)); } - /** - * 题目:34. - * 在排序数组中查找元素的第一个和最后一个位置 - *

- * 给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。 - *

- * 如果数组中不存在目标值,返回 [-1, -1]。 - */ public static int[] searchRange(int[] nums, int target) { - final int[] notFoundResult = { -1, -1 }; - if (nums == null || nums.length == 0) { return notFoundResult; } - + final int[] notFound = { -1, -1 }; + if (nums == null || nums.length == 0) { + return notFound; + } int begin = searchLeft(nums, target); - if (begin == nums.length || nums[begin] != target) { return notFoundResult; } int end = searchRight(nums, target); return new int[] { begin, end }; } - public static int searchLeft(int[] nums, int target) { - if (nums == null || nums.length == 0) { return -1; } - + static int searchLeft(int[] nums, int target) { int left = 0, right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; - if (nums[mid] < target) { - left = mid + 1; - } else if (nums[mid] > target) { + if (nums[mid] == target) { right = mid - 1; - } else if (nums[mid] == target) { + } else if (nums[mid] > target) { right = mid - 1; + } else if (nums[mid] < target) { + left = mid + 1; } } - - if (left >= nums.length || nums[left] != target) { + if (left < 0 || left >= nums.length) { return -1; } - return left; + return nums[left] == target ? left : -1; } - public static int searchRight(int[] nums, int target) { - if (nums == null || nums.length == 0) { return -1; } - + static int searchRight(int[] nums, int target) { int left = 0, right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; - if (nums[mid] > target) { - right = mid - 1; - } else if (nums[mid] < target) { + if (nums[mid] == target) { left = mid + 1; - } else if (nums[mid] == target) { + } else if (nums[mid] < target) { left = mid + 1; + } else if (nums[mid] > target) { + right = mid - 1; } } - - if (right < 0 || nums[right] != target) { + if (right < 0 || right >= nums.length) { return -1; } - return right; + return nums[right] == target ? right : -1; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\273\237\350\256\241\347\233\256\346\240\207\346\210\220\347\273\251\347\232\204\345\207\272\347\216\260\346\254\241\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\273\237\350\256\241\347\233\256\346\240\207\346\210\220\347\273\251\347\232\204\345\207\272\347\216\260\346\254\241\346\225\260.java" new file mode 100644 index 0000000..e00d4db --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\273\237\350\256\241\347\233\256\346\240\207\346\210\220\347\273\251\347\232\204\345\207\272\347\216\260\346\254\241\346\225\260.java" @@ -0,0 +1,47 @@ +package io.github.dunwu.algorithm.array.bsearch; + +import org.junit.jupiter.api.Assertions; + +/** + * LCR 172. 统计目标成绩的出现次数 + * + * @author Zhang Peng + * @date 2025-10-15 + */ +public class 统计目标成绩的出现次数 { + + public static void main(String[] args) { + Assertions.assertEquals(3, countTarget(new int[] { 2, 2, 3, 4, 4, 4, 5, 6, 6, 8 }, 4)); + Assertions.assertEquals(0, countTarget(new int[] { 1, 2, 3, 5, 7, 9 }, 6)); + } + + public static int countTarget(int[] scores, int target) { + int result = search(scores, 0, scores.length - 1, target); + return result == -1 ? 0 : result; + } + + static int search(int[] scores, int left, int right, int target) { + if (left > right) { + return -1; + } + int mid = left + (right - left) / 2; + if (scores[mid] == target) { + int lcnt = search(scores, left, mid - 1, target); + int rcnt = search(scores, mid + 1, right, target); + int cnt = 1; + if (lcnt > 0) { + cnt += lcnt; + } + if (rcnt > 0) { + cnt += rcnt; + } + return cnt; + } else if (scores[mid] < target) { + return search(scores, mid + 1, right, target); + } else if (scores[mid] > target) { + return search(scores, left, mid - 1, target); + } + return -1; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" new file mode 100644 index 0000000..74eef85 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" @@ -0,0 +1,41 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +/** + * 713. 乘积小于 K 的子数组 + * + * @author Zhang Peng + * @date 2025-10-14 + */ +public class 乘积小于K的子数组 { + + public static void main(String[] args) { + Assertions.assertEquals(8, numSubarrayProductLessThanK(new int[] { 10, 5, 2, 6 }, 100)); + Assertions.assertEquals(0, numSubarrayProductLessThanK(new int[] { 1, 2, 3 }, 0)); + } + + public static int numSubarrayProductLessThanK(int[] nums, int k) { + if (k <= 1) return 0; + + // 窗口游标 + int left = 0, right = 0; + // 窗口乘积 + int multi = 1; + // 符合要求的结果 + int result = 0; + while (right < nums.length) { + // 扩大窗口 + multi *= nums[right++]; + + while (multi >= k && left < right) { + multi = multi / nums[left++]; + } + + result += right - left; + // System.out.format("left: %d, right: %d\n", left, right); + } + return result; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" new file mode 100644 index 0000000..c7b51f3 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" @@ -0,0 +1,75 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; + +/** + * 567. 字符串的排列 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 字符串的排列 { + + public static void main(String[] args) { + Assertions.assertTrue(checkInclusion("ab", "eidbaooo")); + Assertions.assertFalse(checkInclusion("ab", "eidboaoo")); + } + + public static boolean checkInclusion(String s1, String s2) { + + // 定义 need 和 window + HashMap need = new HashMap<>(); + HashMap window = new HashMap<>(); + for (int i = 0; i < s1.length(); i++) { + need.put(s1.charAt(i), need.getOrDefault(s1.charAt(i), 0) + 1); + } + + // 符合 need 排列的字符个数 + int valid = 0; + // 扫描 s 的窗口游标 + int left = 0, right = 0; + // 符合要求的子串窗口信息 + int start = 0, len = Integer.MAX_VALUE; + while (right < s2.length()) { + char r = s2.charAt(right); + // 窗口扩展 + right++; + // 窗口 window 满足 need 的一系列更新 + if (need.containsKey(r)) { + window.put(r, window.getOrDefault(r, 0) + 1); + if (window.get(r).equals(need.get(r))) { + valid++; + } + } + + // 判断窗口左边界是否收缩 + while (valid == need.size()) { + // 更新最小窗口信息 + if (right - left < len) { + start = left; + len = right - left; + System.out.format("窗口:[left: %s, right: %s), 子串:%s\n", left, right, + s2.substring(start, right)); + if (len == s1.length()) { + return true; + } + } + + // 窗口左边界收缩 + char l = s2.charAt(left); + left++; + if (need.containsKey(l)) { + if (window.get(l).equals(need.get(l))) { + valid--; + } + window.put(l, window.get(l) - 1); + } + } + } + + return false; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" new file mode 100644 index 0000000..71601db --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" @@ -0,0 +1,35 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashSet; +import java.util.Set; + +/** + * 217. 存在重复元素 + * + * @author Zhang Peng + * @since 2020-06-05 + */ +public class 存在重复元素 { + + public static void main(String[] args) { + Assertions.assertTrue(containsDuplicate(new int[] { 1, 2, 3, 1 })); + Assertions.assertFalse(containsDuplicate(new int[] { 1, 2, 3, 4 })); + Assertions.assertTrue(containsDuplicate(new int[] { 1, 1, 1, 3, 3, 4, 3, 2, 4, 2 })); + } + + public static boolean containsDuplicate(int[] nums) { + if (nums == null || nums.length <= 1) { + return false; + } + Set set = new HashSet<>(); + for (int num : nums) { + if (!set.add(num)) { + return true; + } + } + return false; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240II.java" new file mode 100644 index 0000000..0791392 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240II.java" @@ -0,0 +1,56 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashSet; +import java.util.Set; + +/** + * 219. 存在重复元素 II + * + * @author Zhang Peng + * @date 2025-10-15 + */ +public class 存在重复元素II { + + public static void main(String[] args) { + Assertions.assertTrue(containsNearbyDuplicate(new int[] { 1, 2, 3, 1 }, 3)); + Assertions.assertTrue(containsNearbyDuplicate(new int[] { 1, 0, 1, 1 }, 1)); + Assertions.assertFalse(containsNearbyDuplicate(new int[] { 1, 2, 3, 1, 2, 3 }, 2)); + Assertions.assertTrue(containsNearbyDuplicate(new int[] { 99, 99 }, 2)); + } + + public static boolean containsNearbyDuplicate(int[] nums, int k) { + if (nums == null || nums.length < 2) return false; + int left = 0, right = 0; + Set set = new HashSet<>(); + while (right < nums.length) { + if (!set.add(nums[right])) { + return true; + } + right++; + + if (right - left > k) { + set.remove(nums[left]); + left++; + } + } + return false; + } + + /** + * 效率为 O(N^2) + */ + public static boolean containsNearbyDuplicate2(int[] nums, int k) { + if (nums == null || nums.length < 2) return false; + for (int i = 0; i < nums.length; i++) { + for (int j = i + 1; j < nums.length; j++) { + if (nums[i] == nums[j] && Math.abs(j - i) <= k) { + return true; + } + } + } + return false; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240III.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240III.java" new file mode 100644 index 0000000..1ea0044 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240III.java" @@ -0,0 +1,52 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +import java.util.TreeSet; + +/** + * 220. 存在重复元素 III + * + * @author Zhang Peng + * @date 2025-10-15 + */ +public class 存在重复元素III { + + public static void main(String[] args) { + Assertions.assertTrue(containsNearbyAlmostDuplicate(new int[] { 1, 2, 3, 1 }, 3, 0)); + Assertions.assertFalse(containsNearbyAlmostDuplicate(new int[] { 1, 5, 9, 1, 5, 9 }, 2, 3)); + Assertions.assertTrue(containsNearbyAlmostDuplicate(new int[] { 1, 2, 2, 3, 4, 5 }, 3, 0)); + } + + public static boolean containsNearbyAlmostDuplicate(int[] nums, int indexDiff, int valueDiff) { + TreeSet window = new TreeSet<>(); + int left = 0, right = 0; + while (right < nums.length) { + + // 窗口大小小于等于 indexDiff,且窗口中存在两个不同元素之差小于 valueDiff + + // 为了防止 i == j,所以在扩大窗口之前先判断是否有符合题意的索引对 (i, j) + // 查找略大于 nums[right] 的那个元素 + Integer ceiling = window.ceiling(nums[right]); + if (ceiling != null && Math.abs(ceiling - nums[right]) <= valueDiff) { + return true; + } + // 查找略小于 nums[right] 的那个元素 + Integer floor = window.floor(nums[right]); + if (floor != null && Math.abs(floor - nums[right]) <= valueDiff) { + return true; + } + + // 当窗口大小小于等于 indexDiff 时,扩大窗口 + window.add(nums[right++]); + + // 当窗口大小大于 indexDiff 时,缩小窗口 + while (right - left > indexDiff) { + // 缩小窗口 + window.remove(nums[left++]); + } + } + return false; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" new file mode 100644 index 0000000..1763320 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" @@ -0,0 +1,45 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +/** + * 1658. 将 x 减到 0 的最小操作数 + * + * @author Zhang Peng + * @date 2025-10-14 + */ +public class 将x减到0的最小操作数 { + + public static void main(String[] args) { + Assertions.assertEquals(2, minOperations(new int[] { 1, 1, 4, 2, 3 }, 5)); + Assertions.assertEquals(-1, minOperations(new int[] { 5, 6, 7, 8, 9 }, 4)); + Assertions.assertEquals(5, minOperations(new int[] { 3, 2, 20, 1, 1, 3 }, 10)); + } + + public static int minOperations(int[] nums, int x) { + int sum = 0; + for (int num : nums) { + sum += num; + } + int target = sum - x; + int windowSum = 0; + int maxLen = Integer.MIN_VALUE; + int left = 0, right = 0; + + while (right < nums.length) { + windowSum += nums[right]; + right++; + + while (windowSum > target && left < right) { + windowSum -= nums[left]; + left++; + } + + if (windowSum == target) { + maxLen = Math.max(maxLen, right - left); + } + } + return maxLen == Integer.MIN_VALUE ? -1 : nums.length - maxLen; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" new file mode 100644 index 0000000..efa3b6a --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" @@ -0,0 +1,70 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * 438. 找到字符串中所有字母异位词 + * + * @author Zhang Peng + * @date 2025-10-14 + */ +public class 找到字符串中所有字母异位词 { + + public static void main(String[] args) { + Assertions.assertArrayEquals(new Integer[] { 0, 6 }, findAnagrams("cbaebabacd", "abc").toArray()); + Assertions.assertArrayEquals(new Integer[] { 0, 1, 2 }, findAnagrams("abab", "ab").toArray()); + } + + public static List findAnagrams(String s, String p) { + // 定义窗口:条件窗口、临时窗口 + HashMap need = new HashMap<>(p.length()); + HashMap window = new HashMap<>(p.length()); + for (char c : p.toCharArray()) { + need.put(c, need.getOrDefault(c, 0) + 1); + } + + // 符合条件字符数 + int valid = 0; + // 窗口边界 + int left = 0, right = 0; + // 符合条件的子串起始位置(长度固定,和 p 相等) + List res = new ArrayList<>(); + + while (right < s.length()) { + char r = s.charAt(right); + // 窗口扩展 + right++; + if (need.containsKey(r)) { + window.put(r, window.getOrDefault(r, 0) + 1); + if (window.get(r).equals(need.get(r))) { + valid++; + } + } + + while (valid == need.size()) { + // 更新信息 + if (right - left == p.length()) { + // System.out.format("窗口:[left: %s, right: %s), 子串:%s\n", + // left, right, s.substring(left, left + p.length())); + res.add(left); + } + + char l = s.charAt(left); + // 窗口收缩 + left++; + if (need.containsKey(l)) { + if (window.get(l).equals(need.get(l))) { + valid--; + } + window.put(l, window.get(l) - 1); + } + } + } + return res; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" new file mode 100644 index 0000000..ab45d37 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" @@ -0,0 +1,56 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashSet; + +/** + * 3. 无重复字符的最长子串 + * + * @author Zhang Peng + * @date 2025-10-14 + */ +public class 无重复字符的最长子串 { + + public static void main(String[] args) { + Assertions.assertEquals(3, lengthOfLongestSubstring("abcabcbb")); + Assertions.assertEquals(1, lengthOfLongestSubstring("bbbbb")); + Assertions.assertEquals(3, lengthOfLongestSubstring("pwwkew")); + Assertions.assertEquals(2, lengthOfLongestSubstring("aab")); + } + + public static int lengthOfLongestSubstring(String s) { + // 【debug】 + System.out.println("============> 原始字符串:" + s); + // 定义窗口 + HashSet window = new HashSet<>(); + // 窗口边界 + int left = 0, right = 0; + int max = 0; + + while (right < s.length()) { + char r = s.charAt(right); + // 扩大边界 + right++; + if (window.contains(r)) { + while (r != s.charAt(left)) { + char l = s.charAt(left); + window.remove(l); + left++; + } + char l = s.charAt(left); + left++; + } else { + window.add(r); + if (window.size() > max) { + // 【debug】 + System.out.format("首个最大不重复子串:%s, Offset: [%d, %d)\n", + s.substring(left, right), left, right); + max = window.size(); + } + } + } + return max; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" new file mode 100644 index 0000000..68c8a3a --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" @@ -0,0 +1,44 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; + +/** + * 424. 替换后的最长重复字符 + * + * @author Zhang Peng + * @date 2025-10-15 + */ +public class 替换后的最长重复字符 { + + public static void main(String[] args) { + Assertions.assertEquals(4, characterReplacement("ABAB", 2)); + Assertions.assertEquals(4, characterReplacement("AABABBA", 1)); + Assertions.assertEquals(4, characterReplacement("AAAA", 2)); + } + + public static int characterReplacement(String s, int k) { + int result = 0; + int left = 0, right = 0; + int windowMaxCnt = 0; + HashMap map = new HashMap<>(26); + while (right < s.length()) { + char r = s.charAt(right); + right++; + + map.put(r, map.getOrDefault(r, 0) + 1); + windowMaxCnt = Math.max(windowMaxCnt, map.get(r)); + + while (right - left - windowMaxCnt > k) { + char l = s.charAt(left); + left++; + + map.put(l, map.get(l) - 1); + } + result = Math.max(result, right - left); + } + return result; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260III.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260III.java" new file mode 100644 index 0000000..0a2fe04 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260III.java" @@ -0,0 +1,39 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +/** + * 1004. 最大连续1的个数 III + * + * @author Zhang Peng + * @date 2025-10-14 + */ +public class 最大连续1的个数III { + + public static void main(String[] args) { + Assertions.assertEquals(6, longestOnes(new int[] { 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0 }, 2)); + Assertions.assertEquals(10, + longestOnes(new int[] { 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1 }, 3)); + } + + public static int longestOnes(int[] nums, int k) { + int max = 0; + int zeroCnt = 0; + int left = 0, right = 0; + while (right < nums.length) { + int r = nums[right]; + right++; + if (r == 0) zeroCnt++; + + while (zeroCnt > k) { + int l = nums[left]; + left++; + if (l == 0) zeroCnt--; + } + + max = Math.max(max, right - left); + } + return max; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" new file mode 100644 index 0000000..ea03017 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" @@ -0,0 +1,65 @@ +package io.github.dunwu.algorithm.array.window; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; + +/** + * 76. 最小覆盖子串 + * + * @author Zhang Peng + * @date 2025-01-10 + */ +@Slf4j +public class 最小覆盖子串 { + + public static void main(String[] args) { + Assertions.assertEquals("BANC", minWindow("ADOBECODEBANC", "ABC")); + Assertions.assertEquals("a", minWindow("a", "a")); + Assertions.assertEquals("", minWindow("a", "aa")); + } + + public static String minWindow(String s, String t) { + HashMap window = new HashMap<>(); + HashMap need = new HashMap<>(); + for (int i = 0; i < t.length(); i++) { + need.put(t.charAt(i), need.getOrDefault(t.charAt(i), 0) + 1); + } + + int valid = 0; + int start = 0, len = Integer.MAX_VALUE; + int left = 0, right = 0; + while (right < s.length()) { + char r = s.charAt(right); + // 扩大窗口:右边界右移 + right++; + // 窗口 window 满足 need 的一系列更新 + if (need.containsKey(r)) { + window.put(r, window.getOrDefault(r, 0) + 1); + if (window.get(r).equals(need.get(r))) { + valid++; + } + } + + // 判断左侧窗口是否要收缩 + while (valid == need.size()) { + if (right - left < len) { + start = left; + len = right - left; + System.out.format("窗口:[left: %s, right: %s), 子串:%s\n", left, right, + s.substring(start, right)); + } + char l = s.charAt(left); + // 缩小窗口:左边界右移 + left++; + if (need.containsKey(l)) { + if (window.get(l).equals(need.get(l))) valid--; + window.put(l, window.get(l) - 1); + } + } + } + return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len); + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" new file mode 100644 index 0000000..f96bd68 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" @@ -0,0 +1,79 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +/** + * 395. 至少有 K + * 个重复字符的最长子串 + * + * @author Zhang Peng + * @date 2025-10-15 + */ +public class 至少有K个重复字符的最长子串 { + + public static void main(String[] args) { + Assertions.assertEquals(3, longestSubstring("aaabb", 3)); + Assertions.assertEquals(5, longestSubstring("ababbc", 2)); + } + + public static int longestSubstring(String s, int k) { + int len = 0; + for (int i = 1; i <= 26; i++) { + // 限制窗口中只能有 i 种不同字符 + len = Math.max(len, kLetterLongestSubstring(s, k, i)); + } + return len; + } + + // 寻找 s 中含有 count 种字符,且每种字符出现次数都大于 k 的子串 + static int kLetterLongestSubstring(String s, int k, int count) { + // 记录答案 + int res = 0; + // 快慢指针维护滑动窗口,左闭右开区间 + int left = 0, right = 0; + // 题目说 s 中只有小写字母,所以用大小 26 的数组记录窗口中字符出现的次数 + int[] windowCount = new int[26]; + // 记录窗口中存在几种不同的字符(字符种类) + int windowUniqueCount = 0; + // 记录窗口中有几种字符的出现次数达标(大于等于 k) + int windowValidCount = 0; + // 滑动窗口代码模板 + while (right < s.length()) { + // 移入字符,扩大窗口 + char c = s.charAt(right); + if (windowCount[c - 'a'] == 0) { + // 窗口中新增了一种字符 + windowUniqueCount++; + } + windowCount[c - 'a']++; + if (windowCount[c - 'a'] == k) { + // 窗口中新增了一种达标的字符 + windowValidCount++; + } + right++; + + // 当窗口中字符种类大于 count 时,缩小窗口 + while (windowUniqueCount > count) { + // 移出字符,缩小窗口 + char d = s.charAt(left); + if (windowCount[d - 'a'] == k) { + // 窗口中减少了一种达标的字符 + windowValidCount--; + } + windowCount[d - 'a']--; + if (windowCount[d - 'a'] == 0) { + // 窗口中减少了一种字符 + windowUniqueCount--; + } + left++; + } + + // 当窗口中字符种类为 count 且每个字符出现次数都满足 k 时,更新答案 + if (windowValidCount == count) { + res = Math.max(res, right - left); + } + } + return res; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" new file mode 100644 index 0000000..2baccd8 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" @@ -0,0 +1,42 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +/** + * 209. 长度最小的子数组 + * + * @author Zhang Peng + * @date 2025-10-15 + */ +public class 长度最小的子数组 { + + public static void main(String[] args) { + Assertions.assertEquals(2, minSubArrayLen(7, new int[] { 2, 3, 1, 2, 4, 3 })); + Assertions.assertEquals(1, minSubArrayLen(4, new int[] { 1, 4, 4 })); + Assertions.assertEquals(0, minSubArrayLen(11, new int[] { 1, 1, 1, 1, 1, 1, 1, 1 })); + } + + public static int minSubArrayLen(int target, int[] nums) { + // System.out.println("================================"); + int sum = 0; + int minSize = Integer.MAX_VALUE; + int left = 0, right = 0; + while (right < nums.length) { + + // sum 小于 target 扩大窗口 + sum += nums[right++]; + + // sum 大于等于 target 扩大窗口 + while (sum >= target) { + minSize = Math.min(minSize, right - left); + // System.out.format("left: %d, right: %d, minSize: %d, sum: %d\n", + // left, right, minSize, sum); + + sum -= nums[left]; + left++; + } + } + return minSize == Integer.MAX_VALUE ? 0 : minSize; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" index d0799ec..dfbaf02 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" @@ -2,9 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.HashSet; -import java.util.Set; - /** * 263. 丑数 * diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" new file mode 100644 index 0000000..8cdcb07 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" @@ -0,0 +1,97 @@ +package io.github.dunwu.algorithm.array; + +import org.junit.jupiter.api.Assertions; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Zhang Peng + * @date 2025-10-14 + */ +public class 二维网格迁移 { + // 给你一个 m 行 n 列的二维网格 grid 和一个整数 k。你需要将 grid 迁移 k 次。 + // + // 每次「迁移」操作将会引发下述活动: + // + // 位于 grid[i][j](j < n - 1)的元素将会移动到 grid[i][j + 1]。 + // 位于 grid[i][n - 1] 的元素将会移动到 grid[i + 1][0]。 + // 位于 grid[m - 1][n - 1] 的元素将会移动到 grid[0][0]。 + // 请你返回 k 次迁移操作后最终得到的 二维网格。 + + // 输入:grid = {{1,2,3},{4,5,6},{7,8,9}}, k = 1 + // 输出:{{9,1,2},{3,4,5},{6,7,8}} + // + // + // 输入:grid = {{3,8,1,9},{19,7,2,5},{4,6,11,10},{12,0,21,13}}, k = 4 + // 输出:{{12,0,21,13},{3,8,1,9},{19,7,2,5},{4,6,11,10}} + // + // 输入:grid = {{1,2,3},{4,5,6},{7,8,9}}, k = 9 + // 输出:{{1,2,3},{4,5,6},{7,8,9}} + + public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { + int[][] grid1 = new int[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + List> res1 = shiftGrid(grid1, 1); + Assertions.assertNotNull(res1); + Assertions.assertArrayEquals(new Integer[] { 9, 1, 2 }, res1.get(0).toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 3, 4, 5 }, res1.get(1).toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 6, 7, 8 }, res1.get(2).toArray(new Integer[0])); + + int[][] grid2 = new int[][] { { 3, 8, 1, 9 }, { 19, 7, 2, 5 }, { 4, 6, 11, 10 }, { 12, 0, 21, 13 } }; + List> res2 = shiftGrid(grid2, 4); + Assertions.assertNotNull(res2); + Assertions.assertArrayEquals(new Integer[] { 12, 0, 21, 13 }, res2.get(0).toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 3, 8, 1, 9 }, res2.get(1).toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 19, 7, 2, 5 }, res2.get(2).toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 4, 6, 11, 10 }, res2.get(3).toArray(new Integer[0])); + + int[][] grid3 = new int[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + List> res3 = shiftGrid(grid3, 9); + Assertions.assertNotNull(res3); + Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, res3.get(0).toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 4, 5, 6 }, res3.get(1).toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 7, 8, 9 }, res3.get(2).toArray(new Integer[0])); + } + + /** + * 低效方法 + */ + public static List> shiftGrid(int[][] grid, int k) { + int M = grid.length, N = grid[0].length; + k = k % (M * N); + List> listlist = new ArrayList<>(); + for (int i = 0; i < k; i++) { + shift(grid); + } + for (int[] array : grid) { + ArrayList list = new ArrayList<>(); + for (int val : array) { + list.add(val); + } + listlist.add(list); + } + return listlist; + } + + public static void shift(int[][] grid) { + int M = grid.length, N = grid[0].length; + int[][] shift = new int[M][N]; + for (int i = M - 1; i >= 0; i--) { + for (int j = N - 1; j >= 0; j--) { + int val = grid[i][j]; + if (i == M - 1 && j == N - 1) { + shift[0][0] = val; + } else if (j == N - 1) { + shift[i + 1][0] = val; + } else if (j < N - 1) { + shift[i][j + 1] = val; + } + } + } + for (int i = M - 1; i >= 0; i--) { + System.arraycopy(shift[i], 0, grid[i], 0, N - 1 + 1); + } + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" index 2688a8f..f6b1cd9 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" @@ -4,7 +4,6 @@ import org.junit.jupiter.api.Assertions; import java.lang.reflect.InvocationTargetException; -import java.util.PriorityQueue; /** * 88. 合并两个有序数组 @@ -47,17 +46,20 @@ public static void merge(int[] nums1, int m, int[] nums2, int n) { } public static void merge2(int[] nums1, int m, int[] nums2, int n) { - PriorityQueue pq = new PriorityQueue<>((a, b) -> a - b); - for (int i = 0; i < m; i++) { - pq.offer(nums1[i]); - } - for (int i = 0; i < n; i++) { - pq.offer(nums2[i]); + // 两个指针分别初始化在两个数组的最后一个元素(类似拉链两端的锯齿) + int i = m - 1, j = n - 1; + // 生成排序的结果(类似拉链的拉锁) + int p = nums1.length - 1; + // 从后向前生成结果数组,类似合并两个有序链表的逻辑 + while (i >= 0 && j >= 0) { + if (nums1[i] > nums2[j]) { + nums1[p--] = nums1[i--]; + } else { + nums1[p--] = nums2[j--]; + } } - - int pos = 0; - while (!pq.isEmpty() && pos < (m + n)) { - nums1[pos++] = pq.poll(); + while (j >= 0) { + nums1[p--] = nums2[j--]; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" deleted file mode 100644 index 2017474..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; - -/** - * 567. 字符串的排列 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 字符串的排列 { - - public static void main(String[] args) { - Assertions.assertTrue(checkInclusion("ab", "eidbaooo")); - Assertions.assertFalse(checkInclusion("ab", "eidboaoo")); - } - - public static boolean checkInclusion(String t, String s) { - - // 定义 window, need - Map need = new HashMap<>(); - Map window = new HashMap<>(); - for (char c : s.toCharArray()) { - need.put(c, need.getOrDefault(c, 0) + 1); - } - - int valid = 0; - int left = 0, right = 0; - while (right < s.length()) { - - // 2. right++,窗口右扩,直到满足条件 - - // 移入窗口的字符 - char c = s.charAt(right); - // 扩大窗口 - right++; - // 进行窗口内数据的一系列更新 - if (need.containsKey(c)) { - window.put(c, window.getOrDefault(c, 0) + 1); - if (window.get(c).equals(need.get(c))) { - valid++; - } - } - - - } - return false; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" deleted file mode 100644 index 266542f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" +++ /dev/null @@ -1,42 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -/** - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 存在重复元素 { - - public static void main(String[] args) { - Assertions.assertTrue(containsDuplicate(new Integer[] { 1, 2, 3, 1 })); - Assertions.assertFalse(containsDuplicate(new Integer[] { 1, 2, 3, 4 })); - Assertions.assertTrue(containsDuplicate(new Integer[] { 1, 1, 1, 3, 3, 4, 3, 2, 4, 2 })); - } - - /** - * 题目:217. 存在重复元素 - *

- * 给定一个数组,判断是否存在重复元素。 - *

- * 如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。 - * - * @param array 数组 - * @return true/false - */ - public static boolean containsDuplicate(T[] array) { - if (array == null || array.length <= 1) { - return false; - } - - Set set = new HashSet<>(); - set.addAll(Arrays.asList(array)); - - return set.size() != array.length; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" index 10f2eee..36f8db9 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" @@ -2,11 +2,8 @@ import org.junit.jupiter.api.Assertions; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.PriorityQueue; /** * 1329. 将矩阵按对角线排序 @@ -31,32 +28,29 @@ public static void main(String[] args) { } public static int[][] diagonalSort(int[][] mat) { - Map> map = new HashMap<>(); - int m = mat.length; - int n = mat[0].length; - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { + int R = mat.length, C = mat[0].length; + + // 存储所有对角线的元素列表 + HashMap> map = new HashMap<>(); + + for (int i = 0; i < R; i++) { + for (int j = 0; j < C; j++) { + // 横纵坐标之差可以作为一条对角线的 ID int diff = i - j; - if (!map.containsKey(diff)) { - map.put(diff, new ArrayList<>()); - } - map.get(diff).add(mat[i][j]); + map.putIfAbsent(diff, new PriorityQueue<>((a, b) -> a - b)); + map.get(diff).offer(mat[i][j]); } } - map.forEach((diff, list) -> { - Collections.sort(list); - }); - - int[][] result = new int[m][n]; - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - int diff = i - j; - List list = map.get(diff); - result[i][j] = list.remove(0); + // 把排序结果回填二维矩阵 + for (int i = 0; i < R; i++) { + for (int j = 0; j < C; j++) { + PriorityQueue pq = map.get(i - j); + mat[i][j] = pq.poll(); } } - return result; + + return mat; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" deleted file mode 100644 index 6c38c24..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" +++ /dev/null @@ -1,83 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; - -/** - * 76. 最小覆盖子串 - * - * @author Zhang Peng - * @date 2025-01-10 - */ -@Slf4j -public class 最小覆盖子串 { - - public static void main(String[] args) { - Assertions.assertEquals("BANC", minWindow("ADOBECODEBANC", "ABC")); - Assertions.assertEquals("a", minWindow("a", "a")); - Assertions.assertEquals("", minWindow("a", "aa")); - } - - public static String minWindow(String s, String t) { - // 用合适的数据结构记录窗口中的数据,根据具体场景变通 - // 比如说,我想记录窗口中元素出现的次数,就用 map - // 如果我想记录窗口中的元素和,就可以只用一个 int - - // 记录 window 中的字符出现次数 - HashMap window = new HashMap<>(); - // 记录所需的字符出现次数 - HashMap need = new HashMap<>(); - for (int i = 0; i < t.length(); i++) { - char c = t.charAt(i); - need.put(c, need.getOrDefault(c, 0) + 1); - } - - int valid = 0; - int left = 0, right = 0; - // 记录最小覆盖子串的起始索引及长度 - int start = 0, len = Integer.MAX_VALUE; - while (right < s.length()) { - // c 是将移入窗口的字符 - char c = s.charAt(right); - // 增大窗口 - right++; - // 进行窗口内数据的一系列更新 - if (need.containsKey(c)) { - window.put(c, window.getOrDefault(c, 0) + 1); - if (window.get(c).equals(need.get(c))) { - valid++; - } - } - - // *** debug 输出的位置 *** - // 注意在最终的解法代码中不要 print - // 因为 IO 操作很耗时,可能导致超时 - log.info("window: [{}, {})", left, right); - - // 判断左侧窗口是否要收缩 - while (left < right && valid == need.size()) { - // 在这里更新最小覆盖子串 - if (right - left < len) { - start = left; - len = right - left; - } - - // d 是将移出窗口的字符 - char d = s.charAt(left); - // 缩小窗口 - left++; - // 进行窗口内数据的一系列更新 - if (need.containsKey(d)) { - if (window.get(d).equals(need.get(d))) { - valid--; - } - window.put(d, window.getOrDefault(d, 0) - 1); - } - } - } - return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" index e93cdaf..d653928 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" @@ -1,5 +1,3 @@ - - import org.junit.jupiter.api.Assertions; /** @@ -16,7 +14,7 @@ public static void main(String[] args) { String output1 = longestCommonPrefix(input1); Assertions.assertEquals(expect1, output1); - String[] input2 = { "dog","racecar","car" }; + String[] input2 = { "dog", "racecar", "car" }; String expect2 = ""; String output2 = longestCommonPrefix(input2); Assertions.assertEquals(expect2, output2); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" index fe13f2b..c881410 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" @@ -15,31 +15,29 @@ public static void main(String[] args) { } public static String longestPalindrome(String s) { - char[] chars = s.toCharArray(); - String max = s.substring(0, 1); - for (int i = 0; i < chars.length; i++) { - for (int j = chars.length - 1; j > i; j--) { - if (check(chars, i, j)) { - String temp = s.substring(i, j + 1); - if (temp.length() > max.length()) { - max = temp; - } - } - } + String res = ""; + for (int i = 0; i < s.length(); i++) { + // 以 s[i] 为中心的最长回文子串 + String s1 = palindrome(s, i, i); + // 以 s[i] 和 s[i+1] 为中心的最长回文子串 + String s2 = palindrome(s, i, i + 1); + // res = longest(res, s1, s2) + res = res.length() > s1.length() ? res : s1; + res = res.length() > s2.length() ? res : s2; } - return max; + return res; } - public static boolean check(char[] chars, int begin, int end) { - int left = begin, right = end; - while (left < right) { - if (chars[left] != chars[right]) { - return false; - } - left++; - right--; + public static String palindrome(String s, int l, int r) { + // 防止索引越界 + while (l >= 0 && r < s.length() + && s.charAt(l) == s.charAt(r)) { + // 向两边展开 + l--; + r++; } - return true; + // 此时 [l+1, r-1] 就是最长回文串 + return s.substring(l + 1, r); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\235\250\350\276\211\344\270\211\350\247\222.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\235\250\350\276\211\344\270\211\350\247\222.java" index 51ca60f..64e887b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\235\250\350\276\211\344\270\211\350\247\222.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\235\250\350\276\211\344\270\211\350\247\222.java" @@ -1,7 +1,5 @@ package io.github.dunwu.algorithm.array; -import org.junit.jupiter.api.Test; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" index 2fe2f75..f0ad557 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" @@ -6,7 +6,6 @@ import java.util.Arrays; import java.util.List; import java.util.PriorityQueue; -import java.util.TreeMap; /** * 373. 查找和最小的 K 对数字 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" index e38379b..adeaab3 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" @@ -29,17 +29,14 @@ public static void main(String[] args) { } public static ListNode deleteDuplicates(ListNode head) { - if (head == null || head.next == null) { - return head; - } - ListNode slow = head, fast = head.next; - while (fast != null) { - if (slow.val == fast.val) { - slow.next = fast.next; + if (head == null || head.next == null) return head; + ListNode p = head; + while (p.next != null) { + if (p.val == p.next.val) { + p.next = p.next.next; } else { - slow = slow.next; + p = p.next; } - fast = fast.next; } return head; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250.java" index 47963f5..22efea0 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250.java" @@ -6,8 +6,9 @@ import java.util.Stack; /** + * 206. 反转链表 + * * @author Zhang Peng - * @see 206. 反转链表 * @since 2020-06-09 */ public class 反转链表 { @@ -50,49 +51,38 @@ public static ListNode reverseList(ListNode head) { node = node.next; } - ListNode dummy = new ListNode(-5001); - ListNode p = dummy; + ListNode dummy = new ListNode(5001); + ListNode n = dummy; while (!stack.isEmpty()) { - ListNode top = stack.pop(); - top.next = null; - p.next = top; - p = p.next; + n.next = stack.pop(); + n = n.next; + n.next = null; } return dummy.next; } - /** - * 双指针,时间复杂度:O(N) - */ public static ListNode reverseList2(ListNode head) { + if (head == null || head.next == null) return head; - if (head == null) { - return head; - } - - ListNode pre = null, cur = head; + ListNode pre = null, cur = head, next = head.next; while (cur != null) { - ListNode next = cur.next; cur.next = pre; pre = cur; cur = next; + if (next != null) { + next = next.next; + } } return pre; } - /** - * 递归 - */ public static ListNode reverseList3(ListNode head) { + if (head == null || head.next == null) return head; - if (head == null || head.next == null) { - return head; - } - - ListNode last = reverseList3(head.next); + ListNode reverse = reverseList3(head.next); head.next.next = head; head.next = null; - return last; + return reverse; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" index 4d389de..8f3d29c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" @@ -15,54 +15,45 @@ public class 反转链表II { public static void main(String[] args) { ListNode head = ListUtil.buildList(1, 2, 3, 4, 5); System.out.println(ListUtil.toList(head)); - ListNode result = reverseBetween2(head, 2, 4); + ListNode result = reverseBetween(head, 2, 4); List list = ListUtil.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 1, 4, 3, 2, 5 }, list.toArray(new Integer[0])); + + ListNode head2 = ListUtil.buildList(3, 5); + System.out.println(ListUtil.toList(head2)); + ListNode result2 = reverseBetween(head2, 1, 2); + List list2 = ListUtil.toList(result2); + System.out.println(list2); + Assertions.assertArrayEquals(new Integer[] { 5, 3 }, list2.toArray(new Integer[0])); } public static ListNode reverseBetween(ListNode head, int left, int right) { if (left == 1) { return reverseN(head, right); } - // 找到第 m 个节点的前驱 + ListNode pre = head; for (int i = 1; i < left - 1; i++) { pre = pre.next; } - // 从第 m 个节点开始反转 pre.next = reverseN(pre.next, right - left + 1); return head; } - public static ListNode reverseBetween2(ListNode head, int left, int right) { - if (left == 1) { - return reverseN(head, right); - } - head.next = reverseBetween2(head.next, left - 1, right - 1); - return head; - } - - public static ListNode reverseN(ListNode head, int n) { - if (head == null || head.next == null) { - return head; - } - ListNode pre, cur, nxt; - pre = null; - cur = head; - nxt = head.next; + static ListNode reverseN(ListNode head, int n) { + if (head == null || head.next == null) return head; + ListNode pre = null, cur = head, next = head.next; while (n > 0) { cur.next = pre; pre = cur; - cur = nxt; - if (nxt != null) { - nxt = nxt.next; + cur = next; + if (next != null) { + next = next.next; } n--; } - // 此时的 cur 是第 n + 1 个节点,head 是反转后的尾结点 head.next = cur; - // 此时的 pre 是反转后的头结点 return pre; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" index d2befb6..0792257 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" @@ -23,23 +23,26 @@ public static void main(String[] args) { Assertions.assertFalse(isPalindrome(head)); } - public static boolean isPalindrome(ListNode head) { - LinkedList l1 = new LinkedList<>(); - LinkedList l2 = new LinkedList<>(); - while (head != null) { - l1.offerFirst(head.val); - l2.offerFirst(head.val); - head = head.next; - } - - while (!l1.isEmpty() && !l2.isEmpty()) { - Integer num1 = l1.pollFirst(); - Integer num2 = l2.pollLast(); - if (num1 != num2) { + public static boolean isPalindrome(ListNode list) { + ListNode rlist = reverse(list); + ListNode p = list, q = rlist; + while (p != null && q != null) { + if (p.val != q.val) { return false; } + p = p.next; + q = q.next; } return true; } + static ListNode reverse(ListNode head) { + if (head == null || head.next == null) return head; + + ListNode last = reverse(head.next); + head.next.next = head; + head.next = null; + return last; + } + } From 538fa273906aaf91d6a19d8246d66206bba7c0f2 Mon Sep 17 00:00:00 2001 From: dunwu Date: Thu, 23 Oct 2025 06:46:22 +0800 Subject: [PATCH 09/21] =?UTF-8?q?feat:=20leetcode=20=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 113 +++++++----- ...\346\234\200\345\244\247\345\200\274.java" | 57 ++++++ ...\347\232\204\350\203\275\345\212\233.java" | 27 ++- ...\347\232\204\347\217\202\347\217\202.java" | 36 ++-- ...\344\270\215\345\217\257\345\217\230.java" | 20 ++- ...\347\240\201\346\250\241\346\235\277.java" | 65 +++++++ ...\344\270\215\345\217\257\345\217\230.java" | 2 +- ...\347\240\201\346\250\241\346\235\277.java" | 49 +++++ .../range/\346\213\274\350\275\246.java" | 76 ++++++++ ...\350\256\242\347\273\237\350\256\241.java" | 41 +++++ ...\346\261\202\346\254\241\346\225\260.java" | 38 ---- ...\347\216\257\351\230\237\345\210\227.java" | 111 ------------ .../SampleBrowser.java | 2 +- .../StackBasedOnLinkedList.java | 2 +- .../queue/GenericQueue.java | 2 +- .../queue/MyCircularDeque.java | 2 +- ...\347\232\204\351\230\237\345\210\227.java" | 2 +- ...\347\232\204\351\230\237\345\210\227.java" | 2 +- ...\346\261\202\346\254\241\346\225\260.java" | 36 ++++ ...\347\232\204\351\230\237\345\210\227.java" | 2 +- .../stack/GenericStack.java | 2 +- ...\345\257\271\350\267\257\345\276\204.java" | 7 +- ...\351\242\221\347\216\207\346\240\210.java" | 61 +++++++ ...\346\234\200\345\260\217\346\240\210.java" | 37 ++-- ...\347\232\204\346\213\254\345\217\267.java" | 2 +- ...\345\214\226\350\267\257\345\276\204.java" | 46 +++++ ...\345\274\217\346\261\202\345\200\274.java" | 2 +- ...\346\216\222\351\223\276\350\241\250.java" | 2 +- ...\344\270\211\345\220\210\344\270\200.java" | 2 +- ...345\244\247\345\205\203\347\264\240I.java" | 4 +- ...\350\256\241\347\256\227\345\231\250.java" | 3 +- ...\346\240\210\346\216\222\345\272\217.java" | 2 +- ...\347\220\203\346\257\224\350\265\233.java" | 4 +- ...\345\255\227\347\254\246\344\270\262.java" | 3 +- ...\347\216\260\351\230\237\345\210\227.java" | 81 +++++++++ ...\345\256\236\347\216\260\346\240\210.java" | 37 ++-- ...\351\242\221\347\216\207\346\240\210.java" | 55 ------ ...\347\216\260\351\230\237\345\210\227.java" | 56 ------ ...\345\214\226\350\267\257\345\276\204.java" | 42 ----- .../io/github/dunwu/algorithm/tree/BTree.java | 6 +- .../github/dunwu/algorithm/tree/TreeNode.java | 148 +++++++++++++++ .../dunwu/algorithm/tree/TreeUtils.java | 169 ------------------ ...\345\205\245\346\223\215\344\275\234.java" | 38 ++-- ...\347\232\204\346\220\234\347\264\242.java" | 41 +++++ ...\347\232\204\345\205\203\347\264\240.java" | 47 +++++ ...\345\205\261\347\245\226\345\205\210.java" | 13 +- ...\345\260\217\350\267\235\347\246\273.java" | 3 +- ...\347\232\204\350\212\202\347\202\271.java" | 69 +++++++ ...\347\264\257\345\212\240\346\240\221.java" | 58 ++++++ ...\346\220\234\347\264\242\346\240\221.java" | 50 +----- ...\346\200\247\346\243\200\351\252\214.java" | 71 ++++++++ ...\345\271\263\345\235\207\345\200\274.java" | 26 ++- ...\346\254\241\351\201\215\345\216\206.java" | 51 +++--- ...346\254\241\351\201\215\345\216\2062.java" | 9 +- ...\345\244\247\345\256\275\345\272\246.java" | 77 ++++++++ ...\345\272\217\351\201\215\345\216\206.java" | 65 +++++++ ...\346\234\200\345\244\247\345\200\274.java" | 28 ++- ...\347\202\271\346\214\207\351\222\210.java" | 39 ++-- ...347\202\271\346\214\207\351\222\2102.java" | 5 +- ...\345\245\207\345\201\266\346\240\221.java" | 59 ++++++ ...\347\202\271\347\232\204\345\222\214.java" | 48 +++++ ...\345\205\203\347\264\240\345\222\214.java" | 35 ++-- ...\344\272\214\345\217\211\346\240\221.java" | 5 +- ...\344\272\214\345\217\211\346\240\221.java" | 7 +- ...\347\202\271\346\210\220\346\236\227.java" | 57 ++++++ ...\344\272\214\345\217\211\346\240\221.java" | 65 +++++++ ...344\272\214\345\217\211\346\240\2212.java" | 51 ++++++ ...\344\272\214\345\217\211\346\240\221.java" | 5 +- ...\345\272\217\345\210\227\345\214\226.java" | 44 +++++ ...\346\226\207\350\267\257\345\276\204.java" | 7 +- ...\345\217\263\350\247\206\345\233\276.java" | 7 +- ...\346\234\211\350\267\257\345\276\204.java" | 67 +++++++ ...\345\255\227\347\254\246\344\270\262.java" | 11 +- ...\346\225\260\344\271\213\345\222\214.java" | 7 +- ...\345\212\240\344\270\200\350\241\214.java" | 14 +- ...\345\255\220\344\271\213\345\222\214.java" | 13 +- ...\345\255\227\344\271\213\345\222\214.java" | 7 +- ...\350\267\257\345\276\204\345\222\214.java" | 9 +- ...\344\270\272\351\223\276\350\241\250.java" | 13 +- ...\345\272\217\351\201\215\345\216\206.java" | 7 +- ...\345\272\217\351\201\215\345\216\206.java" | 7 +- ...\345\272\217\351\201\215\345\216\206.java" | 9 +- ...\346\200\247\346\243\200\351\252\214.java" | 61 ------- ...\345\272\217\345\210\227\345\214\226.java" | 79 +++----- ...\346\234\211\350\267\257\345\276\204.java" | 60 ------- ...\345\244\247\345\256\275\345\272\246.java" | 69 ------- ...\345\244\247\346\267\261\345\272\246.java" | 25 ++- ...\345\260\217\346\267\261\345\272\246.java" | 5 +- ...\345\205\261\347\245\226\345\205\210.java" | 32 ++-- ...\347\232\204\347\233\264\345\276\204.java" | 5 +- ...\346\254\241\351\201\215\345\216\206.java" | 8 +- ...\344\272\214\345\217\211\346\240\221.java" | 3 +- ...\347\202\271\346\210\220\346\236\227.java" | 58 ------ ...\344\274\274\347\232\204\346\240\221.java" | 5 +- ...\345\245\207\345\201\266\346\240\221.java" | 73 -------- ...\347\202\271\344\270\252\346\225\260.java" | 7 +- ...\344\272\214\345\217\211\346\240\221.java" | 5 +- ...\347\202\271\347\232\204\345\222\214.java" | 55 ------ ...\344\272\214\345\217\211\346\240\221.java" | 7 +- ...\344\272\214\345\217\211\346\240\221.java" | 21 +-- ...344\272\214\345\217\211\346\240\2212.java" | 47 ----- ...\345\220\214\347\232\204\346\240\221.java" | 13 +- ...\344\272\214\345\217\211\346\240\221.java" | 3 +- ...\345\276\204\346\200\273\345\222\214.java" | 5 +- ...\345\272\217\345\210\227\345\214\226.java" | 63 ------- 105 files changed, 1936 insertions(+), 1473 deletions(-) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" (70%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" (60%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" (61%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" (95%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\256\276\350\256\241\345\276\252\347\216\257\351\230\237\345\210\227.java" rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{stack => queue_and_stack}/SampleBrowser.java (98%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{stack => queue_and_stack}/StackBasedOnLinkedList.java (96%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{ => queue_and_stack}/queue/GenericQueue.java (95%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{ => queue_and_stack}/queue/MyCircularDeque.java (98%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" (96%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" (96%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" (96%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{ => queue_and_stack}/stack/GenericStack.java (95%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" (77%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\260\217\346\240\210.java" (51%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" (96%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" (96%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" (96%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\344\270\211\345\220\210\344\270\200.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\211\345\220\210\344\270\200.java" (96%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" (96%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" (94%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\240\210\346\216\222\345\272\217.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\240\210\346\216\222\345\272\217.java" (96%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" (90%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" (90%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" (57%) delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" delete mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeUtils.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\220\234\347\264\242.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\346\212\212\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\275\254\346\215\242\344\270\272\347\264\257\345\212\240\346\240\221.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" (59%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" (53%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" (89%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\345\272\217\351\201\215\345\216\206.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" (55%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" (57%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" (91%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\245\207\345\201\266\346\240\221.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" (53%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" (92%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" (90%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" (93%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" (85%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" (81%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" (79%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" (83%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" (84%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" (69%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" (91%) delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\210\240\347\202\271\346\210\220\346\236\227.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\245\207\345\201\266\346\240\221.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" diff --git a/README.md b/README.md index b98aa37..33ba586 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ | [76. 最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring/) | ❌ | | [1658. 将 x 减到 0 的最小操作数](https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/) | ❌ | | [713. 乘积小于 K 的子数组](https://leetcode.cn/problems/subarray-product-less-than-k/) | ❌ | -| [1004. 最大连续1的个数 III](https://leetcode.cn/problems/max-consecutive-ones-iii/) | ✔️ | +| [1004. 最大连续 1 的个数 III](https://leetcode.cn/problems/max-consecutive-ones-iii/) | ✔️ | | [424. 替换后的最长重复字符](https://leetcode.cn/problems/longest-repeating-character-replacement/) | ❗ | | [219. 存在重复元素 II](https://leetcode.cn/problems/contains-duplicate-ii/) | ❗ | | [220. 存在重复元素 III](https://labuladong.online/algo/problem-set/sliding-window/#slug_contains-duplicate-iii) | ❌ | @@ -157,20 +157,15 @@ | [34. 在排序数组中查找元素的第一个和最后一个位置](https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/) | ❗ | | [704. 二分查找](https://leetcode.cn/problems/binary-search/) | ✔️ | | [LCR 172. 统计目标成绩的出现次数](https://leetcode.cn/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/) | ✔️ | - -#### 索 - -| 题目 | 掌握度 | -| ------------------------------------------------------------------------------------------------------ | ------ | -| [875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) | ❌ | -| [1011. 在 D 天内送达包裹的能力](https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/) | ❌ | -| [410. 分割数组的最大值](https://leetcode.cn/problems/split-array-largest-sum/) | ❌ | +| [875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) | ❌ | +| [1011. 在 D 天内送达包裹的能力](https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/) | ❌ | +| [410. 分割数组的最大值](https://leetcode.cn/problems/split-array-largest-sum/) | ❌ | #### 前缀和数组 | 题目 | 掌握度 | | ---------------------------------------------------------------------------------------------- | ------ | -| [303. 区域和检索 - 数组不可变](https://leetcode.cn/problems/range-sum-query-immutable/) | ❗ | +| [303. 区域和检索 - 数组不可变](https://leetcode.cn/problems/range-sum-query-immutable/) | ✔️ | | [304. 二维区域和检索 - 矩阵不可变](https://leetcode.cn/problems/range-sum-query-2d-immutable/) | ❌ | #### 差分数组 @@ -187,31 +182,27 @@ | 题目 | 掌握度 | | ------------------------------------------------------------------------------- | ------ | -| [225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/) | ❗ | +| [225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/) | ✔️ | | [232. 用栈实现队列](https://leetcode.cn/problems/implement-queue-using-stacks/) | ✔️ | #### 栈的经典习题 | 题目 | 掌握度 | | --------------------------------------------------------------------------------------- | ------ | -| [71. 简化路径](https://leetcode.cn/problems/simplify-path/) | ❗ | +| [71. 简化路径](https://leetcode.cn/problems/simplify-path/) | ✔️ | | [143. 重排链表](https://leetcode.cn/problems/reorder-list/) | ✔️ | | [20. 有效的括号](https://leetcode.cn/problems/valid-parentheses/) | ✔️ | | [150. 逆波兰表达式求值](https://leetcode.cn/problems/evaluate-reverse-polish-notation/) | ✔️ | | [388. 文件的最长绝对路径](https://leetcode.cn/problems/longest-absolute-file-path/) | ❌ | -| [155. 最小栈](https://leetcode.cn/problems/min-stack/) | | -| [895. 最大频率栈](https://leetcode.cn/problems/maximum-frequency-stack/) | | +| [155. 最小栈](https://leetcode.cn/problems/min-stack/) | ❌ | +| 最大频率栈](https://leetcode.cn/problems/maximum-frequency-stack/) | ❌ | #### 队列的经典习题 | 题目 | 掌握度 | | --------------------------------------------------------------------------- | ------ | | [933. 最近的请求次数](https://leetcode.cn/problems/number-of-recent-calls/) | ❗ | -| [622. 设计循环队列](https://leetcode.cn/problems/design-circular-queue/) | | -| | | -| | | -| | | -| | | +| [622. 设计循环队列](https://leetcode.cn/problems/design-circular-queue/) | ❌ | | | | #### 单调栈算法模板 @@ -227,23 +218,19 @@ #### 基础 -| 题目 | 掌握度 | -| ------------------------------------------------------------------------------------------------------------------------ | ------ | -| [104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) | ✔️ | -| [111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/) | ✔️ | -| [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/) | ✔️ | -| [94. 二叉树的中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal/) | ✔️ | -| [145. 二叉树的后序遍历](https://leetcode.cn/problems/binary-tree-postorder-traversal/) | ✔️ | -| [102. 二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal/) | ❗ | -| [107. 二叉树的层序遍历 II](https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/) | ✔️ | -| [543. 二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree/) | ❌ | -| [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/) | ✔️ | -| [116. 填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) | ✔️ | -| [117. 填充每个节点的下一个右侧节点指针 II](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/) | ✔️ | -| [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/) | ✔️ | -| [654. 最大二叉树](https://leetcode.cn/problems/maximum-binary-tree/) | ✔️ | -| [297. 二叉树的序列化与反序列化](https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/) | ❌ | -| [222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/) | ✔️ | +| 题目 | 掌握度 | +| ---------------------------------------------------------------------------------------------------- | ------ | +| [104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) | ✔️ | +| [111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/) | ✔️ | +| [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/) | ✔️ | +| [94. 二叉树的中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal/) | ✔️ | +| [145. 二叉树的后序遍历](https://leetcode.cn/problems/binary-tree-postorder-traversal/) | ✔️ | +| [543. 二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree/) | ❌ | +| [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/) | ✔️ | +| [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/) | ✔️ | +| [654. 最大二叉树](https://leetcode.cn/problems/maximum-binary-tree/) | ✔️ | +| [297. 二叉树的序列化与反序列化](https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/) | ❌ | +| [222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/) | ✔️ | #### 用「遍历」思维解题 @@ -265,10 +252,50 @@ | [105. 从前序与中序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) | ✔️ | | [106. 从中序与后序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) | ✔️ | | [889. 根据前序和后序遍历构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-postorder-traversal/) | ✔️ | -| [331. 验证二叉树的前序序列化](https://leetcode.cn/problems/verify-preorder-serialization-of-a-binary-tree/) | | -| [894. 所有可能的真二叉树](https://leetcode.cn/problems/all-possible-full-binary-trees/) | | -| [998. 最大二叉树 II](https://leetcode.cn/problems/maximum-binary-tree-ii/) | | -| [1110. 删点成林](https://leetcode.cn/problems/delete-nodes-and-return-forest/) | | +| [331. 验证二叉树的前序序列化](https://leetcode.cn/problems/verify-preorder-serialization-of-a-binary-tree/) | ❌ | +| [894. 所有可能的真二叉树](https://leetcode.cn/problems/all-possible-full-binary-trees/) | ❌ | +| [998. 最大二叉树 II](https://leetcode.cn/problems/maximum-binary-tree-ii/) | ❌ | +| [1110. 删点成林](https://leetcode.cn/problems/delete-nodes-and-return-forest/) | ❌ | + +#### 用「层序遍历」思维解题 + +| 题目 | 掌握度 | +| -------------------------------------------------------------------------------------------------------------------------- | ------ | +| [102. 二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal/) | ✔️ | +| [107. 二叉树的层序遍历 II](https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/) | ✔️ | +| [103. 二叉树的锯齿形层序遍历](https://leetcode.cn/problems/binary-tree-zigzag-level-order-traversal/) | ✔️ | +| [116. 填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) | ✔️ | +| [117. 填充每个节点的下一个右侧节点指针 II](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/) | ✔️ | +| [662. 二叉树最大宽度](https://leetcode.cn/problems/maximum-width-of-binary-tree/) | ✔️ | +| [515. 在每个树行中找最大值](https://leetcode.cn/problems/find-largest-value-in-each-tree-row/) | ✔️ | +| [637. 二叉树的层平均值](https://leetcode.cn/problems/average-of-levels-in-binary-tree/) | ✔️ | +| [958. 二叉树的完全性检验](https://leetcode.cn/problems/check-completeness-of-a-binary-tree/) | ✔️ | +| [1161. 最大层内元素和](https://leetcode.cn/problems/maximum-level-sum-of-a-binary-tree/) | ✔️ | +| [1302. 层数最深叶子节点的和](https://leetcode.cn/problems/deepest-leaves-sum/) | ✔️ | +| [1609. 奇偶树](https://leetcode.cn/problems/even-odd-tree/) | ✔️ | +| [429. N 叉树的层序遍历](https://leetcode.cn/problems/n-ary-tree-level-order-traversal/) | | +| [919. 完全二叉树插入器](https://leetcode.cn/problems/complete-binary-tree-inserter/) | | +| [剑指 Offer 32 - II. 从上到下打印二叉树 II](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/) | | +| [剑指 Offer 32 - III. 从上到下打印二叉树 III](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-iii-lcof/) | | +| [剑指 Offer 32 - I. 从上到下打印二叉树](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/) | | + +#### 二叉搜索树 + +| 题目 | 掌握度 | +| --------------------------------------------------------------------------------------------- | ------ | +| [230. 二叉搜索树中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-bst/) | ❗ | +| [538. 把二叉搜索树转换为累加树](https://leetcode.cn/problems/convert-bst-to-greater-tree/) | ✔️ | +| [450. 删除二叉搜索树中的节点](https://leetcode.cn/problems/delete-node-in-a-bst/) | ❌ | +| [700. 二叉搜索树中的搜索](https://leetcode.cn/problems/search-in-a-binary-search-tree/) | ✔️ | +| [701. 二叉搜索树中的插入操作](https://leetcode.cn/problems/insert-into-a-binary-search-tree/) | ✔️ | +| [98. 验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree/) | ❌ | +| | | +| | | +| | | +| | | +| | | +| | | +| | | ### 动态规划 @@ -277,10 +304,6 @@ | [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | | | [509. 斐波那契数](https://leetcode.cn/problems/fibonacci-number/) | | | | | -| | | -| | | -| | | -| | | ### 贪心算法 @@ -301,7 +324,7 @@ - 刷题必备 - 《剑指 offer》 - 《编程之美》 - - 《编程之法:面试和算法心得》 + - 《编程之法:面试和算法心得》 - 《算法谜题》 都是思维题 - 基础 - 《[编程珠玑(第 2 版)](https://www.amazon.cn/gp/product/B00SFZH0DC/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00SFZH0DC&linkCode=as2&tag=vastwork-23)》 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" new file mode 100644 index 0000000..43692b1 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" @@ -0,0 +1,57 @@ +package io.github.dunwu.algorithm.array.bsearch; + +import org.junit.jupiter.api.Assertions; + +/** + * 410. 分割数组的最大值 + * + * @author Zhang Peng + * @date 2025-10-16 + */ +public class 分割数组的最大值 { + + public static void main(String[] args) { + Assertions.assertEquals(18, splitArray(new int[] { 7, 2, 5, 10, 8 }, 2)); + Assertions.assertEquals(9, splitArray(new int[] { 1, 2, 3, 4, 5 }, 2)); + Assertions.assertEquals(4, splitArray(new int[] { 1, 4, 4 }, 3)); + } + + public static int splitArray(int[] nums, int k) { + int left = 0; + int right = 0; + for (int w : nums) { + left = Math.max(left, w); + right += w; + } + + while (left <= right) { + int mid = left + (right - left) / 2; + if (f(nums, mid) == k) { + right = mid - 1; + } else if (f(nums, mid) < k) { + right = mid - 1; + } else if (f(nums, mid) > k) { + left = mid + 1; + } + } + return left; + } + + public static int f(int[] weights, int x) { + int days = 0; + for (int i = 0; i < weights.length; ) { + int cap = x; + while (i < weights.length) { + if (cap < weights[i]) { + break; + } else { + cap -= weights[i]; + } + i++; + } + days++; + } + return days; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" similarity index 70% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" index 647c1bf..850a9f2 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" @@ -1,8 +1,9 @@ -package io.github.dunwu.algorithm.array; +package io.github.dunwu.algorithm.array.bsearch; import org.junit.jupiter.api.Assertions; import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; /** * 1011. 在 D 天内送达包裹的能力 @@ -13,31 +14,39 @@ public class 在D天内送达包裹的能力 { public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { + + // Assertions.assertEquals(5, f(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 15)); + // Assertions.assertEquals(3, f(new int[] { 3, 2, 2, 4, 1, 4 }, 6)); + // Assertions.assertEquals(4, f(new int[] { 1, 2, 3, 1, 1 }, 3)); + Assertions.assertEquals(15, shipWithinDays(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 5)); Assertions.assertEquals(6, shipWithinDays(new int[] { 3, 2, 2, 4, 1, 4 }, 3)); Assertions.assertEquals(3, shipWithinDays(new int[] { 1, 2, 3, 1, 1 }, 4)); } public static int shipWithinDays(int[] weights, int days) { - int left = 0, right = 1; + int left = 0; + int right = 0; + for (int w : weights) { + left = Math.max(left, w); + right += w; + } + while (left <= right) { int mid = left + (right - left) / 2; if (f(weights, mid) == days) { - // 搜索左侧边界,则需要收缩右侧边界 - right = mid; + right = mid - 1; } else if (f(weights, mid) < days) { - // 需要让 f(x) 的返回值大一些 - right = mid; + right = mid - 1; } else if (f(weights, mid) > days) { - // 需要让 f(x) 的返回值小一些 left = mid + 1; } } return left; } - public static long f(int[] weights, int x) { - long days = 0; + public static int f(int[] weights, int x) { + int days = 0; for (int i = 0; i < weights.length; ) { int cap = x; while (i < weights.length) { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" similarity index 60% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" index 73246ee..111a36c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" @@ -1,8 +1,9 @@ -package io.github.dunwu.algorithm.array; +package io.github.dunwu.algorithm.array.bsearch; import org.junit.jupiter.api.Assertions; import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; /** * 875. 爱吃香蕉的珂珂 @@ -20,31 +21,32 @@ public static void main(String[] args) throws InvocationTargetException, Illegal public static int minEatingSpeed(int[] piles, int h) { int left = 1, right = 1000000000 + 1; - while (left < right) { + while (left <= right) { int mid = left + (right - left) / 2; - if (f(piles, mid) == h) { - // 搜索左侧边界,则需要收缩右侧边界 - right = mid; - } else if (f(piles, mid) < h) { - // 需要让 f(x) 的返回值大一些 - right = mid; - } else if (f(piles, mid) > h) { - // 需要让 f(x) 的返回值小一些 + if (fun(piles, mid) == h) { + right = mid - 1; + } else if (fun(piles, mid) < h) { + right = mid - 1; + } else if (fun(piles, mid) > h) { left = mid + 1; } } return left; } - public static long f(int[] arr, int x) { - long hours = 0; - for (int j : arr) { - hours += j / x; - if (j % x > 0) { - hours++; + public static long fun(int[] piles, int speed) { + long hour = 0L; + for (int pile : piles) { + if (pile <= speed) { + hour++; + } else { + hour += pile / speed; + if (pile % speed != 0) { + hour++; + } } } - return hours; + return hour; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" similarity index 61% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" index 7c67582..fc55e9b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.array; +package io.github.dunwu.algorithm.array.range; import org.junit.jupiter.api.Assertions; @@ -12,7 +12,11 @@ public class 二维区域和检索_矩阵不可变 { public static void main(String[] args) { NumMatrix numMatrix = new NumMatrix(new int[][] { - { 3, 0, 1, 4, 2 }, { 5, 6, 3, 2, 1 }, { 1, 2, 0, 1, 5 }, { 4, 1, 0, 1, 7 }, { 1, 0, 3, 0, 5 } + { 3, 0, 1, 4, 2 }, + { 5, 6, 3, 2, 1 }, + { 1, 2, 0, 1, 5 }, + { 4, 1, 0, 1, 7 }, + { 1, 0, 3, 0, 5 } }); Assertions.assertEquals(8, numMatrix.sumRegion(2, 1, 4, 3)); } @@ -22,12 +26,12 @@ static class NumMatrix { private int[][] preSum; public NumMatrix(int[][] matrix) { - int row = matrix.length; - int col = matrix[0].length; - preSum = new int[row + 1][col + 1]; - for (int i = 1; i <= row; i++) { - for (int j = 1; j <= col; j++) { - preSum[i][j] = preSum[i - 1][j] + preSum[i][j - 1] + matrix[i - 1][j - 1] - preSum[i - 1][j - 1]; + final int M = matrix.length; + final int N = matrix[0].length; + preSum = new int[M + 1][N + 1]; + for (int i = 1; i <= M; i++) { + for (int j = 1; j <= N; j++) { + preSum[i][j] = preSum[i][j - 1] + preSum[i - 1][j] - preSum[i - 1][j - 1] + matrix[i - 1][j - 1]; } } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" new file mode 100644 index 0000000..d59ac4e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" @@ -0,0 +1,65 @@ +package io.github.dunwu.algorithm.array.range; + +/** + * 前缀和数组代码模板 + * + * @author Zhang Peng + * @date 2025-10-20 + */ +public class 前缀和数组代码模板 { + + /** + * 一维前缀和 + */ + static class NumArray { + + // 前缀和数组 + private int[] preSum; + + // 输入一个数组,构造前缀和 + public NumArray(int[] nums) { + // preSum[0] = 0,便于计算累加和 + preSum = new int[nums.length + 1]; + // 计算 nums 的累加和 + for (int i = 1; i < preSum.length; i++) { + preSum[i] = preSum[i - 1] + nums[i - 1]; + } + } + + // 查询闭区间 [left, right] 的累加和 + public int sumRange(int left, int right) { + return preSum[right + 1] - preSum[left]; + } + + } + + /** + * 二维前缀和 + */ + static class NumMatrix { + + // preSum[i][j] 记录矩阵 [0, 0, i-1, j-1] 的元素和 + private int[][] preSum; + + public NumMatrix(int[][] matrix) { + int m = matrix.length, n = matrix[0].length; + if (m == 0 || n == 0) return; + // 构造前缀和矩阵 + preSum = new int[m + 1][n + 1]; + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= n; j++) { + // 计算每个矩阵 [0, 0, i, j] 的元素和 + preSum[i][j] = preSum[i - 1][j] + preSum[i][j - 1] + matrix[i - 1][j - 1] - preSum[i - 1][j - 1]; + } + } + } + + // 计算子矩阵 [x1, y1, x2, y2] 的元素和 + public int sumRegion(int x1, int y1, int x2, int y2) { + // 目标矩阵之和由四个相邻矩阵运算获得 + return preSum[x2 + 1][y2 + 1] - preSum[x1][y2 + 1] - preSum[x2 + 1][y1] + preSum[x1][y1]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" similarity index 95% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" index da25066..276664c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.array; +package io.github.dunwu.algorithm.array.range; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" new file mode 100644 index 0000000..76d7295 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" @@ -0,0 +1,49 @@ +package io.github.dunwu.algorithm.array.range; + +/** + * 差分数组代码模板 + * + * @author Zhang Peng + * @date 2025-10-20 + */ +public class 差分数组代码模板 { + + // 差分数组工具类 + static class Difference { + + // 差分数组 + private int[] diff; + + // 输入一个初始数组,区间操作将在这个数组上进行 + public Difference(int[] nums) { + assert nums.length > 0; + diff = new int[nums.length]; + // 根据初始数组构造差分数组 + diff[0] = nums[0]; + for (int i = 1; i < nums.length; i++) { + diff[i] = nums[i] - nums[i - 1]; + } + } + + // 给闭区间 [i, j] 增加 val(可以是负数) + public void increment(int i, int j, int val) { + diff[i] += val; + if (j + 1 < diff.length) { + diff[j + 1] -= val; + } + } + + // 返回结果数组 + public int[] result() { + int[] res = new int[diff.length]; + // 根据差分数组构造结果数组 + res[0] = diff[0]; + for (int i = 1; i < diff.length; i++) { + res[i] = res[i - 1] + diff[i]; + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" new file mode 100644 index 0000000..252a99f --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" @@ -0,0 +1,76 @@ +package io.github.dunwu.algorithm.array.range; + +import org.junit.jupiter.api.Assertions; + +/** + * 1094. 屁车 + * + * @author Zhang Peng + * @date 2025-10-17 + */ +public class 拼车 { + + public static void main(String[] args) { + int[][] bookings = { { 2, 1, 5 }, { 3, 3, 7 } }; + Assertions.assertFalse(carPooling(bookings, 4)); + + int[][] bookings2 = { { 1, 2, 10 }, { 2, 2, 15 } }; + Assertions.assertTrue(carPooling(bookings2, 5)); + } + + public static boolean carPooling(int[][] trips, int capacity) { + int[] nums = new int[1001]; + Difference df = new Difference(nums); + for (int[] trip : trips) { + // 乘客数量 + int val = trip[0]; + // 第 trip[1] 站乘客上车 + int i = trip[1]; + // 第 trip[2] 站乘客已经下车, + // 即乘客在车上的区间是 [trip[1], trip[2] - 1] + int j = trip[2] - 1; + // 进行区间操作 + df.increase(i, j, val); + } + int[] result = df.result(); + + // 客车自始至终都不应该超载 + for (int res : result) { + if (capacity < res) { + return false; + } + } + return true; + } + + static class Difference { + + private int[] diff; + + public Difference(int[] nums) { + diff = new int[nums.length]; + diff[0] = nums[0]; + for (int i = 1; i < diff.length; i++) { + diff[i] = nums[i] - nums[i - 1]; + } + } + + public void increase(int left, int right, int val) { + diff[left - 1] += val; + if (right < diff.length) { + diff[right] -= val; + } + } + + public int[] result() { + int[] result = new int[diff.length]; + result[0] = diff[0]; + for (int i = 1; i < diff.length; i++) { + result[i] = result[i - 1] + diff[i]; + } + return result; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" new file mode 100644 index 0000000..5ff7556 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" @@ -0,0 +1,41 @@ +package io.github.dunwu.algorithm.array.range; + +import cn.hutool.json.JSONUtil; +import org.junit.jupiter.api.Assertions; + +/** + * 1109. 航班预订统计 + * + * @author Zhang Peng + * @date 2025-10-17 + */ +public class 航班预订统计 { + + public static void main(String[] args) { + int[][] bookings = { { 1, 2, 10 }, { 2, 3, 20 }, { 2, 5, 25 } }; + Assertions.assertArrayEquals(new int[] { 10, 55, 45, 25, 25 }, corpFlightBookings(bookings, 5)); + + int[][] bookings2 = { { 1, 2, 10 }, { 2, 2, 15 } }; + Assertions.assertArrayEquals(new int[] { 10, 25 }, corpFlightBookings(bookings2, 2)); + } + + public static int[] corpFlightBookings(int[][] bookings, int n) { + int[] array = new int[n]; + for (int[] order : bookings) { + int left = order[0], right = order[1], num = order[2]; + array[left - 1] += num; + if (right < n) { + array[right] -= num; + } + // System.out.println("array: " + JSONUtil.toJsonStr(array)); + } + int[] result = new int[n]; + result[0] = array[0]; + for (int i = 1; i < n; i++) { + result[i] = array[i] + result[i - 1]; + } + // System.out.println("result: " + JSONUtil.toJsonStr(result)); + return result; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" deleted file mode 100644 index dc69777..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.dunwu.algorithm.queue; - -import java.util.LinkedList; -import java.util.Queue; - -/** - * 933. 最近的请求次数 - * - * @author Zhang Peng - * @since 2020-06-10 - */ -public class 最近的请求次数 { - - public static void main(String[] args) { - RecentCounter recentCounter = new RecentCounter(); - recentCounter.ping(1); - recentCounter.ping(100); - } - - static class RecentCounter { - - Queue q = new LinkedList<>(); - - public RecentCounter() { - - } - - public int ping(int t) { - q.offer(t); - while (q.peek() < t - 3000) { - q.poll(); - } - return q.size(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\256\276\350\256\241\345\276\252\347\216\257\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\256\276\350\256\241\345\276\252\347\216\257\351\230\237\345\210\227.java" deleted file mode 100644 index 380f53f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\256\276\350\256\241\345\276\252\347\216\257\351\230\237\345\210\227.java" +++ /dev/null @@ -1,111 +0,0 @@ -package io.github.dunwu.algorithm.queue; - -/** - * @author Zhang Peng - * @see 622. 设计循环队列 - * @since 2020-06-10 - */ -public class 设计循环队列 { - - public static void main(String[] args) { - 设计循环队列 queue = new 设计循环队列(3); - queue.enQueue(1); - queue.enQueue(2); - queue.enQueue(3); - queue.enQueue(4); - queue.printAll(); - System.out.println("rear: " + queue.Rear()); - System.out.println("full: " + queue.isFull()); - queue.deQueue(); - queue.enQueue(4); - queue.printAll(); - System.out.println("rear: " + queue.Rear()); - } - - private int[] data; - private int head; - // head表示队头下标,tail表示队尾下标 - private int tail; - private int capacity; - - // 申请一个大小为capacity的数组(由于循环队列会浪费一个空间,所以如果想要存储元素数为capacity,数组维度n=capacity+1) - public 设计循环队列(int k) { - this.capacity = k + 1; - this.data = new int[capacity]; - this.head = 0; - this.tail = 0; - } - - /** Insert an element into the circular queue. Return true if the operation is successful. */ - public boolean enQueue(int value) { - if (isFull()) { - return false; - } - - this.data[tail] = value; - tail = (tail + 1) % capacity; - return true; - } - - /** Delete an element from the circular queue. Return true if the operation is successful. */ - public boolean deQueue() { - if (isEmpty()) { - return false; - } - - head = (head + 1) % capacity; - return true; - } - - /** Get the front item from the queue. */ - public int Front() { - if (isEmpty()) { - return -1; - } - - return data[head]; - } - - /** Get the last item from the queue. */ - public int Rear() { - if (isEmpty()) { - return -1; - } - - int temp = (tail - 1 + capacity) % capacity; - return data[temp]; - } - - /** Checks whether the circular queue is empty or not. */ - public boolean isEmpty() { - if (head == tail) { - return true; - } - return false; - } - - /** Checks whether the circular queue is full or not. */ - public boolean isFull() { - if ((tail + 1) % capacity == head) { - return true; - } - return false; - } - - public void printAll() { - if (head == tail) { - System.out.println("队列已空"); - return; - } - for (int i = head; i != tail; ) { - System.out.print(data[i] + "\t"); - if (i == capacity - 1) { - i = 0; - } else { - i++; - } - } - System.out.println(); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/SampleBrowser.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/SampleBrowser.java similarity index 98% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/SampleBrowser.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/SampleBrowser.java index ac44ef7..50e679a 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/SampleBrowser.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/SampleBrowser.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack; /** * 使用前后栈实现浏览器的前进后退。 diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/StackBasedOnLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/StackBasedOnLinkedList.java similarity index 96% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/StackBasedOnLinkedList.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/StackBasedOnLinkedList.java index f45a3de..8f4ece3 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/StackBasedOnLinkedList.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/StackBasedOnLinkedList.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack; /** * 基于链表实现的栈。 diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/GenericQueue.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/GenericQueue.java similarity index 95% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/GenericQueue.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/GenericQueue.java index f75c96b..9f63e2d 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/GenericQueue.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/GenericQueue.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue; +package io.github.dunwu.algorithm.queue_and_stack.queue; /** * @author Zhang Peng diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/MyCircularDeque.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/MyCircularDeque.java similarity index 98% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/MyCircularDeque.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/MyCircularDeque.java index 8d4bed9..da96c42 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/MyCircularDeque.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/MyCircularDeque.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue; +package io.github.dunwu.algorithm.queue_and_stack.queue; /** * @author Zhang Peng diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" index dc4f3f8..eb5fed7 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue; +package io.github.dunwu.algorithm.queue_and_stack.queue; import java.util.Arrays; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" index 1c55892..83d7a97 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue; +package io.github.dunwu.algorithm.queue_and_stack.queue; /** * 用数组实现的队列 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" new file mode 100644 index 0000000..97ed853 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" @@ -0,0 +1,36 @@ +package io.github.dunwu.algorithm.queue_and_stack.queue; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * 933. 最近的请求次数 + * + * @author Zhang Peng + * @since 2020-06-10 + */ +public class 最近的请求次数 { + + public static void main(String[] args) { + RecentCounter recentCounter = new RecentCounter(); + recentCounter.ping(1); // requests = [1],范围是 [-2999,1],返回 1 + recentCounter.ping(100); // requests = [1, 100],范围是 [-2900,100],返回 2 + recentCounter.ping(3001); // requests = [1, 100, 3001],范围是 [1,3001],返回 3 + recentCounter.ping(3002); // requests = [1, 100, 3001, 3002],范围是 [2,3002],返回 3 + } + + static class RecentCounter { + + Queue queue = new LinkedList<>(); + + public int ping(int t) { + queue.offer(t); + while (queue.peek() < t - 3000) { + queue.poll(); + } + return queue.size(); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" index 5237442..3df21c2 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue; +package io.github.dunwu.algorithm.queue_and_stack.queue; /** * 基于链表实现的队列 diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/GenericStack.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/GenericStack.java similarity index 95% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/GenericStack.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/GenericStack.java index ac5bd96..1ac2fb0 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/GenericStack.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/GenericStack.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack.stack; /** * 简化版泛型栈 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" similarity index 77% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" index b7377df..3486bc7 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" @@ -1,9 +1,10 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack.stack; import org.junit.jupiter.api.Assertions; import java.util.Deque; import java.util.LinkedList; +import java.util.Stack; /** * 150. 逆波兰表达式求值 @@ -15,6 +16,10 @@ public class 文件的最长绝对路径 { public static void main(String[] args) { Assertions.assertEquals(20, lengthLongestPath("dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext")); + Assertions.assertEquals(32, lengthLongestPath( + "dir\\n\\tsubdir1\\n\\t\\tfile1.ext\\n\\t\\tsubsubdir1\\n\\tsubdir2\\n\\t\\tsubsubdir2\\n\\t\\t\\tfile2.ext")); + Assertions.assertEquals(0, lengthLongestPath("a")); + Assertions.assertEquals(12, lengthLongestPath("file1.txt\\nfile2.txt\\nlongfile.txt")); } public static int lengthLongestPath(String input) { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" new file mode 100644 index 0000000..01d98a8 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" @@ -0,0 +1,61 @@ +package io.github.dunwu.algorithm.queue_and_stack.stack; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; +import java.util.Stack; +import java.util.TreeMap; + +/** + * 895. 最大频率栈 + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 最大频率栈 { + + public static void main(String[] args) { + FreqStack s1 = new FreqStack(); + s1.push(5);//堆栈为 [5] + s1.push(7);//堆栈是 [5,7] + s1.push(5);//堆栈是 [5,7,5] + s1.push(7);//堆栈是 [5,7,5,7] + s1.push(4);//堆栈是 [5,7,5,7,4] + s1.push(5);//堆栈是 [5,7,5,7,4,5] + Assertions.assertEquals(5, s1.pop()); //返回 5 ,因为 5 出现频率最高。堆栈变成 [5,7,5,7,4] + Assertions.assertEquals(7, s1.pop()); //返回 7 ,因为 5 和 7 出现频率最高,但7最接近顶部。堆栈变成 [5,7,5,4]。 + Assertions.assertEquals(5, s1.pop()); //返回 5 ,因为 5 出现频率最高。堆栈变成 [5,7,4]。 + Assertions.assertEquals(4, s1.pop()); //返回 4 ,因为 4, 5 和 7 出现频率最高,但 4 是最接近顶部的。堆栈变成 [5,7]。 + } + + static class FreqStack { + + int maxFreq = 0; + HashMap valToFreq = new HashMap<>(); + TreeMap> freqToVal = new TreeMap<>(); + + public FreqStack() { + } + + public void push(int val) { + int freq = valToFreq.getOrDefault(val, 0) + 1; + valToFreq.put(val, freq); + freqToVal.putIfAbsent(freq, new Stack<>()); + freqToVal.get(freq).add(val); + maxFreq = Math.max(maxFreq, freq); + } + + public int pop() { + Stack vals = freqToVal.get(maxFreq); + int v = vals.pop(); + int freq = valToFreq.get(v) - 1; + valToFreq.put(v, freq); + if (vals.isEmpty()) { + maxFreq--; + } + return v; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\260\217\346\240\210.java" similarity index 51% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\260\217\346\240\210.java" index 0edb40f..97f1b47 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\260\217\346\240\210.java" @@ -1,13 +1,14 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack.stack; import org.junit.jupiter.api.Assertions; -import java.util.LinkedList; -import java.util.Queue; import java.util.Stack; /** - * @see 面试题 03.02. 栈的最小值 + * 面试题 03.02. 栈的最小值 + * + * @author Zhang Peng + * @date 2025-10-20 */ public class 最小栈 { @@ -24,30 +25,28 @@ public static void main(String[] args) { static class MinStack { - Stack stack = new Stack<>(); - Stack minStack = new Stack<>(); + private Stack stack; + private Stack min; public MinStack() { - + stack = new Stack<>(); + min = new Stack<>(); } public void push(int val) { stack.push(val); - if (minStack.isEmpty()) { - minStack.push(val); + if (min.isEmpty() || val <= min.peek()) { + // 新插入的这个元素就是全栈最小的 + min.push(val); } else { - Integer lastMin = minStack.peek(); - if (val <= lastMin) { - minStack.push(val); - } else { - minStack.push(lastMin); - } + // 插入的这个元素比较大 + min.push(min.peek()); } } - public int pop() { - minStack.pop(); - return stack.pop(); + public void pop() { + stack.pop(); + min.pop(); } public int top() { @@ -55,7 +54,7 @@ public int top() { } public int getMin() { - return minStack.peek(); + return min.peek(); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" index 142efac..1cdba8d 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack.stack; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" new file mode 100644 index 0000000..9bbf399 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" @@ -0,0 +1,46 @@ +package io.github.dunwu.algorithm.queue_and_stack.stack; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 71. 简化路径 + * + * @author Zhang Peng + * @since 2025-08-08 + */ +public class 简化路径 { + + public static void main(String[] args) { + Assertions.assertEquals("/home", simplifyPath("/home/")); + Assertions.assertEquals("/home/foo", simplifyPath("/home//foo/")); + Assertions.assertEquals("/home/user/Pictures", simplifyPath("/home/user/Documents/../Pictures")); + Assertions.assertEquals("/", simplifyPath("/../")); + Assertions.assertEquals("/.../b/d", simplifyPath("/.../a/../b/c/../d/./")); + } + + public static String simplifyPath(String path) { + Stack s1 = new Stack<>(); + for (String str : path.split("/")) { + switch (str) { + case "": + case ".": + break; + case "..": + if (!s1.isEmpty()) s1.pop(); + break; + default: + s1.push(str); + break; + } + } + + StringBuilder result = new StringBuilder(); + while (!s1.isEmpty()) { + result.insert(0, "/" + s1.pop()); + } + return result.toString().equals("") ? "/" : result.toString(); + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" index 252871f..7be3e73 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack.stack; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" index 361f95e..d0b428b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack.stack; import io.github.dunwu.algorithm.list.ListNode; import io.github.dunwu.algorithm.list.ListUtil; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\344\270\211\345\220\210\344\270\200.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\211\345\220\210\344\270\200.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\344\270\211\345\220\210\344\270\200.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\211\345\220\210\344\270\200.java" index b38b134..c4379a9 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\344\270\211\345\220\210\344\270\200.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\211\345\220\210\344\270\200.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack; import java.util.ArrayList; import java.util.LinkedList; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" index d95976b..4b7ae2c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" @@ -1,9 +1,7 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack; import org.junit.jupiter.api.Assertions; -import java.util.Deque; -import java.util.LinkedList; import java.util.Stack; /** diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" similarity index 94% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" index 1e41699..c63bd08 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" @@ -1,5 +1,6 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack; +import io.github.dunwu.algorithm.queue_and_stack.stack.GenericStack; import org.junit.jupiter.api.Assertions; /** diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\240\210\346\216\222\345\272\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\240\210\346\216\222\345\272\217.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\240\210\346\216\222\345\272\217.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\240\210\346\216\222\345\272\217.java" index 8e9e1ef..86ee967 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\240\210\346\216\222\345\272\217.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\240\210\346\216\222\345\272\217.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack; import java.util.LinkedList; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" similarity index 90% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" index 57d7263..ad3b205 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" @@ -1,4 +1,6 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack; + +import io.github.dunwu.algorithm.queue_and_stack.stack.GenericStack; /** * @author Zhang Peng diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" similarity index 90% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" index 6315118..fcb066a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" @@ -1,5 +1,6 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack; +import io.github.dunwu.algorithm.queue_and_stack.stack.GenericStack; import org.junit.jupiter.api.Assertions; /** diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" new file mode 100644 index 0000000..ff3d6ad --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" @@ -0,0 +1,81 @@ +package io.github.dunwu.algorithm.queue_and_stack; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 232. 用栈实现队列 + * + * @author Zhang Peng + * @since 2020-01-18 + */ +public class 用栈实现队列 { + + public static void main(String[] args) { + + // MyQueue q1 = new MyQueue(); + // q1.push(1); // queue is: [1] + // q1.push(2); // queue is: [1, 2] (leftmost is front of the queue) + // Assertions.assertEquals(1, q1.peek()); + // Assertions.assertEquals(1, q1.pop()); + // Assertions.assertFalse(q1.empty()); + // Assertions.assertEquals(2, q1.pop()); + // Assertions.assertTrue(q1.empty()); + + MyQueue q2 = new MyQueue(); + q2.push(1); + q2.push(2); + Assertions.assertEquals(1, q2.pop()); + q2.push(3); + q2.push(4); + Assertions.assertEquals(2, q2.pop()); + Assertions.assertEquals(3, q2.peek()); + + MyQueue q3 = new MyQueue(); + int max = 10; + for (int i = 1; i <= max; i++) { + q3.push(i); + } + for (int i = 1; i <= max; i++) { + Assertions.assertEquals(i, q3.peek()); + Assertions.assertEquals(i, q3.pop()); + } + } + + static class MyQueue { + + private Stack s1; + private Stack s2; + + public MyQueue() { + s1 = new Stack<>(); + s2 = new Stack<>(); + } + + public void push(int x) { + s1.push(x); + } + + public int pop() { + peek(); + Integer top = s2.pop(); + return top == null ? 0 : top; + } + + public int peek() { + if (s2.isEmpty()) { + while (!s1.isEmpty()) { + s2.push(s1.pop()); + } + } + return s2.isEmpty() ? 0 : s2.peek(); + } + + public boolean empty() { + return s1.isEmpty() && s2.isEmpty(); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" similarity index 57% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" index d6c3ab8..e5b036f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.stack; +package io.github.dunwu.algorithm.queue_and_stack; import org.junit.jupiter.api.Assertions; @@ -14,6 +14,13 @@ public class 用队列实现栈 { public static void main(String[] args) { + MyStack s1 = new MyStack(); + s1.push(1); + s1.push(2); + Assertions.assertEquals(2, s1.top()); + Assertions.assertEquals(2, s1.pop()); + Assertions.assertFalse(s1.empty()); + int max = 10; MyStack stack = new MyStack(); for (int i = 1; i <= max; i++) { @@ -27,34 +34,34 @@ public static void main(String[] args) { static class MyStack { - int top = -1; - Queue queue = new LinkedList<>(); + private Integer top; + Queue q; - public MyStack() { } + public MyStack() { + q = new LinkedList<>(); + } public void push(int x) { + q.offer(x); top = x; - queue.offer(x); } public int pop() { - int size = queue.size(); - while (size > 2) { - queue.offer(queue.poll()); - size--; + int size = q.size(); + for (int i = 1; i < size; i++) { + Integer val = q.poll(); + q.offer(val); + top = val; } - // 倒数第 2 个值作为 top - top = queue.poll(); - queue.offer(top); - return queue.poll(); + return q.poll(); } public int top() { - return top; + return top == null ? 0 : top; } public boolean empty() { - return queue.isEmpty(); + return q.isEmpty(); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" deleted file mode 100644 index cc7c33d..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import io.github.dunwu.algorithm.list.ListNode; -import io.github.dunwu.algorithm.list.ListUtil; -import org.junit.jupiter.api.Assertions; - -import java.util.List; -import java.util.Stack; - -/** - * 143. 重排链表 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 最大频率栈 { - - public static void main(String[] args) { - ListNode input = ListUtil.buildList(1, 2, 3, 4); - reorderList(input); - List list = ListUtil.toList(input); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 1, 4, 2, 3 }, list.toArray()); - } - - public static void reorderList(ListNode head) { - - if (head == null || head.next == null) { - return; - } - - ListNode p = head; - int total = 0; - Stack stack = new Stack<>(); - while (p != null) { - stack.push(p); - total++; - p = p.next; - } - - p = head; - int cnt = 0; - while (p != null && cnt < total) { - if (cnt % 2 == 0) { - ListNode node = stack.pop(); - node.next = p.next; - p.next = node; - } - p = p.next; - cnt++; - } - p.next = null; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" deleted file mode 100644 index 2c674a5..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" +++ /dev/null @@ -1,56 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 232. 用栈实现队列 - * - * @author Zhang Peng - * @since 2020-01-18 - */ -public class 用栈实现队列 { - - public static void main(String[] args) { - MyStack queue = new MyStack(); - int max = 10; - for (int i = 1; i <= max; i++) { - queue.push(i); - } - for (int i = 1; i <= max; i++) { - Assertions.assertEquals(i, queue.peek()); - Assertions.assertEquals(i, queue.pop()); - } - } - - static class MyStack { - - private LinkedList s1 = new LinkedList<>(); - private LinkedList s2 = new LinkedList<>(); - - public void push(int x) { - s1.push(x); - } - - public int pop() { - peek(); - return s2.pop(); - } - - public int peek() { - if (s2.isEmpty()) { - while (!s1.isEmpty()) { - s2.push(s1.pop()); - } - } - return s2.peek(); - } - - public boolean empty() { - return s1.isEmpty() && s2.isEmpty(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" deleted file mode 100644 index c4f6b36..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" +++ /dev/null @@ -1,42 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 71. 简化路径 - * - * @author Zhang Peng - * @since 2025-08-08 - */ -public class 简化路径 { - - public static void main(String[] args) { - Assertions.assertEquals("/home", simplifyPath("/home/")); - Assertions.assertEquals("/home/foo", simplifyPath("/home//foo/")); - Assertions.assertEquals("/home/user/Pictures", simplifyPath("/home/user/Documents/../Pictures")); - Assertions.assertEquals("/", simplifyPath("/../")); - } - - public static String simplifyPath(String path) { - String[] parts = path.split("/"); - Stack stack = new Stack<>(); - for (String part : parts) { - if (part.isEmpty() || part.equals(".")) continue; - if (part.equals("..")) { - if (!stack.isEmpty()) { - stack.pop(); - } - } else { - stack.push(part); - } - } - String res = ""; - while (!stack.isEmpty()) { - res = "/" + stack.pop() + res; - } - return res.isEmpty() ? "/" : res; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BTree.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BTree.java index d953673..0e14249 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BTree.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BTree.java @@ -1,6 +1,10 @@ package io.github.dunwu.algorithm.tree; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; /** * 二叉树 diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeNode.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeNode.java index a552ff1..d6e1f92 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeNode.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeNode.java @@ -1,8 +1,15 @@ package io.github.dunwu.algorithm.tree; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; import java.util.Objects; +import java.util.Queue; /** + * 二叉树节点 + * * @author Zhang Peng * @since 2020-01-28 */ @@ -42,4 +49,145 @@ public int hashCode() { return Objects.hash(val, left, right); } + public static String serialize(TreeNode root) { + return serialize(root, "NULL", ","); + } + + public static String serialize(TreeNode root, String nullFlag, String sepFlag) { + StringBuilder sb = new StringBuilder(); + doSerialize(root, sb, nullFlag, sepFlag); + return sb.toString(); + } + + static void doSerialize(TreeNode root, StringBuilder sb, String nullFlag, String sepFlag) { + if (root == null) { + sb.append(nullFlag).append(sepFlag); + return; + } + sb.append(root.val).append(sepFlag); + doSerialize(root.left, sb, nullFlag, sepFlag); + doSerialize(root.right, sb, nullFlag, sepFlag); + } + + public static TreeNode deserialize(String data) { + return deserialize(data, "NULL", ","); + } + + public static TreeNode deserialize(String data, String nullFlag, String sepFlag) { + LinkedList nodes = new LinkedList<>(Arrays.asList(data.split(sepFlag))); + return doDeserialize(nodes, nullFlag); + } + + static TreeNode doDeserialize(LinkedList nodes, String nullFlag) { + if (nodes.isEmpty()) return null; + + // =============== 前序遍历处理 =============== + String val = nodes.removeFirst(); + if (nullFlag.equals(val)) { return null; } + TreeNode root = new TreeNode(Integer.parseInt(val)); + // ========================================== + + root.left = doDeserialize(nodes, nullFlag); + root.right = doDeserialize(nodes, nullFlag); + return root; + } + + public static TreeNode buildTree(Integer... values) { + + if (values == null || values.length == 0 || values[0] == null) { + return null; + } + + Queue queue = new LinkedList<>(); + TreeNode root = new TreeNode(values[0]); + queue.offer(root); + + int i = 1; + while (!queue.isEmpty() && i < values.length) { + TreeNode current = queue.poll(); + + // 处理左子节点 + if (i < values.length && values[i] != null) { + current.left = new TreeNode(values[i]); + queue.offer(current.left); + } + i++; + + // 处理右子节点 + if (i < values.length && values[i] != null) { + current.right = new TreeNode(values[i]); + queue.offer(current.right); + } + i++; + } + + return root; + } + + public static TreeNode find(TreeNode root, int val) { + if (root == null || root.val == val) { return root; } + TreeNode left = find(root.left, val); + if (left != null) return left; + return find(root.right, val); + } + + public static List toList(TreeNode root) { + List list = new ArrayList<>(); + if (root == null) { + return list; + } + + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + TreeNode node = queue.poll(); + list.add(node); + if (node == null) continue; + queue.add(node.left); + queue.add(node.right); + } + + // 删除队列尾部的所有 null + int last = list.size() - 1; + while (last > 0 && list.get(last) == null) { + last--; + } + return list.subList(0, last + 1); + } + + public static List toValueList(TreeNode root) { + List list = new ArrayList<>(); + if (root == null) { + return list; + } + + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + TreeNode node = queue.poll(); + if (node == null) { + list.add(null); + continue; + } else { + list.add(node.val); + } + + queue.add(node.left); + queue.add(node.right); + } + + // 删除队列尾部的所有 null + int last = list.size() - 1; + while (last > 0 && list.get(last) == null) { + last--; + } + return list.subList(0, last + 1); + } + + static enum Order { + PreOrder, + InOrder, + PostOrder + } + } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeUtils.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeUtils.java deleted file mode 100644 index 149adf3..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeUtils.java +++ /dev/null @@ -1,169 +0,0 @@ -package io.github.dunwu.algorithm.tree; - -import java.util.*; - -/** - * @author Zhang Peng - * @since 2020-01-28 - */ -public class TreeUtils { - - public static TreeNode buildTree(Integer... values) { - - if (values == null || values.length == 0 || values[0] == null) { - return null; - } - - Queue queue = new LinkedList<>(); - TreeNode root = new TreeNode(values[0]); - queue.offer(root); - - int i = 1; - while (!queue.isEmpty() && i < values.length) { - TreeNode current = queue.poll(); - - // 处理左子节点 - if (i < values.length && values[i] != null) { - current.left = new TreeNode(values[i]); - queue.offer(current.left); - } - i++; - - // 处理右子节点 - if (i < values.length && values[i] != null) { - current.right = new TreeNode(values[i]); - queue.offer(current.right); - } - i++; - } - - return root; - } - - public static TreeNode find(TreeNode root, int val) { - if (root == null || root.val == val) { return root; } - TreeNode left = find(root.left, val); - if (left != null) return left; - return find(root.right, val); - } - - public static void depthOrderTraverse(TreeNode root) { - if (root == null) { - return; - } - LinkedList stack = new LinkedList<>(); - stack.push(root); - while (!stack.isEmpty()) { - TreeNode node = stack.pop(); - System.out.print(node.val + " "); - if (node.left != null) stack.push(node.left); - if (node.right != null) stack.push(node.right); - } - } - - public static List toList(TreeNode root) { - List list = new ArrayList<>(); - if (root == null) { - return list; - } - - Queue queue = new LinkedList<>(); - queue.add(root); - while (!queue.isEmpty()) { - TreeNode node = queue.poll(); - list.add(node); - if (node == null) continue; - queue.add(node.left); - queue.add(node.right); - } - - // 删除队列尾部的所有 null - int last = list.size() - 1; - while (last > 0 && list.get(last) == null) { - last--; - } - return list.subList(0, last + 1); - } - - public static List toValueList(TreeNode root) { - List list = new ArrayList<>(); - if (root == null) { - return list; - } - - Queue queue = new LinkedList<>(); - queue.add(root); - while (!queue.isEmpty()) { - TreeNode node = queue.poll(); - if (node == null) { - list.add(null); - continue; - } else { - list.add(node.val); - } - - queue.add(node.left); - queue.add(node.right); - } - - // 删除队列尾部的所有 null - int last = list.size() - 1; - while (last > 0 && list.get(last) == null) { - last--; - } - return list.subList(0, last + 1); - } - - public static String serialize(TreeNode root, String NULL, String SEP) { - StringBuilder sb = new StringBuilder(); - serializePreOrder(root, sb, NULL, SEP); - int size = sb.length(); - int pos = sb.lastIndexOf(SEP); - if (pos == size - 1) { - sb.deleteCharAt(pos); - } - return sb.toString(); - } - - static void serializePreOrder(TreeNode root, StringBuilder sb, String NULL, String SEP) { - if (root == null) { - sb.append(NULL).append(SEP); - return; - } - - // 前序处理 - sb.append(root.val).append(SEP); - - serializePreOrder(root.left, sb, NULL, SEP); - serializePreOrder(root.right, sb, NULL, SEP); - } - - public static TreeNode deserialize(String data, String SEP, String NULL) { - // 将字符串转化成列表 - LinkedList nodes = new LinkedList<>(); - for (String s : data.split(SEP)) { - nodes.addLast(s); - } - return deserializePreOrder(nodes, NULL); - } - - static TreeNode deserializePreOrder(LinkedList nodes, String NULL) { - if (nodes.isEmpty()) return null; - - String first = nodes.removeFirst(); - if (first.equals(NULL)) return null; - TreeNode root = new TreeNode(Integer.parseInt(first)); - - root.left = deserializePreOrder(nodes, NULL); - root.right = deserializePreOrder(nodes, NULL); - - return root; - } - - public static void main(String[] args) { - Integer[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - TreeNode head = TreeUtils.buildTree(array); - toList(head); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" index 27f8d70..9a6925c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" @@ -1,36 +1,38 @@ package io.github.dunwu.algorithm.tree.bstree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; - -import java.util.List; +import org.junit.jupiter.api.Assertions; /** + * 701. 二叉搜索树中的插入操作 + * * @author Zhang Peng - * @see 701. 二叉搜索树中的插入操作 * @since 2020-07-06 */ public class 二叉搜索树中的插入操作 { public static void main(String[] args) { - TreeNode tree = TreeUtils.buildTree(4, 2, 7, 1, 3); - insertIntoBST(tree, 5); - List treeNodes = TreeUtils.toList(tree); - System.out.println(treeNodes); + TreeNode input1 = TreeNode.buildTree(4, 2, 7, 1, 3); + TreeNode output1 = insertIntoBST(input1, 5); + Assertions.assertArrayEquals(new Integer[] { 4, 2, 7, 1, 3, 5 }, TreeNode.toValueList(output1).toArray()); + + TreeNode input2 = TreeNode.buildTree(40, 20, 60, 10, 30, 50, 70); + TreeNode output2 = insertIntoBST(input2, 25); + Assertions.assertArrayEquals(new Integer[] { 40, 20, 60, 10, 30, 50, 70, null, null, 25 }, + TreeNode.toValueList(output2).toArray()); + + TreeNode input3 = TreeNode.buildTree(4, 2, 7, 1, 3, null, null, null, null, null, null); + TreeNode output3 = insertIntoBST(input3, 5); + Assertions.assertArrayEquals(new Integer[] { 4, 2, 7, 1, 3, 5 }, + TreeNode.toValueList(output3).toArray()); } public static TreeNode insertIntoBST(TreeNode root, int val) { - if (root == null) return new TreeNode(val); - - TreeNode node = root; - if (val > node.val) { - if (node.right == null) { - node.right = new TreeNode(val); - } else { insertIntoBST(node.right, val); } + if (root == null) { return new TreeNode(val); } + if (root.val < val) { + root.right = (root.right == null) ? new TreeNode(val) : insertIntoBST(root.right, val); } else { - if (node.left == null) { - node.left = new TreeNode(val); - } else { insertIntoBST(node.left, val); } + root.left = (root.left == null) ? new TreeNode(val) : insertIntoBST(root.left, val); } return root; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\220\234\347\264\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\220\234\347\264\242.java" new file mode 100644 index 0000000..9650df6 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\220\234\347\264\242.java" @@ -0,0 +1,41 @@ +package io.github.dunwu.algorithm.tree.bstree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +/** + * 538. 把二叉搜索树转换为累加树 + * + * @author Zhang Peng + * @date 2025-10-22 + */ +public class 二叉搜索树中的搜索 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + TreeNode input1 = TreeNode.buildTree(4, 2, 7, 1, 3); + TreeNode output1 = s.searchBST(input1, 2); + Assertions.assertArrayEquals(new Integer[] { 2, 1, 3 }, TreeNode.toValueList(output1).toArray()); + + TreeNode output2 = s.searchBST(input1, 5); + Assertions.assertNull(output2); + } + + static class Solution { + + public TreeNode searchBST(TreeNode root, int val) { + if (root == null) { return null; } + if (root.val == val) { + return root; + } else if (root.val < val) { + return searchBST(root.right, val); + } else { + return searchBST(root.left, val); + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" new file mode 100644 index 0000000..5854957 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" @@ -0,0 +1,47 @@ +package io.github.dunwu.algorithm.tree.bstree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +/** + * 98. 验证二叉搜索树 + * + * @author Zhang Peng + * @date 2025-10-22 + */ +public class 二叉搜索树中第K小的元素 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(1, s.kthSmallest(TreeNode.buildTree(3, 1, 4, null, 2), 1)); + Assertions.assertEquals(3, s.kthSmallest(TreeNode.buildTree(5, 3, 6, 2, 4, null, null, 1), 3)); + } + + static class Solution { + + int res = 0; + int rank = 0; + + public int kthSmallest(TreeNode root, int k) { + if (root == null) { return -1; } + rank = 0; + res = 0; + traverse(root, k); + return res; + } + + void traverse(TreeNode root, int k) { + if (root == null) { return; } + traverse(root.left, k); + rank++; + if (rank == k) { + System.out.printf("val: %s, rank: %d\n", root.val, rank); + res = root.val; + return; + } + traverse(root.right, k); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" index a37fa7d..cc8445a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.bstree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import io.github.dunwu.algorithm.tree.btree.二叉树的最近公共祖先; import org.junit.jupiter.api.Assertions; @@ -14,18 +13,18 @@ public class 二叉搜索树的最近公共祖先 { public static void main(String[] args) { - TreeNode root = TreeUtils.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); - TreeNode p = TreeUtils.find(root, 2); - TreeNode q = TreeUtils.find(root, 8); + TreeNode root = TreeNode.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); + TreeNode p = TreeNode.find(root, 2); + TreeNode q = TreeNode.find(root, 8); // TreeNode treeNode = lowestCommonAncestor(root, p, q); TreeNode treeNode = lowestCommonAncestor2(root, p, q); Assertions.assertNotNull(treeNode); Assertions.assertEquals(6, treeNode.val); System.out.println("公共祖先节点 = " + treeNode.val); - TreeNode root2 = TreeUtils.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); - TreeNode p2 = TreeUtils.find(root2, 2); - TreeNode q2 = TreeUtils.find(root2, 4); + TreeNode root2 = TreeNode.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); + TreeNode p2 = TreeNode.find(root2, 2); + TreeNode q2 = TreeNode.find(root2, 4); // TreeNode treeNode2 = lowestCommonAncestor(root2, p2, q2); TreeNode treeNode2 = lowestCommonAncestor2(root2, p2, q2); Assertions.assertNotNull(treeNode2); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" index 1fb0c28..1f629d5 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.bstree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import java.util.ArrayList; import java.util.Collections; @@ -36,7 +35,7 @@ public class 二叉搜索树节点最小距离 { public static void main(String[] args) { - TreeNode tree = TreeUtils.buildTree(4, 2, 6, 1, 3, null, null); + TreeNode tree = TreeNode.buildTree(4, 2, 6, 1, 3, null, null); System.out.println("result = " + minDiffInBST2(tree)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" new file mode 100644 index 0000000..294af07 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" @@ -0,0 +1,69 @@ +package io.github.dunwu.algorithm.tree.bstree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +/** + * 701. 二叉搜索树中的插入操作 + * + * @author Zhang Peng + * @since 2020-07-06 + */ +public class 删除二叉搜索树中的节点 { + + public static void main(String[] args) { + TreeNode input1 = TreeNode.buildTree(5, 3, 6, 2, 4, null, 7); + TreeNode output1 = deleteNode(input1, 3); + Assertions.assertArrayEquals(new Integer[] { 5, 4, 6, 2, null, null, 7 }, + TreeNode.toValueList(output1).toArray()); + + TreeNode input2 = TreeNode.buildTree(5, 3, 6, 2, 4, null, 7); + TreeNode output2 = deleteNode(input2, 0); + Assertions.assertArrayEquals(new Integer[] { 5, 3, 6, 2, 4, null, 7 }, + TreeNode.toValueList(output2).toArray()); + + TreeNode input3 = TreeNode.buildTree(); + TreeNode output3 = deleteNode(input3, 0); + Assertions.assertNull(output3); + } + + public static TreeNode deleteNode(TreeNode root, int key) { + if (root == null) { return null; } + if (key == root.val) { + // 找到 key,进行处理 + + if (root.left == null && root.right == null) { + // 情况一、无孩子节点:直接删除 + return null; + } else if (root.left != null && root.right == null) { + // 情况二、有一个孩子节点:用孩子节点替换 + root = root.left; + } else if (root.left == null && root.right != null) { + // 情况二、有一个孩子节点:用孩子节点替换 + root = root.right; + } else if (root.left != null && root.right != null) { + // 情况三、有两个孩子节点: + // 从左子树中找最大的节点替换根节点 + // 或从右子树中找最小的节点替换根节点 + TreeNode minRight = getMin(root.right); + minRight.right = deleteNode(root.right, minRight.val); + minRight.left = root.left; + root = minRight; + } + } else if (key < root.val) { + // 在左子树查找、处理 + root.left = deleteNode(root.left, key); + } else if (key > root.val) { + // 在右子树查找、处理 + root.right = deleteNode(root.right, key); + } + return root; + } + + static TreeNode getMin(TreeNode root) { + if (root == null) { return null; } + if (root.left == null) { return root; } + return getMin(root.left); + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\346\212\212\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\275\254\346\215\242\344\270\272\347\264\257\345\212\240\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\346\212\212\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\275\254\346\215\242\344\270\272\347\264\257\345\212\240\346\240\221.java" new file mode 100644 index 0000000..2b0c161 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\346\212\212\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\275\254\346\215\242\344\270\272\347\264\257\345\212\240\346\240\221.java" @@ -0,0 +1,58 @@ +package io.github.dunwu.algorithm.tree.bstree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +/** + * 538. 把二叉搜索树转换为累加树 + * + * @author Zhang Peng + * @date 2025-10-22 + */ +public class 把二叉搜索树转换为累加树 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + TreeNode input1 = TreeNode.buildTree(4, 1, 6, 0, 2, 5, 7, null, null, null, 3, null, null, null, 8); + TreeNode output1 = s.convertBST(input1); + Assertions.assertArrayEquals( + new Integer[] { 30, 36, 21, 36, 35, 26, 15, null, null, null, 33, null, null, null, 8 }, + TreeNode.toValueList(output1).toArray()); + + TreeNode input2 = TreeNode.buildTree(0, null, 1); + TreeNode output2 = s.convertBST(input2); + Assertions.assertArrayEquals(new Integer[] { 1, null, 1 }, TreeNode.toValueList(output2).toArray()); + + TreeNode input3 = TreeNode.buildTree(1, 0, 2); + TreeNode output3 = s.convertBST(input3); + Assertions.assertArrayEquals(new Integer[] { 3, 3, 2 }, TreeNode.toValueList(output3).toArray()); + + TreeNode input4 = TreeNode.buildTree(3, 2, 4, 1); + TreeNode output4 = s.convertBST(input4); + Assertions.assertArrayEquals(new Integer[] { 7, 9, 4, 10 }, TreeNode.toValueList(output4).toArray()); + } + + static class Solution { + + int sum = 0; + + public TreeNode convertBST(TreeNode root) { + sum = 0; // 重置 + traverse(root); + return root; + } + + public void traverse(TreeNode root) { + if (root == null) return; + traverse(root.right); + sum += root.val; + root.val = sum; + // System.out.printf("val: %d\n", root.val); + traverse(root.left); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" index 6a2fe32..adb4acb 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" @@ -1,11 +1,8 @@ package io.github.dunwu.algorithm.tree.bstree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; -import java.util.*; - /** * 98. 验证二叉搜索树 算法实现 * @@ -16,54 +13,25 @@ public class 验证二叉搜索树 { public static void main(String[] args) { - TreeNode root = TreeUtils.buildTree(2, 1, 3); - TreeNode root2 = TreeUtils.buildTree(5, 1, 4, null, null, 3, 6); - TreeNode root3 = TreeUtils.buildTree(1, 1); + TreeNode root = TreeNode.buildTree(2, 1, 3); + TreeNode root2 = TreeNode.buildTree(5, 1, 4, null, null, 3, 6); + TreeNode root3 = TreeNode.buildTree(1, 1); Assertions.assertTrue(isValidBST(root)); Assertions.assertFalse(isValidBST(root2)); Assertions.assertFalse(isValidBST(root3)); - - Assertions.assertTrue(isValidBST2(root)); - Assertions.assertFalse(isValidBST2(root2)); - Assertions.assertFalse(isValidBST2(root3)); } public static boolean isValidBST(TreeNode root) { - return help(root, null, null); - } - - public static boolean help(TreeNode root, Integer min, Integer max) { - if (root == null) return true; - if (min != null && root.val <= min) return false; - if (max != null && root.val >= max) return false; - return help(root.left, min, root.val) && help(root.right, root.val, max); + return isValidBST(root, null, null); } - /** - * 中序遍历二叉搜索树获取到的一定是有序数组。符合这个条件的就是有效二叉搜索树 - *

- * 遍历二叉搜索树的时间复杂度:O(N) 但是对 List 进行排序,也要耗费时间,所以综合来看,应该是 O(N) + O(log N) - *

- * 空间复杂度:用两个链表进行比较,占用了 O(2N),比较耗费空间,性能并不好 - */ - public static boolean isValidBST2(TreeNode root) { + static boolean isValidBST(TreeNode root, Integer min, Integer max) { if (root == null) { return true; } - List list = new LinkedList<>(); - inOrder2(root, list); - - // 这里使用 TreeSet,基于两个目的:(1)去重 (2)根据值排序 - Set set2 = new TreeSet<>(); - set2.addAll(list); - return Arrays.equals(list.toArray(), set2.toArray()); - } - - // 单纯的中序遍历 - public static void inOrder2(TreeNode root, List list) { - if (root == null) return; - inOrder2(root.left, list); - list.add(root.val); - inOrder2(root.right, list); + // BST 树中,任意节点的值应该大于所有左子树节点,小于所有右子树节点 + if (min != null && root.val <= min) { return false; } + if (max != null && root.val >= max) { return false; } + return isValidBST(root.left, min, root.val) && isValidBST(root.right, root.val, max); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" new file mode 100644 index 0000000..d27f609 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" @@ -0,0 +1,71 @@ +package io.github.dunwu.algorithm.tree.btree.bfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 958. 二叉树的完全性检验 + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 二叉树的完全性检验 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.isCompleteTree(TreeNode.buildTree(1, 2, 3, 4, 5, 6))); + Assertions.assertTrue(s.isCompleteTree( + TreeNode.buildTree(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33))); + Assertions.assertFalse(s.isCompleteTree(TreeNode.buildTree(1, 2, 3, 4, 5, null, 7))); + Assertions.assertFalse(s.isCompleteTree(TreeNode.buildTree(1, 2, 3, 5, null, 7, 8))); + Assertions.assertFalse(s.isCompleteTree(TreeNode.buildTree(1, null, 7))); + } + + static class Solution { + + static class NodeInfo { + + public int id; + public TreeNode node; + + public NodeInfo(int id, TreeNode node) { + this.id = id; + this.node = node; + } + + } + + public boolean isCompleteTree(TreeNode root) { + + if (root == null) { return false; } + + int expect = 1; + LinkedList queue = new LinkedList<>(); + queue.offer(new NodeInfo(1, root)); + while (!queue.isEmpty()) { + int size = queue.size(); + for (int i = 0; i < size; i++) { + NodeInfo info = queue.poll(); + if (expect != info.id) { return false; } + if (info.node.left == null && info.node.right != null) { + return false; + } + if (info.node.left != null) { + queue.offer(new NodeInfo(info.id * 2, info.node.left)); + } + if (info.node.right != null) { + queue.offer(new NodeInfo(info.id * 2 + 1, info.node.right)); + } + expect++; + } + } + + return true; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" similarity index 59% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" index d66dd2d..71b0a95 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" @@ -1,7 +1,6 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.bfs; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.LinkedList; @@ -18,9 +17,9 @@ public class 二叉树的层平均值 { public static void main(String[] args) { Solution s = new Solution(); Assertions.assertArrayEquals(new Double[] { 3.00000, 14.50000, 11.00000 }, - s.averageOfLevels(TreeUtils.buildTree(3, 9, 20, null, null, 15, 7)).toArray()); + s.averageOfLevels(TreeNode.buildTree(3, 9, 20, null, null, 15, 7)).toArray()); Assertions.assertArrayEquals(new Double[] { 3.00000, 14.50000, 11.00000 }, - s.averageOfLevels(TreeUtils.buildTree(3, 9, 20, 15, 7)).toArray()); + s.averageOfLevels(TreeNode.buildTree(3, 9, 20, 15, 7)).toArray()); } static class Solution { @@ -28,18 +27,17 @@ static class Solution { public List averageOfLevels(TreeNode root) { if (root == null) { return new LinkedList<>(); } - List res = new LinkedList<>(); - LinkedList q = new LinkedList<>(); - q.offer(root); - - while (!q.isEmpty()) { - double sum = 0; - int size = q.size(); + LinkedList res = new LinkedList<>(); + LinkedList queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + int size = queue.size(); + double sum = 0.0; for (int i = 0; i < size; i++) { - TreeNode node = q.poll(); + TreeNode node = queue.poll(); sum += node.val; - if (node.left != null) { q.offer(node.left); } - if (node.right != null) { q.offer(node.right); } + if (node.left != null) queue.offer(node.left); + if (node.right != null) queue.offer(node.right); } res.add(sum / size); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" similarity index 53% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" index 17d1a25..dd133f3 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" @@ -1,13 +1,12 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.bfs; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; -import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; +import java.util.Queue; /** * 二叉树的层次遍历 @@ -19,7 +18,7 @@ public class 二叉树的层次遍历 { public static void main(String[] args) { Solution s = new Solution(); - TreeNode root = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); + TreeNode root = TreeNode.buildTree(3, 9, 20, null, null, 15, 7); List> expectList = new LinkedList<>(); expectList.add(Arrays.asList(3)); expectList.add(Arrays.asList(9, 20)); @@ -27,46 +26,40 @@ public static void main(String[] args) { Assertions.assertArrayEquals(expectList.toArray(), s.levelOrder(root).toArray()); Solution s2 = new Solution(); - TreeNode root2 = TreeUtils.buildTree(1); + TreeNode root2 = TreeNode.buildTree(1); List> expectList2 = new LinkedList<>(); expectList2.add(Arrays.asList(1)); Assertions.assertArrayEquals(expectList2.toArray(), s2.levelOrder(root2).toArray()); Solution s3 = new Solution(); - TreeNode root3 = TreeUtils.buildTree(); + TreeNode root3 = TreeNode.buildTree(); Assertions.assertArrayEquals(new LinkedList<>().toArray(), s3.levelOrder(root3).toArray()); } static class Solution { public List> levelOrder(TreeNode root) { - if (root == null) { - return new ArrayList(); - } - List> result = new LinkedList<>(); - LinkedList queue = new LinkedList<>(); - queue.add(root); - int level = 1; + + LinkedList> res = new LinkedList<>(); + if (root == null) { return res; } + + Queue queue = new LinkedList<>(); + queue.offer(root); + // while 循环控制从上向下一层层遍历 while (!queue.isEmpty()) { - int n = queue.size(); - System.out.printf("\nLevel[%s]: ", level); - List curLevelNodes = new LinkedList<>(); - for (int i = 0; i < n; i++) { + int size = queue.size(); + // 记录这一层的节点值 + List level = new LinkedList<>(); + // for 循环控制每一层从左向右遍历 + for (int i = 0; i < size; i++) { TreeNode node = queue.poll(); - System.out.printf("%s, ", node); - curLevelNodes.add(node.val); - if (node.left != null) { - queue.add(node.left); - } - if (node.right != null) { - queue.add(node.right); - } + level.add(node.val); + if (node.left != null) { queue.offer(node.left); } + if (node.right != null) { queue.offer(node.right); } } - level++; - result.add(curLevelNodes); + res.add(level); } - System.out.println(); - return result; + return res; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" similarity index 89% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" index 317a43a..dae1cfc 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" @@ -1,7 +1,6 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.bfs; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.ArrayList; @@ -20,7 +19,7 @@ public class 二叉树的层次遍历2 { public static void main(String[] args) { Solution s = new Solution(); - TreeNode root = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); + TreeNode root = TreeNode.buildTree(3, 9, 20, null, null, 15, 7); List> expectList = new LinkedList<>(); expectList.add(Arrays.asList(15, 7)); expectList.add(Arrays.asList(9, 20)); @@ -28,13 +27,13 @@ public static void main(String[] args) { Assertions.assertArrayEquals(expectList.toArray(), s.levelOrderBottom(root).toArray()); Solution s2 = new Solution(); - TreeNode root2 = TreeUtils.buildTree(1); + TreeNode root2 = TreeNode.buildTree(1); List> expectList2 = new LinkedList<>(); expectList2.add(Arrays.asList(1)); Assertions.assertArrayEquals(expectList2.toArray(), s2.levelOrderBottom(root2).toArray()); Solution s3 = new Solution(); - TreeNode root3 = TreeUtils.buildTree(); + TreeNode root3 = TreeNode.buildTree(); Assertions.assertArrayEquals(new LinkedList<>().toArray(), s3.levelOrderBottom(root3).toArray()); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" new file mode 100644 index 0000000..df94b8e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" @@ -0,0 +1,77 @@ +package io.github.dunwu.algorithm.tree.btree.bfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 104. 二叉树的最大深度 + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 二叉树的最大宽度 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(4, s.widthOfBinaryTree(TreeNode.buildTree(1, 3, 2, 5, 3, null, 9))); + Assertions.assertEquals(7, s.widthOfBinaryTree(TreeNode.buildTree(1, 3, 2, 5, null, null, 9, 6, null, 7))); + } + + static class Solution { + + public static class NodeInfo { + + public int id; + public TreeNode node; + + public NodeInfo(int id, TreeNode node) { + this.id = id; + this.node = node; + } + + @Override + public String toString() { + return "NodeInfo{" + + "id=" + id + + ", node=" + node.val + + '}'; + } + + } + + public int widthOfBinaryTree(TreeNode root) { + + if (root == null) return 0; + + int level = 0; + int maxWidth = 0; + LinkedList queue = new LinkedList<>(); + queue.offer(new NodeInfo(1, root)); + while (!queue.isEmpty()) { + level++; + int size = queue.size(); + NodeInfo left = null, right = null; + for (int i = 0; i < size; i++) { + NodeInfo info = queue.poll(); + if (info == null) { continue; } + if (left == null) { left = info; } + right = info; + if (info.node.left != null) { + queue.offer(new NodeInfo(2 * info.id, info.node.left)); + } + if (info.node.right != null) { + queue.offer(new NodeInfo(2 * info.id + 1, info.node.right)); + } + } + // System.out.printf("level: %d, left: %s, right: %s\n", level, left.toString(), right.toString()); + int width = right.id - left.id + 1; + maxWidth = Math.max(maxWidth, width); + } + return maxWidth; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 0000000..0d458c6 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,65 @@ +package io.github.dunwu.algorithm.tree.btree.bfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 103. 二叉树的锯齿形层序遍历 + * + * @author Zhang Peng + * @date 2025-10-21 + */ +public class 二叉树的锯齿形层序遍历 { + + public static void main(String[] args) { + Solution s = new Solution(); + TreeNode root = TreeNode.buildTree(3, 9, 20, null, null, 15, 7); + List> expectList = new LinkedList<>(); + expectList.add(Arrays.asList(3)); + expectList.add(Arrays.asList(20, 9)); + expectList.add(Arrays.asList(15, 7)); + Assertions.assertArrayEquals(expectList.toArray(), s.zigzagLevelOrder(root).toArray()); + + TreeNode root2 = TreeNode.buildTree(1, 2, 3, 4, null, null, 5); + List> expectList2 = new LinkedList<>(); + expectList2.add(Arrays.asList(1)); + expectList2.add(Arrays.asList(3, 2)); + expectList2.add(Arrays.asList(4, 5)); + Assertions.assertArrayEquals(expectList2.toArray(), s.zigzagLevelOrder(root2).toArray()); + } + + static class Solution { + + public List> zigzagLevelOrder(TreeNode root) { + List> result = new LinkedList<>(); + if (root == null) return result; + + boolean reverse = false; + LinkedList queue = new LinkedList<>(); + queue.addLast(root); + while (!queue.isEmpty()) { + int size = queue.size(); + LinkedList layer = new LinkedList<>(); + for (int i = 0; i < size; i++) { + TreeNode node = queue.removeFirst(); + if (reverse) { + layer.addFirst(node.val); + } else { + layer.addLast(node.val); + } + if (node.left != null) queue.addLast(node.left); + if (node.right != null) queue.addLast(node.right); + } + reverse = !reverse; + result.add(layer); + } + return result; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" similarity index 55% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" index 82b6964..c9bdb3c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" @@ -1,7 +1,6 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.bfs; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.LinkedList; @@ -18,9 +17,9 @@ public class 在每个树行中找最大值 { public static void main(String[] args) { Solution s = new Solution(); Assertions.assertArrayEquals(new Integer[] { 1, 3, 9 }, - s.largestValues(TreeUtils.buildTree(1, 3, 2, 5, 3, null, 9)).toArray()); - Assertions.assertArrayEquals(new Integer[] { 1, 3, 9 }, - s.largestValues(TreeUtils.buildTree(1, 3)).toArray()); + s.largestValues(TreeNode.buildTree(1, 3, 2, 5, 3, null, 9)).toArray()); + Assertions.assertArrayEquals(new Integer[] { 1, 3 }, + s.largestValues(TreeNode.buildTree(1, 2, 3)).toArray()); } static class Solution { @@ -29,22 +28,21 @@ public List largestValues(TreeNode root) { if (root == null) { return new LinkedList<>(); } - List res = new LinkedList<>(); - LinkedList q = new LinkedList<>(); - q.offer(root); - - while (!q.isEmpty()) { + LinkedList res = new LinkedList<>(); + LinkedList queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + int size = queue.size(); int max = Integer.MIN_VALUE; - int size = q.size(); for (int i = 0; i < size; i++) { - TreeNode node = q.poll(); - if (node == null) { continue; } + TreeNode node = queue.poll(); max = Math.max(max, node.val); - if (node.left != null) { q.offer(node.left); } - if (node.right != null) { q.offer(node.right); } + if (node.left != null) { queue.offer(node.left); } + if (node.right != null) { queue.offer(node.right); } } res.add(max); } + return res; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" similarity index 57% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" index 4612d4c..061e188 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" @@ -1,8 +1,7 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.bfs; import cn.hutool.json.JSONUtil; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import java.util.LinkedList; @@ -16,7 +15,7 @@ public class 填充每个节点的下一个右侧节点指针 { public static void main(String[] args) { Solution s = new Solution(); - TreeNode treeNode = TreeUtils.buildTree(1, 2, 3, 4, 5, 6, 7); + TreeNode treeNode = TreeNode.buildTree(1, 2, 3, 4, 5, 6, 7); Node root = JSONUtil.toBean(JSONUtil.toJsonStr(treeNode), Node.class); s.connect(root); System.out.println(root); @@ -25,27 +24,23 @@ public static void main(String[] args) { static class Solution { public Node connect(Node root) { - if (root == null) return null; - traverse(root); - return root; - } - - public void traverse(Node root) { - if (root == null) return; - LinkedList q = new LinkedList<>(); - q.offer(root); - - while (!q.isEmpty()) { - int size = q.size(); - Node prev = null; - for (int i = 0; i < size; i++) { - Node cur = q.poll(); - if (prev != null) { prev.next = cur; } - if (cur.left != null) q.offer(cur.left); - if (cur.right != null) q.offer(cur.right); - prev = cur; + if (root == null) return root; + LinkedList queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + int size = queue.size(); + Node prev = queue.poll(); + if (prev.left != null) queue.offer(prev.left); + if (prev.right != null) queue.offer(prev.right); + for (int i = 1; i < size; i++) { + Node next = queue.poll(); + prev.next = next; + prev = next; + if (next.left != null) queue.offer(next.left); + if (next.right != null) queue.offer(next.right); } } + return root; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" similarity index 91% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" index 69a1bd6..187eae0 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" @@ -1,8 +1,7 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.bfs; import cn.hutool.json.JSONUtil; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import java.util.LinkedList; @@ -16,7 +15,7 @@ public class 填充每个节点的下一个右侧节点指针2 { public static void main(String[] args) { Solution s = new Solution(); - TreeNode treeNode = TreeUtils.buildTree(1, 2, 3, 4, 5, null, 7); + TreeNode treeNode = TreeNode.buildTree(1, 2, 3, 4, 5, null, 7); Node root = JSONUtil.toBean(JSONUtil.toJsonStr(treeNode), Node.class); s.connect(root); System.out.println(root); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\245\207\345\201\266\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\245\207\345\201\266\346\240\221.java" new file mode 100644 index 0000000..8d58a76 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\245\207\345\201\266\346\240\221.java" @@ -0,0 +1,59 @@ +package io.github.dunwu.algorithm.tree.btree.bfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 1609. 奇偶树 + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 奇偶树 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.isEvenOddTree(TreeNode.buildTree(1, 10, 4, 3, null, 7, 9, 12, 8, 6, null, null, 2))); + Assertions.assertFalse(s.isEvenOddTree(TreeNode.buildTree(5, 4, 2, 3, 3, 7))); + Assertions.assertFalse(s.isEvenOddTree(TreeNode.buildTree(5, 9, 1, 3, 5, 7))); + Assertions.assertTrue(s.isEvenOddTree(TreeNode.buildTree(1))); + Assertions.assertTrue( + s.isEvenOddTree(TreeNode.buildTree(11, 8, 6, 1, 3, 9, 11, 30, 20, 18, 16, 12, 10, 4, 2, 17))); + } + + static class Solution { + + public boolean isEvenOddTree(TreeNode root) { + if (root == null) return false; + int level = 0; + LinkedList queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + int size = queue.size(); + boolean odd = level % 2 != 0; + Integer lastVal = null; + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + if (odd) { // 奇数层 + // 奇数下标 层上的所有节点的值都是 偶 整数,从左到右按顺序 严格递减 + if (node.val % 2 != 0) { return false; } + if (lastVal != null && node.val >= lastVal) { return false; } + } else { // 偶数层 + // 偶数下标 层上的所有节点的值都是 奇 整数,从左到右按顺序 严格递增 + if (node.val % 2 == 0) { return false; } + if (lastVal != null && node.val <= lastVal) { return false; } + } + lastVal = node.val; + if (node.left != null) { queue.offer(node.left); } + if (node.right != null) { queue.offer(node.right); } + } + level++; + } + return true; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" new file mode 100644 index 0000000..0992a9a --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" @@ -0,0 +1,48 @@ +package io.github.dunwu.algorithm.tree.btree.bfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 1302. 层数最深叶子节点的和 + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 层数最深叶子节点的和 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(15, + s.deepestLeavesSum(TreeNode.buildTree(1, 2, 3, 4, 5, null, 6, 7, null, null, null, null, 8))); + Assertions.assertEquals(19, + s.deepestLeavesSum(TreeNode.buildTree(6, 7, 8, 2, 7, 1, 3, 9, null, 1, 4, null, null, null, 5))); + } + + static class Solution { + + public int deepestLeavesSum(TreeNode root) { + + if (root == null) { return 0; } + + int sum = 0; + LinkedList queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + sum = 0; + int size = queue.size(); + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + sum += node.val; + if (node.left != null) { queue.offer(node.left); } + if (node.right != null) { queue.offer(node.right); } + } + } + return sum; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" similarity index 53% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" index c26f7af..d0bd78b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" @@ -1,13 +1,9 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.bfs; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; -import java.util.HashMap; import java.util.LinkedList; -import java.util.List; -import java.util.Map; /** * 1161. 最大层内元素和 @@ -20,36 +16,33 @@ public class 最大层内元素和 { public static void main(String[] args) { Solution s = new Solution(); Assertions.assertEquals(2, - s.maxLevelSum(TreeUtils.buildTree(1, 7, 0, 7, -8, null, null))); + s.maxLevelSum(TreeNode.buildTree(1, 7, 0, 7, -8, null, null))); Assertions.assertEquals(2, - s.maxLevelSum(TreeUtils.buildTree(989, null, 10250, 98693, -89388, null, null, null, -32127))); + s.maxLevelSum(TreeNode.buildTree(989, null, 10250, 98693, -89388, null, null, null, -32127))); Assertions.assertEquals(3, - s.maxLevelSum(TreeUtils.buildTree(-100, -200, -300, -20, -5, -10, null))); + s.maxLevelSum(TreeNode.buildTree(-100, -200, -300, -20, -5, -10, null))); } static class Solution { public int maxLevelSum(TreeNode root) { - if (root == null) { return 0; } - int depth = 1; + int max = Integer.MIN_VALUE; int maxDepth = 1; - int maxSum = Integer.MIN_VALUE; - LinkedList q = new LinkedList<>(); - q.offer(root); - - while (!q.isEmpty()) { + LinkedList queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { int sum = 0; - int size = q.size(); + int size = queue.size(); for (int i = 0; i < size; i++) { - TreeNode node = q.poll(); + TreeNode node = queue.poll(); sum += node.val; - if (node.left != null) { q.offer(node.left); } - if (node.right != null) { q.offer(node.right); } + if (node.left != null) { queue.offer(node.left); } + if (node.right != null) { queue.offer(node.right); } } - if (sum > maxSum) { - maxSum = sum; + if (sum > max) { + max = sum; maxDepth = depth; } depth++; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" similarity index 92% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" index d642dcd..9504da0 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" @@ -1,7 +1,6 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.divide; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.Arrays; @@ -21,7 +20,7 @@ public class 从中序与后序遍历序列构造二叉树 { public static void main(String[] args) { Solution s = new Solution(); TreeNode output1 = s.buildTree(new int[] { 9, 3, 15, 20, 7 }, new int[] { 9, 15, 7, 20, 3 }); - List list = TreeUtils.toValueList(output1); + List list = TreeNode.toValueList(output1); System.out.println(list); Assertions.assertArrayEquals(Arrays.asList(3, 9, 20, null, null, 15, 7).toArray(), list.toArray()); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" similarity index 90% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" index 8786b74..b3b367f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" @@ -1,7 +1,6 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.divide; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.Arrays; @@ -23,12 +22,12 @@ public static void main(String[] args) { Solution s = new Solution(); TreeNode output1 = s.buildTree(new int[] { 3, 9, 20, 15, 7 }, new int[] { 9, 3, 15, 20, 7 }); - List list = TreeUtils.toValueList(output1); + List list = TreeNode.toValueList(output1); System.out.println(list); Assertions.assertArrayEquals(Arrays.asList(3, 9, 20, null, null, 15, 7).toArray(), list.toArray()); TreeNode output2 = s.buildTree(new int[] { -1 }, new int[] { -1 }); - List list2 = TreeUtils.toValueList(output2); + List list2 = TreeNode.toValueList(output2); System.out.println(list2); Assertions.assertArrayEquals(Arrays.asList(-1).toArray(), list2.toArray()); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" new file mode 100644 index 0000000..28deff6 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" @@ -0,0 +1,57 @@ +package io.github.dunwu.algorithm.tree.btree.divide; + +import io.github.dunwu.algorithm.tree.TreeNode; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * 1110. 删点成林 + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 删点成林 { + + public static void main(String[] args) { + Solution s = new Solution(); + + TreeNode input = TreeNode.buildTree(1, 2, 3, 4, 5, 6, 7); + List output = s.delNodes(input, new int[] { 3, 5 }); + for (TreeNode tree : output) { + System.out.println(TreeNode.toValueList(tree)); + } + + // List result1 = TreeNode.toValueList(output); + // Assertions.assertArrayEquals(new Integer[] { 5, 4, null, 1, 3, null, null, 2 }, result1.toArray()); + } + + static class Solution { + + Set delValSet = new HashSet<>(); + List res = new LinkedList<>(); + + public List delNodes(TreeNode root, int[] to_delete) { + for (int val : to_delete) { + delValSet.add(val); + } + traverse(root, false); + return res; + } + + public TreeNode traverse(TreeNode root, boolean hasParent) { + if (root == null) { return null; } + boolean deleted = delValSet.contains(root.val); + if (!deleted && !hasParent) { + res.add(root); + } + root.left = traverse(root.left, !deleted); + root.right = traverse(root.right, !deleted); + return deleted ? null : root; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" new file mode 100644 index 0000000..e0e8079 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" @@ -0,0 +1,65 @@ +package io.github.dunwu.algorithm.tree.btree.divide; + +import io.github.dunwu.algorithm.tree.TreeNode; + +import java.util.LinkedList; +import java.util.List; + +/** + * 894. 所有可能的真二叉树 + * + * @author Zhang Peng + * @date 2025-10-21 + */ +public class 所有可能的真二叉树 { + + public static void main(String[] args) { + Solution s = new Solution(); + List trees = s.allPossibleFBT(7); + trees.forEach(tree -> { + System.out.println(TreeNode.serialize(tree)); + }); + } + + static class Solution { + + List[] memo; + + public List allPossibleFBT(int n) { + if (n % 2 == 0) { + return new LinkedList<>(); + } + memo = new LinkedList[n + 1]; + return build(n); + } + + public List build(int n) { + List res = new LinkedList<>(); + if (n == 1) { + res.add(new TreeNode(0)); + return res; + } + if (memo[n] != null) { + return memo[n]; + } + for (int i = 1; i < n; i += 2) { + int j = n - i - 1; + + List leftSubTree = build(i); + List rightSubTree = build(j); + for (TreeNode left : leftSubTree) { + for (TreeNode right : rightSubTree) { + TreeNode node = new TreeNode(0); + node.left = left; + node.right = right; + res.add(node); + } + } + } + memo[n] = res; + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" new file mode 100644 index 0000000..a256d07 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" @@ -0,0 +1,51 @@ +package io.github.dunwu.algorithm.tree.btree.divide; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.List; + +/** + * 998. 最大二叉树 II + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 最大二叉树2 { + + public static void main(String[] args) { + TreeNode input = TreeNode.buildTree(4, 1, 3, null, null, 2); + TreeNode output = insertIntoMaxTree(input, 5); + List result1 = TreeNode.toValueList(output); + Assertions.assertArrayEquals(new Integer[] { 5, 4, null, 1, 3, null, null, 2 }, result1.toArray()); + + TreeNode input2 = TreeNode.buildTree(5, 2, 4, null, 1); + TreeNode output2 = insertIntoMaxTree(input2, 3); + List result2 = TreeNode.toValueList(output2); + Assertions.assertArrayEquals(new Integer[] { 5, 2, 4, null, 1, null, 3 }, result2.toArray()); + + TreeNode input3 = TreeNode.buildTree(3, 2); + TreeNode output3 = insertIntoMaxTree(input3, 1); + List result3 = TreeNode.toValueList(output3); + Assertions.assertArrayEquals(new Integer[] { 3, 2, null, null, 1 }, result3.toArray()); + } + + public static TreeNode insertIntoMaxTree(TreeNode root, int val) { + if (root == null) { + return new TreeNode(val); + } + if (root.val < val) { + // 如果 val 是整棵树最大的,那么原来的这棵树应该是 val 节点的左子树, + // 因为 val 节点是接在原始数组 a 的最后一个元素 + TreeNode temp = root; + root = new TreeNode(val); + root.left = temp; + } else { + // 如果 val 不是最大的,那么就应该在右子树上, + // 因为 val 节点是接在原始数组 a 的最后一个元素 + root.right = insertIntoMaxTree(root.right, val); + } + return root; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" similarity index 93% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" index 91b4a48..60759ba 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" @@ -1,7 +1,6 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.divide; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.Arrays; @@ -21,7 +20,7 @@ public class 根据前序和后序遍历构造二叉树 { public static void main(String[] args) { TreeNode output1 = new Solution().constructFromPrePost(new int[] { 1, 2, 4, 5, 3, 6, 7 }, new int[] { 4, 5, 2, 6, 7, 3, 1 }); - List list = TreeUtils.toValueList(output1); + List list = TreeNode.toValueList(output1); // System.out.println(list); Assertions.assertArrayEquals(Arrays.asList(1, 2, 3, 4, 5, 6, 7).toArray(), list.toArray()); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" new file mode 100644 index 0000000..180ab12 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" @@ -0,0 +1,44 @@ +package io.github.dunwu.algorithm.tree.btree.divide; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 331. 验证二叉树的前序序列化 + * + * @author Zhang Peng + * @date 2025-08-15 + */ +public class 验证二叉树的前序序列化 { + + public static void main(String[] args) { + Assertions.assertTrue(isValidSerialization("9,3,4,#,#,1,#,#,2,#,6,#,#")); + Assertions.assertFalse(isValidSerialization("1,#")); + Assertions.assertFalse(isValidSerialization("9,#,#,1")); + } + + public static boolean isValidSerialization(String preorder) { + // 将字符串转化成列表 + LinkedList nodes = new LinkedList<>(); + for (String s : preorder.split(",")) { + nodes.addLast(s); + } + return deserialize(nodes) && nodes.isEmpty(); + } + + public static boolean deserialize(LinkedList nodes) { + if (nodes.isEmpty()) { + return false; + } + + // ***** 前序遍历位置 ***** + // 列表最左侧就是根节点 + String first = nodes.removeFirst(); + if (first.equals("#")) return true; + // ********************* + + return deserialize(nodes) && deserialize(nodes); + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" similarity index 85% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" index 0bb7acf..37d8dec 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" @@ -1,7 +1,6 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.traverse; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.HashMap; @@ -18,9 +17,9 @@ public class 二叉树中的伪回文路径 { public static void main(String[] args) { Assertions.assertEquals(2, - new Solution().pseudoPalindromicPaths(TreeUtils.buildTree(2, 3, 1, 3, 1, null, 1))); + new Solution().pseudoPalindromicPaths(TreeNode.buildTree(2, 3, 1, 3, 1, null, 1))); Assertions.assertEquals(1, - new Solution().pseudoPalindromicPaths(TreeUtils.buildTree(2, 1, 1, 1, 3, null, null, null, null, null, 1))); + new Solution().pseudoPalindromicPaths(TreeNode.buildTree(2, 1, 1, 1, 3, null, null, null, null, null, 1))); } static class Solution { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" similarity index 81% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" index a3f7593..8fa2c7e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" @@ -1,7 +1,6 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.traverse; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.ArrayList; @@ -18,10 +17,10 @@ public class 二叉树的右视图 { public static void main(String[] args) { Assertions.assertArrayEquals(new Integer[] { 1, 3, 4 }, - new Solution().rightSideView(TreeUtils.buildTree(1, 2, 3, null, 5, null, 4)).toArray(new Integer[0])); + new Solution().rightSideView(TreeNode.buildTree(1, 2, 3, null, 5, null, 4)).toArray(new Integer[0])); Assertions.assertArrayEquals(new Integer[] { 1, 3, 4, 5 }, - new Solution().rightSideView(TreeUtils.buildTree(1, 2, 3, 4, null, null, null, 5)).toArray(new Integer[0])); + new Solution().rightSideView(TreeNode.buildTree(1, 2, 3, 4, null, null, null, 5)).toArray(new Integer[0])); } static class Solution { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" new file mode 100644 index 0000000..121ea23 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" @@ -0,0 +1,67 @@ +package io.github.dunwu.algorithm.tree.btree.traverse; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 二叉树的所有路径 + * + * @author Zhang Peng + * @since 2025-08-15 + */ +public class 二叉树的所有路径 { + + public static void main(String[] args) { + + Solution s = new Solution(); + TreeNode tree = TreeNode.buildTree(1, 2, 3, 5); + List list = s.binaryTreePaths(tree); + Assertions.assertArrayEquals(Arrays.asList("1->2->5", "1->3").toArray(), + list.toArray(new String[0])); + } + + static class Solution { + + LinkedList res = new LinkedList<>(); + LinkedList paths = new LinkedList<>(); + + public List binaryTreePaths(TreeNode root) { + traverse(root); + return res; + } + + public void traverse(TreeNode root) { + if (root == null) { return; } + + // 选择 + paths.addLast(String.valueOf(root.val)); + if (root.left == null && root.right == null) { + res.addLast(String.join("->", paths)); + // System.out.printf("res: %s\n", JSONUtil.toJsonStr(res)); + } + + // 遍历左子树 + if (root.left != null) { + // System.out.format("root: %s -> root.left: %s\n", root.val, root.left.val); + traverse(root.left); + // System.out.format("root.left: %s -> root: %s\n", root.left.val, root.val); + } + + // 遍历右子树 + if (root.right != null) { + // System.out.format("root: %s -> root.right: %s\n", root.val, root.right.val); + traverse(root.right); + // System.out.format("root.right: %s -> root: %s\n", root.right.val, root.val); + } + + // 取消选择 + paths.removeLast(); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" similarity index 79% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" index 1903eb0..6a373ee 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" @@ -1,12 +1,9 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.traverse; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; -import java.util.ArrayList; import java.util.LinkedList; -import java.util.List; /** * 988. 从叶结点开始的最小字符串 @@ -18,11 +15,11 @@ public class 从叶结点开始的最小字符串 { public static void main(String[] args) { Assertions.assertEquals("dba", - new Solution().smallestFromLeaf(TreeUtils.buildTree(0, 1, 2, 3, 4, 3, 4))); + new Solution().smallestFromLeaf(TreeNode.buildTree(0, 1, 2, 3, 4, 3, 4))); Assertions.assertEquals("adz", - new Solution().smallestFromLeaf(TreeUtils.buildTree(25, 1, 3, 1, 3, 0, 2))); + new Solution().smallestFromLeaf(TreeNode.buildTree(25, 1, 3, 1, 3, 0, 2))); Assertions.assertEquals("abc", - new Solution().smallestFromLeaf(TreeUtils.buildTree(2, 2, 1, null, 1, 0, null, 0))); + new Solution().smallestFromLeaf(TreeNode.buildTree(2, 2, 1, null, 1, 0, null, 0))); } static class Solution { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" similarity index 83% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" index c3a5904..ca2d004 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" @@ -1,7 +1,6 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.traverse; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.LinkedList; @@ -16,9 +15,9 @@ public class 从根到叶的二进制数之和 { public static void main(String[] args) { Assertions.assertEquals(22, - new Solution().sumRootToLeaf(TreeUtils.buildTree(1, 0, 1, 0, 1, 0, 1))); + new Solution().sumRootToLeaf(TreeNode.buildTree(1, 0, 1, 0, 1, 0, 1))); Assertions.assertEquals(0, - new Solution().sumRootToLeaf(TreeUtils.buildTree(0))); + new Solution().sumRootToLeaf(TreeNode.buildTree(0))); } static class Solution { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" similarity index 84% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" index 2ba9f3a..b04a5ff 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" @@ -1,14 +1,10 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.traverse; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; -import java.util.Arrays; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Set; /** * 623. 在二叉树中增加一行 @@ -19,14 +15,14 @@ public class 在二叉树中增加一行 { public static void main(String[] args) { - TreeNode root = TreeUtils.buildTree(4, 2, 6, 3, 1, 5); + TreeNode root = TreeNode.buildTree(4, 2, 6, 3, 1, 5); TreeNode newRoot = new Solution().addOneRow(root, 1, 2); - List list = TreeUtils.toValueList(newRoot); + List list = TreeNode.toValueList(newRoot); Assertions.assertArrayEquals(new Integer[] { 4, 1, 1, 2, null, null, 6, 3, 1, 5 }, list.toArray()); - TreeNode root2 = TreeUtils.buildTree(4, 2, 6, 3, 1, 5); + TreeNode root2 = TreeNode.buildTree(4, 2, 6, 3, 1, 5); TreeNode newRoot2 = new Solution().addOneRow(root2, 1, 1); - List list2 = TreeUtils.toValueList(newRoot2); + List list2 = TreeNode.toValueList(newRoot2); Assertions.assertArrayEquals(new Integer[] { 1, 4, null, 2, 6, 3, 1, 5 }, list2.toArray()); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" similarity index 69% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" index 52876ae..7d24178 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" @@ -1,13 +1,8 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.traverse; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - /** * 404. 左叶子之和 * @@ -18,13 +13,13 @@ public class 左叶子之和 { public static void main(String[] args) { Assertions.assertEquals(24, - new Solution().sumOfLeftLeaves(TreeUtils.buildTree(3, 9, 20, null, null, 15, 7))); + new Solution().sumOfLeftLeaves(TreeNode.buildTree(3, 9, 20, null, null, 15, 7))); Assertions.assertEquals(4, - new Solution().sumOfLeftLeaves(TreeUtils.buildTree(1, 2, 3, 4, 5))); + new Solution().sumOfLeftLeaves(TreeNode.buildTree(1, 2, 3, 4, 5))); Assertions.assertEquals(0, - new Solution().sumOfLeftLeaves(TreeUtils.buildTree(1))); + new Solution().sumOfLeftLeaves(TreeNode.buildTree(1))); } static class Solution { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" similarity index 91% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" index f92b423..9b8e09a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" @@ -1,7 +1,6 @@ -package io.github.dunwu.algorithm.tree.btree; +package io.github.dunwu.algorithm.tree.btree.traverse; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.LinkedList; @@ -16,8 +15,8 @@ public class 求根节点到叶节点数字之和 { public static void main(String[] args) { - Assertions.assertEquals(25, new Solution().sumNumbers(TreeUtils.buildTree(1, 2, 3))); - Assertions.assertEquals(1026, new Solution().sumNumbers(TreeUtils.buildTree(4, 9, 0, 5, 1))); + Assertions.assertEquals(25, new Solution().sumNumbers(TreeNode.buildTree(1, 2, 3))); + Assertions.assertEquals(1026, new Solution().sumNumbers(TreeNode.buildTree(4, 9, 0, 5, 1))); } static class Solution { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" index 2ae0cb5..8a04657 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; /** @@ -13,13 +12,13 @@ public class 二叉树中的最大路径和 { public static void main(String[] args) { 二叉树中的最大路径和 demo = new 二叉树中的最大路径和(); - TreeNode tree = TreeUtils.buildTree(1, 2, 3); + TreeNode tree = TreeNode.buildTree(1, 2, 3); Assertions.assertEquals(6, demo.maxPathSum(tree)); - TreeNode tree2 = TreeUtils.buildTree(-10, 9, 20, null, null, 15, 7); + TreeNode tree2 = TreeNode.buildTree(-10, 9, 20, null, null, 15, 7); Assertions.assertEquals(42, demo.maxPathSum(tree2)); - TreeNode tree3 = TreeUtils.buildTree(2, -1); + TreeNode tree3 = TreeNode.buildTree(2, -1); Assertions.assertEquals(2, demo.maxPathSum(tree3)); - TreeNode tree4 = TreeUtils.buildTree(-2, -1); + TreeNode tree4 = TreeNode.buildTree(-2, -1); Assertions.assertEquals(-1, demo.maxPathSum(tree4)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" index d80d421..005e6e5 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.List; @@ -18,21 +17,21 @@ public static void main(String[] args) { Solution s = new Solution(); - TreeNode root = TreeUtils.buildTree(1, 2, 5, 3, 4, null, 6); + TreeNode root = TreeNode.buildTree(1, 2, 5, 3, 4, null, 6); s.flatten(root); - List list = TreeUtils.toValueList(root); + List list = TreeNode.toValueList(root); Assertions.assertArrayEquals(new Integer[] { 1, null, 2, null, 3, null, 4, null, 5, null, 6 }, list.toArray(new Integer[0])); - TreeNode root2 = TreeUtils.buildTree(0); + TreeNode root2 = TreeNode.buildTree(0); s.flatten(root2); - List list2 = TreeUtils.toValueList(root2); + List list2 = TreeNode.toValueList(root2); Assertions.assertArrayEquals(new Integer[] { 0 }, list2.toArray(new Integer[0])); - TreeNode root3 = TreeUtils.buildTree(); + TreeNode root3 = TreeNode.buildTree(); s.flatten(root3); - List list3 = TreeUtils.toValueList(root3); + List list3 = TreeNode.toValueList(root3); Assertions.assertArrayEquals(new Integer[] {}, list3.toArray(new Integer[0])); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" index 9607c61..252b62e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.ArrayList; @@ -17,15 +16,15 @@ public class 二叉树的中序遍历 { public static void main(String[] args) { Solution s1 = new Solution(); - TreeNode root = TreeUtils.buildTree(1, null, 2, 3); + TreeNode root = TreeNode.buildTree(1, null, 2, 3); Assertions.assertArrayEquals(new Integer[] { 1, 3, 2 }, s1.inorderTraversal(root).toArray(new Integer[0])); Solution s2 = new Solution(); - TreeNode root2 = TreeUtils.buildTree(); + TreeNode root2 = TreeNode.buildTree(); Assertions.assertArrayEquals(new Integer[] {}, s2.inorderTraversal(root2).toArray(new Integer[0])); Solution s3 = new Solution(); - TreeNode root3 = TreeUtils.buildTree(1); + TreeNode root3 = TreeNode.buildTree(1); Assertions.assertArrayEquals(new Integer[] { 1 }, s3.inorderTraversal(root3).toArray(new Integer[0])); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" index 7063228..06c1168 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.ArrayList; @@ -17,15 +16,15 @@ public class 二叉树的前序遍历 { public static void main(String[] args) { Solution s1 = new Solution(); - TreeNode root = TreeUtils.buildTree(1, null, 2, 3); + TreeNode root = TreeNode.buildTree(1, null, 2, 3); Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, s1.preorderTraversal(root).toArray(new Integer[0])); Solution s2 = new Solution(); - TreeNode root2 = TreeUtils.buildTree(); + TreeNode root2 = TreeNode.buildTree(); Assertions.assertArrayEquals(new Integer[] {}, s2.preorderTraversal(root2).toArray(new Integer[0])); Solution s3 = new Solution(); - TreeNode root3 = TreeUtils.buildTree(1); + TreeNode root3 = TreeNode.buildTree(1); Assertions.assertArrayEquals(new Integer[] { 1 }, s3.preorderTraversal(root3).toArray(new Integer[0])); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" index 320c3ab..5f72ca1 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.ArrayList; @@ -17,19 +16,19 @@ public class 二叉树的后序遍历 { public static void main(String[] args) { Solution s1 = new Solution(); - TreeNode root = TreeUtils.buildTree(1, null, 2, 3); + TreeNode root = TreeNode.buildTree(1, null, 2, 3); Assertions.assertArrayEquals(new Integer[] { 3, 2, 1 }, s1.postorderTraversal(root).toArray(new Integer[0])); Solution s2 = new Solution(); - TreeNode root2 = TreeUtils.buildTree(); + TreeNode root2 = TreeNode.buildTree(); Assertions.assertArrayEquals(new Integer[] {}, s2.postorderTraversal(root2).toArray(new Integer[0])); Solution s3 = new Solution(); - TreeNode root3 = TreeUtils.buildTree(1); + TreeNode root3 = TreeNode.buildTree(1); Assertions.assertArrayEquals(new Integer[] { 1 }, s3.postorderTraversal(root3).toArray(new Integer[0])); Solution s4 = new Solution(); - TreeNode root4 = TreeUtils.buildTree(1, 2, 3, 4, 5, null, 8, null, null, 6, 7, 9); + TreeNode root4 = TreeNode.buildTree(1, 2, 3, 4, 5, null, 8, null, null, 6, 7, 9); Assertions.assertArrayEquals(new Integer[] { 4, 6, 7, 5, 2, 9, 8, 3, 1 }, s4.postorderTraversal(root4).toArray(new Integer[0])); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" deleted file mode 100644 index c94f788..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" +++ /dev/null @@ -1,61 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 958. 二叉树的完全性检验 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 二叉树的完全性检验 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.isCompleteTree(TreeUtils.buildTree(1, 2, 3, 4, 5, 6))); - Assertions.assertFalse(s.isCompleteTree(TreeUtils.buildTree(1, 2, 3, 4, 5, null, 7))); - } - - static class Solution { - - static class NodeInfo { - - public int id; - public TreeNode node; - - public NodeInfo(int id, TreeNode node) { - this.id = id; - this.node = node; - } - - } - - public boolean isCompleteTree(TreeNode root) { - - if (root == null) { return false; } - - int id = 1; - LinkedList q = new LinkedList<>(); - q.offer(new NodeInfo(id, root)); - - while (!q.isEmpty()) { - int size = q.size(); - for (int i = 0; i < size; i++) { - NodeInfo info = q.poll(); - if (info.id != id) { return false; } - if (info.node.left != null) { q.offer(new NodeInfo(id * 2, info.node.left)); } - if (info.node.right != null) { q.offer(new NodeInfo(id * 2 + 1, info.node.right)); } - id++; - } - } - return true; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" index af0c364..515e471 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" @@ -3,19 +3,21 @@ import io.github.dunwu.algorithm.tree.TreeNode; import org.junit.jupiter.api.Assertions; +import java.util.Arrays; import java.util.LinkedList; /** + * 297. 二叉树的序列化与反序列化 + * * @author Zhang Peng * @since 2020-07-06 */ public class 二叉树的序列化与反序列化 { public static void main(String[] args) { - // String input = "1,2,null,4,null,null,3,null,null"; - String input2 = "null,null,null,4,2,null,null,3,1"; - TreeNode tree = deserialize(input2); - Assertions.assertEquals(input2, serialize(tree)); + String input1 = "1,2,3,null,null,4,5,null,null,null,null,"; + TreeNode tree1 = deserialize(input1); + Assertions.assertEquals(input1, serialize(tree1)); } static final String SEP = ","; @@ -23,77 +25,36 @@ public static void main(String[] args) { public static String serialize(TreeNode root) { StringBuilder sb = new StringBuilder(); - serializePostOrder(root, sb); - int size = sb.length(); - int pos = sb.lastIndexOf(SEP); - if (pos == size - 1) { - sb.deleteCharAt(pos); - } + doSerialize(root, sb); return sb.toString(); } - static void serializePreOrder(TreeNode root, StringBuilder sb) { + static void doSerialize(TreeNode root, StringBuilder sb) { if (root == null) { sb.append(NULL).append(SEP); return; } - - // 前序处理 - sb.append(root.val).append(SEP); - - serializePreOrder(root.left, sb); - serializePreOrder(root.right, sb); - } - - static void serializePostOrder(TreeNode root, StringBuilder sb) { - if (root == null) { - sb.append(NULL).append(SEP); - return; - } - - serializePostOrder(root.left, sb); - serializePostOrder(root.right, sb); - - // 后序处理 sb.append(root.val).append(SEP); + doSerialize(root.left, sb); + doSerialize(root.right, sb); } public static TreeNode deserialize(String data) { - // 将字符串转化成列表 - LinkedList nodes = new LinkedList<>(); - for (String s : data.split(SEP)) { - nodes.addLast(s); - } - return deserializePostOrder(nodes); + LinkedList nodes = new LinkedList<>(Arrays.asList(data.split(SEP))); + return doDeserialize(nodes); } - static TreeNode deserializePreOrder(LinkedList nodes) { + static TreeNode doDeserialize(LinkedList nodes) { if (nodes.isEmpty()) return null; - // ****** 前序位置 ******** - // 列表最左侧就是根节点 - String first = nodes.removeFirst(); - if (first.equals(NULL)) return null; - TreeNode root = new TreeNode(Integer.parseInt(first)); - - // ********************* - - root.left = deserializePreOrder(nodes); - root.right = deserializePreOrder(nodes); - - return root; - } - - static TreeNode deserializePostOrder(LinkedList nodes) { - if (nodes.isEmpty()) return null; - - String last = nodes.removeLast(); - if (last.equals(NULL)) return null; - TreeNode root = new TreeNode(Integer.parseInt(last)); - - root.right = deserializePostOrder(nodes); - root.left = deserializePostOrder(nodes); + // =============== 前序遍历处理 =============== + String val = nodes.removeFirst(); + if (NULL.equals(val)) { return null; } + TreeNode root = new TreeNode(Integer.parseInt(val)); + // ========================================== + root.left = doDeserialize(nodes); + root.right = doDeserialize(nodes); return root; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" deleted file mode 100644 index ff1108e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" +++ /dev/null @@ -1,60 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.stream.Collectors; - -/** - * 二叉树的所有路径 - * - * @author Zhang Peng - * @since 2025-08-15 - */ -public class 二叉树的所有路径 { - - public static void main(String[] args) { - - Solution s = new Solution(); - TreeNode tree = TreeUtils.buildTree(1, 2, 3, 5); - List list = s.binaryTreePaths(tree); - Assertions.assertArrayEquals(Arrays.asList("1->2->5", "1->3").toArray(), - list.toArray(new String[0])); - } - - static class Solution { - - LinkedList nodes = new LinkedList<>(); - List paths = new LinkedList<>(); - - public List binaryTreePaths(TreeNode root) { - traverse(root); - return paths; - } - - public void traverse(TreeNode root) { - if (root == null) { - return; - } - - if (root.left == null && root.right == null) { - nodes.addLast(String.valueOf(root.val)); - String path = String.join("->", nodes.toArray(new String[0])); - paths.add(path); - nodes.removeLast(); - return; - } - - nodes.addLast(String.valueOf(root.val)); - traverse(root.left); - traverse(root.right); - nodes.removeLast(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" deleted file mode 100644 index f23eff5..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" +++ /dev/null @@ -1,69 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 104. 二叉树的最大深度 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 二叉树的最大宽度 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(4, s.widthOfBinaryTree(TreeUtils.buildTree(1, 3, 2, 5, 3, null, 9))); - Assertions.assertEquals(7, s.widthOfBinaryTree(TreeUtils.buildTree(1, 3, 2, 5, null, null, 9, 6, null, 7))); - } - - static class Solution { - - public static class NodeInfo { - - public int id; - public TreeNode node; - - public NodeInfo(int id, TreeNode node) { - this.id = id; - this.node = node; - } - - } - - public int widthOfBinaryTree(TreeNode root) { - - int maxWidth = 0; - LinkedList q = new LinkedList<>(); - q.offer(new NodeInfo(1, root)); - - while (!q.isEmpty()) { - int size = q.size(); - int begin = 0, end = 0; - for (int i = 0; i < size; i++) { - NodeInfo cur = q.poll(); - if (i == 0) { - begin = cur.id; - } - if (i == size - 1) { - end = cur.id; - } - if (cur.node.left != null) { - q.offer(new NodeInfo(cur.id * 2, cur.node.left)); - } - if (cur.node.right != null) { - q.offer(new NodeInfo(cur.id * 2 + 1, cur.node.right)); - } - } - int width = end - begin + 1; - maxWidth = Math.max(maxWidth, width); - } - return maxWidth; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" index fbe08e6..87aab90 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; /** @@ -14,16 +13,36 @@ public class 二叉树的最大深度 { public static void main(String[] args) { Solution s = new Solution(); - TreeNode root = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); + TreeNode root = TreeNode.buildTree(3, 9, 20, null, null, 15, 7); Assertions.assertEquals(3, s.maxDepth(root)); - TreeNode root2 = TreeUtils.buildTree(1, null, 2); + TreeNode root2 = TreeNode.buildTree(1, null, 2); Assertions.assertEquals(2, s.maxDepth(root2)); } static class Solution { + int depth = 0; + int res = 0; + public int maxDepth(TreeNode root) { + traverse(root); + return res; + } + + public void traverse(TreeNode root) { + if (root == null) return; + depth++; + if (root.left == null && root.right == null) { + res = Math.max(res, depth); + } + traverse(root.left); + traverse(root.right); + + depth--; + } + + public int maxDepth2(TreeNode root) { if (root == null) { return 0; } int left = maxDepth(root.left); int right = maxDepth(root.right); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" index c8374b4..38bfbb8 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; /** @@ -15,10 +14,10 @@ public class 二叉树的最小深度 { public static void main(String[] args) { Solution s = new Solution(); - TreeNode root = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); + TreeNode root = TreeNode.buildTree(3, 9, 20, null, null, 15, 7); Assertions.assertEquals(2, s.minDepth(root)); - TreeNode root2 = TreeUtils.buildTree(2, null, 3, null, 4, null, 5, null, 6); + TreeNode root2 = TreeNode.buildTree(2, null, 3, null, 4, null, 5, null, 6); Assertions.assertEquals(5, s.minDepth(root2)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" index c94761e..7a871d1 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" @@ -1,28 +1,28 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; /** * 236. 二叉树的最近公共祖先 算法实现 * * @see 236. 二叉树的最近公共祖先 - * @see 解题思路 + * @see 解题思路 */ public class 二叉树的最近公共祖先 { public static void main(String[] args) { - TreeNode root = TreeUtils.buildTree(3, 5, 1, 6, 2, 0, 8, null, null, 7, 4); - TreeNode p = TreeUtils.find(root, 5); - TreeNode q = TreeUtils.find(root, 1); + TreeNode root = TreeNode.buildTree(3, 5, 1, 6, 2, 0, 8, null, null, 7, 4); + TreeNode p = TreeNode.find(root, 5); + TreeNode q = TreeNode.find(root, 1); TreeNode treeNode = lowestCommonAncestor(root, p, q); Assertions.assertNotNull(treeNode); Assertions.assertEquals(3, treeNode.val); System.out.println("公共祖先节点 = " + treeNode.val); - TreeNode p2 = TreeUtils.find(root, 5); - TreeNode q2 = TreeUtils.find(root, 4); + TreeNode p2 = TreeNode.find(root, 5); + TreeNode q2 = TreeNode.find(root, 4); TreeNode treeNode2 = lowestCommonAncestor(root, p2, q2); Assertions.assertNotNull(treeNode2); Assertions.assertEquals(5, treeNode2.val); @@ -37,21 +37,19 @@ public static void main(String[] args) { * 空间复杂度:O(2) 常数级 */ public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { - // 如果当前节点为空,直接返回 - // 或当前节点就是 p 或 q 其中一个,显然就是要找的最近公共祖先,直接返回 - if (root == null || root == p || root == q) return root; + + if (root == null) { return null; } + if (root == p || root == q) { return root; } TreeNode left = lowestCommonAncestor(root.left, p, q); TreeNode right = lowestCommonAncestor(root.right, p, q); - - if (left == null) { // p、q 都不在左子树,查找右子树 - return right; - } else if (right == null) { // p、q 都不在右子树,查找左子树 - return left; - } else { - // p、q 既不在左子树,又不在右子树,直接返回当前节点 + if (left != null && right != null) { return root; } + if (left == null && right == null) { + return null; + } + return left == null ? right : left; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" index 09624b0..9d7020a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; /** @@ -14,11 +13,11 @@ public class 二叉树的直径 { public static void main(String[] args) { Solution s = new Solution(); - TreeNode root = TreeUtils.buildTree(1, 2, 3, 4, 5); + TreeNode root = TreeNode.buildTree(1, 2, 3, 4, 5); Assertions.assertEquals(3, s.diameterOfBinaryTree(root)); Solution s2 = new Solution(); - TreeNode root2 = TreeUtils.buildTree(1, 2); + TreeNode root2 = TreeNode.buildTree(1, 2); Assertions.assertEquals(1, s2.diameterOfBinaryTree(root2)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" index 9d4ca7d..1b91f8f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" @@ -1,10 +1,8 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; @@ -22,19 +20,19 @@ public static void main(String[] args) { Solution s = new Solution(); - TreeNode root = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); + TreeNode root = TreeNode.buildTree(3, 9, 20, null, null, 15, 7); List> expect = new LinkedList<>(); expect.add(Arrays.asList(3)); expect.add(Arrays.asList(20, 9)); expect.add(Arrays.asList(15, 7)); Assertions.assertArrayEquals(expect.toArray(), s.zigzagLevelOrder(root).toArray()); - TreeNode root2 = TreeUtils.buildTree(1); + TreeNode root2 = TreeNode.buildTree(1); List> expect2 = new LinkedList<>(); expect2.add(Arrays.asList(1)); Assertions.assertArrayEquals(expect2.toArray(), s.zigzagLevelOrder(root2).toArray()); - TreeNode root3 = TreeUtils.buildTree(); + TreeNode root3 = TreeNode.buildTree(); List> expect3 = new LinkedList<>(); Assertions.assertArrayEquals(expect3.toArray(), s.zigzagLevelOrder(root3).toArray()); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\205\210\345\272\217\351\201\215\345\216\206\350\277\230\345\216\237\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\205\210\345\272\217\351\201\215\345\216\206\350\277\230\345\216\237\344\272\214\345\217\211\346\240\221.java" index 1ff3498..729b3c0 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\205\210\345\272\217\351\201\215\345\216\206\350\277\230\345\216\237\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\205\210\345\272\217\351\201\215\345\216\206\350\277\230\345\216\237\344\272\214\345\217\211\346\240\221.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import java.util.Stack; @@ -13,7 +12,7 @@ public class 从先序遍历还原二叉树 { public static void main(String[] args) { TreeNode result = recoverFromPreorder("1-2--3--4-5--6--7"); - System.out.println(TreeUtils.toList(result)); + System.out.println(TreeNode.toList(result)); } public static TreeNode recoverFromPreorder(String S) { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\210\240\347\202\271\346\210\220\346\236\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\210\240\347\202\271\346\210\220\346\236\227.java" deleted file mode 100644 index f2e2c0e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\210\240\347\202\271\346\210\220\346\236\227.java" +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 1110. 删点成林 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 删点成林 { - - public static void main(String[] args) { - Solution s = new Solution(); - - TreeNode input = TreeUtils.buildTree(1, 2, 3, 4, 5, 6, 7); - List output = s.delNodes(input, new int[] { 3, 5 }); - // List result1 = TreeUtils.toValueList(output); - // Assertions.assertArrayEquals(new Integer[] { 5, 4, null, 1, 3, null, null, 2 }, result1.toArray()); - - } - - static class Solution { - - List res = new LinkedList<>(); - - public List delNodes(TreeNode root, int[] to_delete) { - if (root == null) return new LinkedList<>(); - - if (isDel(root.val, to_delete)) { - if (root.left == null && root.right == null) { - root = null; - return new LinkedList<>(); - } else { - - } - } else { - res.addAll(delNodes(root.left, to_delete)); - res.addAll(delNodes(root.right, to_delete)); - } - return res; - } - - public boolean isDel(int val, int[] to_delete) { - for (int num : to_delete) { - if (val == num) return true; - } - return false; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" index 33a3db7..03dc2b9 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.Arrays; @@ -32,8 +31,8 @@ public class 叶子相似的树 { public static void main(String[] args) { - TreeNode tree1 = TreeUtils.buildTree(3, 5, 1, 6, 2, 9, 8, null, null, 7, 4); - TreeNode tree2 = TreeUtils.buildTree(3, 5, 1, 6, 7, 4, 2, null, null, null, null, null, null, 9, 8); + TreeNode tree1 = TreeNode.buildTree(3, 5, 1, 6, 2, 9, 8, null, null, 7, 4); + TreeNode tree2 = TreeNode.buildTree(3, 5, 1, 6, 7, 4, 2, null, null, null, null, null, null, 9, 8); Assertions.assertTrue(leafSimilar(tree1, tree2)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\245\207\345\201\266\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\245\207\345\201\266\346\240\221.java" deleted file mode 100644 index 640cecd..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\245\207\345\201\266\346\240\221.java" +++ /dev/null @@ -1,73 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 1609. 奇偶树 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 奇偶树 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.isEvenOddTree(TreeUtils.buildTree(1, 10, 4, 3, null, 7, 9, 12, 8, 6, null, null, 2))); - Assertions.assertFalse(s.isEvenOddTree(TreeUtils.buildTree(5, 4, 2, 3, 3, 7))); - } - - static class Solution { - - public boolean isEvenOddTree(TreeNode root) { - - if (root == null) { return false; } - - LinkedList q = new LinkedList<>(); - q.offer(root); - - int depth = 0; - while (!q.isEmpty()) { - Integer lastValue = null; - int size = q.size(); - for (int i = 0; i < size; i++) { - TreeNode node = q.poll(); - if (!check(depth, node.val, lastValue)) { - return false; - } - if (node.left != null) { q.offer(node.left); } - if (node.right != null) { q.offer(node.right); } - lastValue = node.val; - } - depth++; - } - return true; - } - - public boolean check(int depth, int val, Integer lastValue) { - // 偶数下标 层上的所有节点的值都是 奇 整数,从左到右按顺序 严格递增 - // 奇数下标 层上的所有节点的值都是 偶 整数,从左到右按顺序 严格递减 - if (depth % 2 == 0) { - if (val % 2 == 0) { - return false; - } - if (lastValue != null && val <= lastValue) { - return false; - } - } else { - if (val % 2 != 0) { - return false; - } - if (lastValue != null && val >= lastValue) { - return false; - } - } - return true; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" index 382e6e9..be830dd 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; /** @@ -15,13 +14,13 @@ public class 完全二叉树的节点个数 { public static void main(String[] args) { Solution s = new Solution(); - TreeNode root = TreeUtils.buildTree(1, 2, 3, 4, 5, 6); + TreeNode root = TreeNode.buildTree(1, 2, 3, 4, 5, 6); Assertions.assertEquals(6, s.countNodes(root)); - TreeNode root2 = TreeUtils.buildTree(); + TreeNode root2 = TreeNode.buildTree(); Assertions.assertEquals(0, s.countNodes(root2)); - TreeNode root3 = TreeUtils.buildTree(1); + TreeNode root3 = TreeNode.buildTree(1); Assertions.assertEquals(1, s.countNodes(root3)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" index 45a6822..0daf9e0 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; /** * 101. 对称二叉树 算法实现 @@ -31,10 +30,10 @@ public class 对称二叉树 { public static void main(String[] args) { - TreeNode tree = TreeUtils.buildTree(1, 2, 2, 3, 4, 4, 3); + TreeNode tree = TreeNode.buildTree(1, 2, 2, 3, 4, 4, 3); System.out.println("result = " + isSymmetric(tree)); - tree = TreeUtils.buildTree(1, 2, 2, null, 3, null, 3); + tree = TreeNode.buildTree(1, 2, 2, null, 3, null, 3); System.out.println("result = " + isSymmetric(tree)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" deleted file mode 100644 index 42ed056..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; - -/** - * 1302. 层数最深叶子节点的和 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 层数最深叶子节点的和 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(15, - s.deepestLeavesSum(TreeUtils.buildTree(1, 2, 3, 4, 5, null, 6, 7, null, null, null, null, 8))); - Assertions.assertEquals(19, - s.deepestLeavesSum(TreeUtils.buildTree(6, 7, 8, 2, 7, 1, 3, 9, null, 1, 4, null, null, null, 5))); - } - - static class Solution { - - public int deepestLeavesSum(TreeNode root) { - - if (root == null) { return 0; } - - int lastLevelSum = 0; - LinkedList q = new LinkedList<>(); - q.offer(root); - - while (!q.isEmpty()) { - int sum = 0; - int size = q.size(); - for (int i = 0; i < size; i++) { - TreeNode node = q.poll(); - if (node.left == null && node.right == null) { - sum += node.val; - } - if (node.left != null) { q.offer(node.left); } - if (node.right != null) { q.offer(node.right); } - } - lastLevelSum = sum; - } - return lastLevelSum; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" index 270cdf0..21958c1 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; /** @@ -11,9 +10,9 @@ public class 平衡二叉树 { public static void main(String[] args) { - TreeNode tree = TreeUtils.buildTree(3, 9, 20, null, null, 15, 7); - TreeNode tree2 = TreeUtils.buildTree(1, 2, 2, 3, 3, null, null, 4, 4); - TreeNode tree3 = TreeUtils.buildTree(null); + TreeNode tree = TreeNode.buildTree(3, 9, 20, null, null, 15, 7); + TreeNode tree2 = TreeNode.buildTree(1, 2, 2, 3, 3, null, null, 4, 4); + TreeNode tree3 = TreeNode.buildTree(null); 平衡二叉树 demo = new 平衡二叉树(); Assertions.assertTrue(demo.isBalanced(tree)); Assertions.assertFalse(demo.isBalanced(tree2)); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" index 87944f5..2882f5f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; import java.util.List; @@ -16,11 +15,11 @@ public class 最大二叉树 { public static void main(String[] args) { TreeNode output = constructMaximumBinaryTree(new int[] { 3, 2, 1, 6, 0, 5 }); - List outputList = TreeUtils.toValueList(output); + List outputList = TreeNode.toValueList(output); Assertions.assertArrayEquals(new Integer[] { 6, 3, 5, null, 2, 0, null, null, 1 }, outputList.toArray()); TreeNode root = constructMaximumBinaryTree(new int[] { 3, 2, 1 }); - List list = TreeUtils.toValueList(root); + List list = TreeNode.toValueList(root); Assertions.assertArrayEquals(new Integer[] { 3, null, 2, null, 1 }, list.toArray()); } @@ -29,20 +28,22 @@ public static TreeNode constructMaximumBinaryTree(int[] nums) { } public static TreeNode traverse(int[] nums, int left, int right) { - if (nums == null || nums.length == 0) return null; - if (left > right) return null; + if (left > right) { + return null; + } - int pos = left, max = Integer.MIN_VALUE; + int index = -1; + int max = Integer.MIN_VALUE; for (int i = left; i <= right; i++) { - if (nums[i] > max) { + if (max < nums[i]) { + index = i; max = nums[i]; - pos = i; } } TreeNode root = new TreeNode(max); - root.left = traverse(nums, left, pos - 1); - root.right = traverse(nums, pos + 1, right); + root.left = traverse(nums, left, index - 1); + root.right = traverse(nums, index + 1, right); return root; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" deleted file mode 100644 index 8b0e85c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" +++ /dev/null @@ -1,47 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; -import org.junit.jupiter.api.Assertions; - -import java.util.List; - -/** - * 998. 最大二叉树 II - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 最大二叉树2 { - - public static void main(String[] args) { - Solution s = new Solution(); - - TreeNode input = TreeUtils.buildTree(4, 1, 3, null, null, 2); - TreeNode output = s.insertIntoMaxTree(input, 5); - List result1 = TreeUtils.toValueList(output); - Assertions.assertArrayEquals(new Integer[] { 5, 4, null, 1, 3, null, null, 2 }, result1.toArray()); - - TreeNode input2 = TreeUtils.buildTree(5, 2, 4, null, 1); - TreeNode output2 = s.insertIntoMaxTree(input2, 3); - List result2 = TreeUtils.toValueList(output2); - Assertions.assertArrayEquals(new Integer[] { 5, 2, 4, null, 1, null, 3 }, result2.toArray()); - } - - static class Solution { - - public TreeNode insertIntoMaxTree(TreeNode root, int val) { - if (root == null) return new TreeNode(val); - if (val > root.val) { - TreeNode node = new TreeNode(val); - node.left = root; - return node; - } else { - root.right = insertIntoMaxTree(root.right, val); - } - return root; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\233\270\345\220\214\347\232\204\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\233\270\345\220\214\347\232\204\346\240\221.java" index 96b00c6..7d6ec15 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\233\270\345\220\214\347\232\204\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\233\270\345\220\214\347\232\204\346\240\221.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; /** * 100. 相同的树 算法实现 @@ -46,16 +45,16 @@ public class 相同的树 { public static void main(String[] args) { - TreeNode tree1 = TreeUtils.buildTree(1, 2, 3); - TreeNode tree2 = TreeUtils.buildTree(1, 2, 3); + TreeNode tree1 = TreeNode.buildTree(1, 2, 3); + TreeNode tree2 = TreeNode.buildTree(1, 2, 3); System.out.println("result = " + isSameTree(tree1, tree2)); - tree1 = TreeUtils.buildTree(1, 2); - tree2 = TreeUtils.buildTree(1, 2, 3); + tree1 = TreeNode.buildTree(1, 2); + tree2 = TreeNode.buildTree(1, 2, 3); System.out.println("result = " + isSameTree(tree1, tree2)); - tree1 = TreeUtils.buildTree(1, 2, 1); - tree2 = TreeUtils.buildTree(1, 1, 2); + tree1 = TreeNode.buildTree(1, 2, 1); + tree2 = TreeNode.buildTree(1, 1, 2); System.out.println("result = " + isSameTree(tree1, tree2)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" index b7cc361..736aa53 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; /** * 226. 翻转二叉树 @@ -12,7 +11,7 @@ public class 翻转二叉树 { public static void main(String[] args) { - TreeNode tree = TreeUtils.buildTree(4, 2, 7, 1, 3, 6, 9); + TreeNode tree = TreeNode.buildTree(4, 2, 7, 1, 3, 6, 9); System.out.println("result = " + invertTree2(tree)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" index edf8641..5d09719 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; import org.junit.jupiter.api.Assertions; /** @@ -31,9 +30,9 @@ public class 路径总和 { public static void main(String[] args) { TreeNode - tree = TreeUtils.buildTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, null, null, 1); + tree = TreeNode.buildTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, null, null, 1); Assertions.assertTrue(hasPathSum(tree, 22)); - TreeNode tree2 = TreeUtils.buildTree(1, 2); + TreeNode tree2 = TreeNode.buildTree(1, 2); Assertions.assertFalse(hasPathSum(tree2, 1)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" deleted file mode 100644 index 1662c7e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" +++ /dev/null @@ -1,63 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.TreeUtils; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 331. 验证二叉树的前序序列化 - * - * @author Zhang Peng - * @date 2025-08-15 - */ -public class 验证二叉树的前序序列化 { - - public static void main(String[] args) { - Assertions.assertTrue(new Solution().isValidSerialization("9,3,4,#,#,1,#,#,2,#,6,#,#")); - Assertions.assertFalse(new Solution().isValidSerialization("1,#")); - Assertions.assertFalse(new Solution().isValidSerialization("9,#,#,1")); - } - - static class Solution { - - public static final String SEP = ","; - public static final String NULL = "#"; - boolean isOk = true; - - public boolean isValidSerialization(String preorder) { - LinkedList nodes = new LinkedList<>(); - for (String s : preorder.split(SEP)) { - nodes.addFirst(s); - } - deserialize(nodes); - if (nodes.size() > 0) { - isOk = false; - } - return isOk; - } - - public TreeNode deserialize(LinkedList values) { - - if (values.isEmpty()) return null; - - String value = values.removeLast(); - if (NULL.equals(value)) { - return null; - } - if (values.isEmpty() || values.size() < 2) { - isOk = false; - return null; - } - TreeNode node = new TreeNode(Integer.parseInt(value)); - - node.left = deserialize(values); - node.right = deserialize(values); - - return node; - } - - } - -} From 17047d6c62bcd6d14e113ac25190fd04c82ccb39 Mon Sep 17 00:00:00 2001 From: dunwu Date: Tue, 4 Nov 2025 06:33:30 +0800 Subject: [PATCH 10/21] =?UTF-8?q?feat:=20leetcode=20=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\345\205\250\346\216\222\345\210\227.java" | 61 ++ ...\350\247\243\346\225\260\347\213\254.java" | 44 + .../LRU\347\274\223\345\255\230.java" | 63 ++ ...\345\256\211\346\216\222\350\241\250.java" | 45 + ...\347\244\272\345\215\241\347\211\214.java" | 43 + ...\347\224\237\346\225\260\351\207\217.java" | 53 + ...\350\256\241\347\256\227\345\231\250.java" | 31 + ...\345\216\206\346\241\206\346\236\266.java" | 39 + ...\344\272\214\345\210\206\345\233\276.java" | 76 ++ ...\347\232\204\350\267\257\345\276\204.java" | 67 ++ .../github/dunwu/algorithm/map/LRUCache.java | 45 - ...\346\234\200\345\260\217\346\240\210.java" | 20 +- ...\350\256\241\347\256\227\345\231\250.java" | 115 ++- ...350\256\241\347\256\227\345\231\2502.java" | 73 ++ .../github/dunwu/algorithm/tree/BaseCase.java | 25 + .../dunwu/algorithm/tree/BinaryTree.java | 937 ------------------ .../github/dunwu/algorithm/tree/NAryTree.java | 32 + .../github/dunwu/algorithm/tree/TreeNode.java | 6 - ...\346\220\234\347\264\242\346\240\221.java" | 45 + ...346\220\234\347\264\242\346\240\2212.java" | 80 ++ ...\347\232\204\345\205\203\347\264\240.java" | 19 +- ...\345\205\261\347\245\226\345\205\210.java" | 83 +- ...\345\260\217\350\267\235\347\246\273.java" | 91 +- ...\347\232\204\350\212\202\347\202\271.java" | 77 +- ...\346\220\234\347\264\242\346\240\221.java" | 46 +- ...\346\220\234\347\264\242\346\240\221.java" | 37 +- ...\345\272\217\351\201\215\345\216\206.java" | 82 ++ ...\346\217\222\345\205\245\345\231\250.java" | 72 ++ ...\351\245\260\350\256\260\345\275\225.java" | 44 + ...351\245\260\350\256\260\345\275\2252.java" | 57 ++ ...351\245\260\350\256\260\345\275\2253.java" | 63 ++ ...\346\240\221\345\211\252\346\236\235.java" | 38 + ...\345\272\217\351\201\215\345\216\206.java" | 53 + ...\345\272\217\351\201\215\345\216\206.java" | 79 ++ ...\345\272\217\351\201\215\345\216\206.java" | 55 + ...\347\232\204\345\235\241\345\272\246.java" | 41 + ...\345\205\203\347\264\240\345\222\214.java" | 61 ++ ...\345\255\220\350\212\202\347\202\271.java" | 38 + ...\344\274\274\347\232\204\346\240\221.java" | 55 + ...\344\272\214\345\217\211\346\240\221.java" | 44 + ...\350\267\257\345\276\204\345\222\214.java" | 41 + ...\344\272\214\345\217\211\346\240\221.java" | 35 +- ...\344\272\214\345\217\211\346\240\221.java" | 36 +- ...\347\202\271\346\210\220\346\236\227.java" | 35 +- ...\344\272\214\345\217\211\346\240\221.java" | 38 + ...\344\272\214\345\217\211\346\240\221.java" | 30 +- ...344\272\214\345\217\211\346\240\2212.java" | 55 +- ...\344\272\214\345\217\211\346\240\221.java" | 42 +- ...\345\220\214\347\232\204\346\240\221.java" | 32 + ...\344\272\214\345\217\211\346\240\221.java" | 40 + ...\345\272\217\345\210\227\345\214\226.java" | 46 +- ...\346\226\207\350\267\257\345\276\204.java" | 59 +- ...\345\217\263\350\247\206\345\233\276.java" | 81 +- ...\346\234\211\350\267\257\345\276\204.java" | 35 +- ...\345\255\227\347\254\246\344\270\262.java" | 54 +- ...\346\225\260\344\271\213\345\222\214.java" | 45 +- ...\345\255\227\344\271\213\345\222\214.java" | 56 +- ...\350\267\257\345\276\204\345\222\214.java" | 53 - ...\344\270\272\351\223\276\350\241\250.java" | 41 +- ...\345\272\217\351\201\215\345\216\206.java" | 49 - ...\345\272\217\351\201\215\345\216\206.java" | 67 -- ...\345\272\217\351\201\215\345\216\206.java" | 54 - ...\345\272\217\345\210\227\345\214\226.java" | 72 +- ...\345\244\247\346\267\261\345\272\246.java" | 58 +- ...\345\205\261\347\245\226\345\205\210.java" | 56 +- ...\347\232\204\347\233\264\345\276\204.java" | 30 +- ...\347\202\271\344\270\252\346\225\260.java" | 16 +- ...\344\272\214\345\217\211\346\240\221.java" | 51 - ...\344\272\214\345\217\211\346\240\221.java" | 42 - ...\344\272\214\345\217\211\346\240\221.java" | 38 +- ...\345\220\214\347\232\204\346\240\221.java" | 71 -- ...\344\272\214\345\217\211\346\240\221.java" | 76 +- ...\345\216\206\346\241\206\346\236\266.java" | 30 + ...\345\216\206\346\241\206\346\236\266.java" | 35 + .../dunwu/algorithm/map/LRUCacheTest.java | 24 - .../dunwu/algorithm/tree/BinaryTreeTests.java | 27 - 76 files changed, 2563 insertions(+), 2122 deletions(-) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\345\205\250\346\216\222\345\210\227.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\350\247\243\346\225\260\347\213\254.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/LRU\347\274\223\345\255\230.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\350\256\241\347\256\227\345\231\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\233\276\347\232\204DFS\351\201\215\345\216\206\346\241\206\346\236\266.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" delete mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/map/LRUCache.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BaseCase.java delete mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BinaryTree.java create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/NAryTree.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\225.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\2252.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\2253.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\345\211\252\346\236\235.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\235\241\345\272\246.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\210\240\351\231\244\347\273\231\345\256\232\345\200\274\347\232\204\345\217\266\345\255\220\350\212\202\347\202\271.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\233\270\345\220\214\347\232\204\346\240\221.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\233\270\345\220\214\347\232\204\346\240\221.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\344\272\214\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\345\244\232\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" delete mode 100644 codes/algorithm/src/test/java/io/github/dunwu/algorithm/map/LRUCacheTest.java delete mode 100644 codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BinaryTreeTests.java diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\345\205\250\346\216\222\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\345\205\250\346\216\222\345\210\227.java" new file mode 100644 index 0000000..40279c8 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\345\205\250\346\216\222\345\210\227.java" @@ -0,0 +1,61 @@ +package io.github.dunwu.algorithm.backtrack; + +import java.util.LinkedList; +import java.util.List; + +/** + * 46. 全排列 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 全排列 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[] input = new int[] { 1, 2, 3 }; + List> output = s.permute(input); + System.out.println("output: " + output); + } + + static class Solution { + + private List> res = null; + + public List> permute(int[] nums) { + // 记录「路径」 + LinkedList track = new LinkedList<>(); + // 「路径」中的元素会被标记为 true,避免重复使用 + boolean[] used = new boolean[nums.length]; + res = new LinkedList<>(); + backtrack(nums, track, used); + return res; + } + + public void backtrack(int[] nums, LinkedList track, boolean[] used) { + if (track.size() == nums.length) { + res.add(new LinkedList<>(track)); + return; + } + + for (int i = 0; i < nums.length; i++) { + if (used[i]) { + continue; + } + + // 选择 + track.addLast(nums[i]); + used[i] = true; + + // 进入下一层决策树 + backtrack(nums, track, used); + + // 取消选择 + track.removeLast(); + used[i] = false; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\350\247\243\346\225\260\347\213\254.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\350\247\243\346\225\260\347\213\254.java" new file mode 100644 index 0000000..4f4d548 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\350\247\243\346\225\260\347\213\254.java" @@ -0,0 +1,44 @@ +package io.github.dunwu.algorithm.backtrack; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 37. 解数独 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 解数独 { + + public static void main(String[] args) { + Solution s = new Solution(); + char[][] input = new char[][] { { '5', '3', '.', '.', '7', '.', '.', '.', '.' }, + { '6', '.', '.', '1', '9', '5', '.', '.', '.' }, { '.', '9', '8', '.', '.', '.', '.', '6', '.' }, + { '8', '.', '.', '.', '6', '.', '.', '.', '3' }, { '4', '.', '.', '8', '.', '3', '.', '.', '1' }, + { '7', '.', '.', '.', '2', '.', '.', '.', '6' }, { '.', '6', '.', '.', '.', '.', '2', '8', '.' }, + { '.', '.', '.', '4', '1', '9', '.', '.', '5' }, { '.', '.', '.', '.', '8', '.', '.', '7', '9' } }; + char[][] expect = new char[][] { { '5', '3', '4', '6', '7', '8', '9', '1', '2' }, + { '6', '7', '2', '1', '9', '5', '3', '4', '8' }, { '1', '9', '8', '3', '4', '2', '5', '6', '7' }, + { '8', '5', '9', '7', '6', '1', '4', '2', '3' }, { '4', '2', '6', '8', '5', '3', '7', '9', '1' }, + { '7', '1', '3', '9', '2', '4', '8', '5', '6' }, { '9', '6', '1', '5', '3', '7', '2', '8', '4' }, + { '2', '8', '7', '4', '1', '9', '6', '3', '5' }, { '3', '4', '5', '2', '8', '6', '1', '7', '9' } }; + s.solveSudoku(input); + Assertions.assertArrayEquals(expect, input); + } + + static class Solution { + + public void solveSudoku(char[][] board) { + + } + + public void backtrack(char[][] board, LinkedList track, boolean[] used) { + + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/LRU\347\274\223\345\255\230.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/LRU\347\274\223\345\255\230.java" new file mode 100644 index 0000000..f716636 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/LRU\347\274\223\345\255\230.java" @@ -0,0 +1,63 @@ +package io.github.dunwu.algorithm.data_structure; + +import org.junit.jupiter.api.Assertions; + +import java.util.Iterator; +import java.util.LinkedHashMap; + +/** + * 146. LRU 缓存 + * + * @author Zhang Peng + * @date 2025-10-31 + */ +public class LRU缓存 { + + public static void main(String[] args) { + + LRUCache lRUCache = new LRUCache(2); + lRUCache.put(1, 1); // 缓存是 {1=1} + lRUCache.put(2, 2); // 缓存是 {1=1, 2=2} + Assertions.assertEquals(1, lRUCache.get(1)); + lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3} + Assertions.assertEquals(-1, lRUCache.get(2)); + lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3} + Assertions.assertEquals(-1, lRUCache.get(1)); + Assertions.assertEquals(3, lRUCache.get(3)); + Assertions.assertEquals(4, lRUCache.get(4)); + } + + static class LRUCache { + + private int capacity = 0; + private LinkedHashMap cache = null; + + public LRUCache(int capacity) { + this.capacity = capacity; + this.cache = new LinkedHashMap<>(capacity); + } + + public int get(int key) { + Integer val = cache.get(key); + if (val != null) { + cache.remove(key); + cache.put(key, val); + } + return val == null ? -1 : val; + } + + public void put(int key, int value) { + if (cache.containsKey(key)) { + cache.remove(key); + } else { + if (capacity <= cache.size()) { + Iterator iterator = cache.keySet().iterator(); + cache.remove(iterator.next()); + } + } + cache.put(key, value); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" new file mode 100644 index 0000000..6ffed58 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" @@ -0,0 +1,45 @@ +package io.github.dunwu.algorithm.data_structure; + +import org.junit.jupiter.api.Assertions; + +import java.util.TreeMap; + +/** + * 729. 我的日程安排表 I + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 我的日程安排表 { + + public static void main(String[] args) { + MyCalendar s = new MyCalendar(); + Assertions.assertTrue(s.book(10, 20)); + Assertions.assertFalse(s.book(15, 25)); + Assertions.assertTrue(s.book(20, 30)); + } + + static class MyCalendar { + + private TreeMap calendar = null; + + public MyCalendar() { + calendar = new TreeMap<>(); + } + + public boolean book(int start, int end) { + Integer earlier = calendar.floorKey(start); + Integer later = calendar.ceilingKey(start); + if (later != null && later < end) { + return false; + } + if (earlier != null && start < calendar.get(earlier)) { + return false; + } + calendar.put(start, end); + return true; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" new file mode 100644 index 0000000..3c5631d --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" @@ -0,0 +1,43 @@ +package io.github.dunwu.algorithm.data_structure; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.LinkedList; + +/** + * 950. 按递增顺序显示卡牌 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 按递增顺序显示卡牌 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new int[] { 2, 13, 3, 11, 5, 17, 7 } + , s.deckRevealedIncreasing(new int[] { 17, 13, 11, 2, 3, 5, 7 })); + } + + static class Solution { + + public int[] deckRevealedIncreasing(int[] deck) { + int n = deck.length; + LinkedList res = new LinkedList<>(); + Arrays.sort(deck); + for (int i = n - 1; i >= 0; i--) { + if (!res.isEmpty()) { + res.addFirst(res.removeLast()); + } + res.addFirst(deck[i]); + } + int[] arr = new int[n]; + for (int i = 0; i < res.size(); i++) { + arr[i] = res.get(i); + } + return arr; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" new file mode 100644 index 0000000..dce18d0 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" @@ -0,0 +1,53 @@ +package io.github.dunwu.algorithm.data_structure; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.LinkedList; + +/** + * 1700. 无法吃午餐的学生数量 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 无法吃午餐的学生数量 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(0, s.countStudents(new int[] { 1, 1, 0, 0 }, new int[] { 0, 1, 0, 1 })); + Assertions.assertEquals(3, s.countStudents(new int[] { 1, 1, 1, 0, 0, 1 }, new int[] { 1, 0, 0, 0, 1, 1 })); + } + + static class Solution { + + public int countStudents(int[] students, int[] sandwiches) { + int total = students.length; + LinkedList studentQueue = new LinkedList<>(); + for (int s : students) { + studentQueue.addLast(s); + } + int matchNum = 0; + while (matchNum < sandwiches.length) { + int notMatchNum = 0; + int size = studentQueue.size(); + while (notMatchNum < size) { + Integer s = studentQueue.removeFirst(); + if (s == sandwiches[matchNum]) { + matchNum++; + break; + } else { + studentQueue.addLast(s); + notMatchNum++; + } + } + if (notMatchNum == size) { + break; + } + } + return total - matchNum; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\350\256\241\347\256\227\345\231\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\350\256\241\347\256\227\345\231\250.java" new file mode 100644 index 0000000..51b5b65 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\350\256\241\347\256\227\345\231\250.java" @@ -0,0 +1,31 @@ +package io.github.dunwu.algorithm.data_structure; + +import java.util.Arrays; + +/** + * 计数器模板 + * + * @author Zhang Peng + * @date 2025-10-31 + */ +public class 计算器 { + + public static void main(String[] args) { + Solution s = new Solution(); + System.out.println("args = " + Arrays.toString(args)); + } + + static class Solution { + + public int toNum(String s) { + if (s == null || s.length() == 0) { return 0; } + int num = 0; + for (char c : s.toCharArray()) { + num = num * 10 + (c - '0'); + } + return num; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\233\276\347\232\204DFS\351\201\215\345\216\206\346\241\206\346\236\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\233\276\347\232\204DFS\351\201\215\345\216\206\346\241\206\346\236\266.java" new file mode 100644 index 0000000..7a2e5dd --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\233\276\347\232\204DFS\351\201\215\345\216\206\346\241\206\346\236\266.java" @@ -0,0 +1,39 @@ +package io.github.dunwu.algorithm.graph.template; + +/** + * 图的遍历框架 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 图的DFS遍历框架 { + + // 图的遍历框架 + // 需要一个 visited 数组记录被遍历过的节点 + // 避免走回头路陷入死循环 + void traverse(Vertex s, boolean[] visited) { + // base case + if (s == null) { + return; + } + if (visited[s.id]) { + // 防止死循环 + return; + } + // 前序位置 + visited[s.id] = true; + System.out.println("visit " + s.id); + for (Vertex neighbor : s.neighbors) { + traverse(neighbor, visited); + } + // 后序位置 + } + + static class Vertex { + + int id; + Vertex[] neighbors; + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" new file mode 100644 index 0000000..ad8e078 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" @@ -0,0 +1,76 @@ +package io.github.dunwu.algorithm.graph; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 785. 判断二分图 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 判断二分图 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[][] input = new int[][] { + { 1, 2, 3 }, { 0, 2 }, { 0, 1, 3 }, { 0, 2 } + }; + Assertions.assertFalse(s.isBipartite(input)); + } + + static class Solution { + + // 记录图是否符合二分图性质 + private boolean ok = true; + // 记录图中节点的颜色,false 和 true 代表两种不同颜色 + private boolean[] color; + // 记录图中节点是否被访问过 + private boolean[] visited; + + // 主函数,输入邻接表,判断是否是二分图 + public boolean isBipartite(int[][] graph) { + int n = graph.length; + color = new boolean[n]; + visited = new boolean[n]; + // 因为图不一定是联通的,可能存在多个子图 + // 所以要把每个节点都作为起点进行一次遍历 + // 如果发现任何一个子图不是二分图,整幅图都不算二分图 + for (int v = 0; v < n; v++) { + if (!visited[v]) { + traverse(graph, v); + } + } + return ok; + } + + // DFS 遍历框架 + private void traverse(int[][] graph, int v) { + // 如果已经确定不是二分图了,就不用浪费时间再递归遍历了 + if (!ok) return; + + visited[v] = true; + for (int w : graph[v]) { + if (!visited[w]) { + // 相邻节点 w 没有被访问过 + // 那么应该给节点 w 涂上和节点 v 不同的颜色 + color[w] = !color[v]; + // 继续遍历 w + traverse(graph, w); + } else { + // 相邻节点 w 已经被访问过 + // 根据 v 和 w 的颜色判断是否是二分图 + if (color[w] == color[v]) { + // 若相同,则此图不是二分图 + ok = false; + } + } + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" new file mode 100644 index 0000000..3fbd0c5 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" @@ -0,0 +1,67 @@ +package io.github.dunwu.algorithm.graph; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 797. 所有可能的路径 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 所有可能的路径 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[][] input = new int[][] { + { 1, 2 }, { 3 }, { 3 }, {} + }; + List> expect = new LinkedList<>(); + expect.add(Arrays.asList(0, 1, 3)); + expect.add(Arrays.asList(0, 2, 3)); + List> output = s.allPathsSourceTarget(input); + for (int i = 0; i < expect.size(); i++) { + Assertions.assertArrayEquals(expect.get(i).toArray(), output.get(i).toArray()); + } + System.out.println("v = " + output); + } + + static class Solution { + + LinkedList> res = new LinkedList<>(); + LinkedList path = new LinkedList<>(); + + public List> allPathsSourceTarget(int[][] graph) { + if (graph == null || graph.length == 0) return res; + traverse(graph, 0); + return res; + } + + void traverse(int[][] graph, int s) { + + // 添加节点 s 到路径 + path.addLast(s); + + int n = graph.length; + if (s == n - 1) { + // 到达终点 + res.add(new LinkedList<>(path)); + path.removeLast(); + return; + } + + // 递归每个相邻节点 + for (int v : graph[s]) { + traverse(graph, v); + } + + // 从路径移出节点 s + path.removeLast(); + } + + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/map/LRUCache.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/map/LRUCache.java deleted file mode 100644 index 6723dd3..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/map/LRUCache.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.github.dunwu.algorithm.map; - -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * @author Zhang Peng - * @since 2020-01-18 - */ -class LRUCache { - - private int capacity; - - // 保持插入顺序 - private Map map; - - public LRUCache(int capacity) { - this.capacity = capacity; - map = new LinkedHashMap<>(capacity); - } - - public int get(int key) { - if (map.containsKey(key)) { - int value = map.get(key); - map.remove(key); - // 保证每次查询后,都在末尾 - map.put(key, value); - return value; - } - return -1; - } - - public void put(int key, int value) { - if (map.containsKey(key)) { - map.remove(key); - } else if (map.size() == capacity) { - Iterator> iterator = map.entrySet().iterator(); - iterator.next(); - iterator.remove(); - } - map.put(key, value); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\260\217\346\240\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\260\217\346\240\210.java" index 97f1b47..44783f6 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\260\217\346\240\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\260\217\346\240\210.java" @@ -25,28 +25,28 @@ public static void main(String[] args) { static class MinStack { - private Stack stack; - private Stack min; + // 记录栈中的所有元素 + Stack stack; + // 阶段性记录栈中的最小元素 + Stack minStack; public MinStack() { stack = new Stack<>(); - min = new Stack<>(); + minStack = new Stack<>(); } public void push(int val) { stack.push(val); - if (min.isEmpty() || val <= min.peek()) { - // 新插入的这个元素就是全栈最小的 - min.push(val); + if (minStack.isEmpty() || val < minStack.peek()) { + minStack.push(val); } else { - // 插入的这个元素比较大 - min.push(min.peek()); + minStack.push(minStack.peek()); } } public void pop() { + minStack.pop(); stack.pop(); - min.pop(); } public int top() { @@ -54,7 +54,7 @@ public int top() { } public int getMin() { - return min.peek(); + return minStack.peek(); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" index c63bd08..bf9bc63 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" @@ -1,66 +1,89 @@ package io.github.dunwu.algorithm.queue_and_stack; -import io.github.dunwu.algorithm.queue_and_stack.stack.GenericStack; import org.junit.jupiter.api.Assertions; +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; + /** + * 224. 基本计算器 + * * @author Zhang Peng - * @see 224. 基本计算器 * @since 2020-06-09 */ public class 基本计算器 { public static void main(String[] args) { - Assertions.assertEquals(23, calculate("(1+(4+5+2)-3)+(6+8)")); - Assertions.assertEquals(3, calculate("2-(5-6)")); - Assertions.assertEquals(12, calculate("1+(4+5+2)")); - Assertions.assertEquals(2147483647, calculate("2147483647")); - Assertions.assertEquals(2, calculate("1 + 1")); - Assertions.assertEquals(3, calculate("2 - 1 + 2")); + Solution s = new Solution(); + Assertions.assertEquals(23, s.calculate("(1+(4+5+2)-3)+(6+8)")); + Assertions.assertEquals(12, s.calculate("1+(4+5+2)")); + Assertions.assertEquals(2147483647, s.calculate("2147483647")); + Assertions.assertEquals(2, s.calculate("1 + 1")); + Assertions.assertEquals(3, s.calculate("2 - 1 + 2")); } - public static int calculate(String s) { - int sign = 1; - int current = 0; - int result = 0; - GenericStack stack = new GenericStack<>(); - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if (Character.isDigit(c)) { - current = current * 10 + (c - '0'); - } else if (c == '+') { - // 累加上一个操作数并重置 - result = result + sign * current; - current = 0; - // 设置下一个操作数的正负号 - sign = 1; - } else if (c == '-') { - // 累加上一个操作数并重置 - result = result + sign * current; - current = 0; - // 设置下一个操作数的正负号 - sign = -1; - } else if (c == '(') { - stack.push(result); - stack.push(sign); - sign = 1; - result = 0; - } else if (c == ')') { - // 累加上一个操作数并重置 - result = result + sign * current; - current = 0; - // 依次取出暂存栈中的正负号和操作数 - sign = stack.pop(); - int temp = stack.pop(); - // 累加 - result = temp + sign * result; + static class Solution { + + public int calculate(String s) { + Stack stack = new Stack<>(); + Map map = new HashMap<>(); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + stack.push(i); + } else if (s.charAt(i) == ')') { + map.put(stack.pop(), i); + } } + return calculate(s, 0, s.length() - 1, map); } - if (current != 0) { - result = result + sign * current; + public int calculate(String s, int start, int end, Map map) { + int num = 0; + char sign = '+'; + Stack stack = new Stack<>(); + for (int i = start; i <= end; i++) { + char c = s.charAt(i); + if (Character.isDigit(c)) { + num = num * 10 + (c - '0'); + } + if (c == '(') { + num = calculate(s, i + 1, map.get(i) - 1, map); + i = map.get(i); + } + + if (c == '+' || c == '-' || c == '*' || c == '/' || i == end) { + int pre = 0; + switch (sign) { + case '+': + stack.push(num); + break; + case '-': + stack.push(-num); + break; + case '*': + pre = stack.pop(); + stack.push(pre * num); + break; + case '/': + pre = stack.pop(); + stack.push(pre / num); + break; + default: + break; + } + sign = c; + num = 0; + } + } + + int result = 0; + while (!stack.isEmpty()) { + result += stack.pop(); + } + return result; } - return result; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" new file mode 100644 index 0000000..04461e7 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" @@ -0,0 +1,73 @@ +package io.github.dunwu.algorithm.queue_and_stack; + +import io.github.dunwu.algorithm.queue_and_stack.stack.GenericStack; +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 227. 基本计算器 II + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 基本计算器2 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(2147483647, s.calculate("2147483647")); + Assertions.assertEquals(2, s.calculate("1 + 1")); + Assertions.assertEquals(3, s.calculate("2 - 1 + 2")); + Assertions.assertEquals(7, s.calculate("3+2*2")); + } + + static class Solution { + + public int calculate(String s) { + return calculate(s, 0, s.length() - 1); + } + + public int calculate(String s, int start, int end) { + int num = 0; + char sign = '+'; + Stack stack = new Stack<>(); + for (int i = start; i <= end; i++) { + char c = s.charAt(i); + if (Character.isDigit(c)) { + num = num * 10 + (c - '0'); + } + if (c == '+' || c == '-' || c == '*' || c == '/' || i == s.length() - 1) { + int pre = 0; + switch (sign) { + case '+': + stack.push(num); + break; + case '-': + stack.push(-num); + break; + case '*': + pre = stack.pop(); + stack.push(pre * num); + break; + case '/': + pre = stack.pop(); + stack.push(pre / num); + break; + default: + break; + } + sign = c; + num = 0; + } + } + + int result = 0; + while (!stack.isEmpty()) { + result += stack.pop(); + } + return result; + } + + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BaseCase.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BaseCase.java new file mode 100644 index 0000000..f6ea850 --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BaseCase.java @@ -0,0 +1,25 @@ +package io.github.dunwu.algorithm.tree; + +import java.util.List; + +/** + * 基本示例 + * + * @author Zhang Peng + * @date 2025-10-27 + */ +public class BaseCase { + + public static class Node extends NAryTree { + + public Node(int val) { + super(val); + } + + public Node(int val, List children) { + super(val, children); + } + + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BinaryTree.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BinaryTree.java deleted file mode 100644 index 84fbd3d..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BinaryTree.java +++ /dev/null @@ -1,937 +0,0 @@ -package io.github.dunwu.algorithm.tree; - -import io.github.dunwu.algorithm.common.ITree; - -import java.util.ArrayDeque; -import java.util.Arrays; -import java.util.Comparator; -import java.util.Deque; - -/** - * B树是一种树数据结构,可以对数据进行排序,并允许以对数时间进行搜索,顺序访问,插入和删除。 - *

- * B树是二叉搜索树的一般化,因为节点可以有两个以上的子节点。 - *

- * 与自平衡二进制搜索树不同,B树针对读取和写入大块数据的系统进行了优化。 - *

- * 它通常用于数据库和文件系统。 - *

- * - * @author Justin Wetherell - * @see B-Tree (Wikipedia) - */ -@SuppressWarnings("ALL") -public class BinaryTree> implements ITree { - - private int minKeySize = 1; - - private int minChildrenSize = minKeySize + 1; // 2 - - private int maxKeySize = 2 * minKeySize; // 2 - - private int maxChildrenSize = maxKeySize + 1; // 3 - - private Node root = null; - - private int size = 0; - - /** - * Constructor for B-Tree which defaults to a 2-3 B-Tree. - */ - public BinaryTree() { - } - - /** - * Constructor for B-Tree of ordered parameter. Order here means minimum number of keys in a non-root node. - * - * @param order of the B-Tree. - */ - public BinaryTree(int order) { - this.minKeySize = order; - this.minChildrenSize = minKeySize + 1; - this.maxKeySize = 2 * minKeySize; - this.maxChildrenSize = maxKeySize + 1; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean add(T value) { - if (root == null) { - root = new Node(null, maxKeySize, maxChildrenSize); - root.addKey(value); - } else { - Node node = root; - while (node != null) { - if (node.numberOfChildren() == 0) { - node.addKey(value); - if (node.numberOfKeys() <= maxKeySize) { - // A-OK - break; - } - // Need to split up - split(node); - break; - } - // Navigate - - // Lesser or equal - T lesser = node.getKey(0); - if (value.compareTo(lesser) <= 0) { - node = node.getChild(0); - continue; - } - - // Greater - int numberOfKeys = node.numberOfKeys(); - int last = numberOfKeys - 1; - T greater = node.getKey(last); - if (value.compareTo(greater) > 0) { - node = node.getChild(numberOfKeys); - continue; - } - - // Search internal nodes - for (int i = 1; i < node.numberOfKeys(); i++) { - T prev = node.getKey(i - 1); - T next = node.getKey(i); - if (value.compareTo(prev) > 0 && value.compareTo(next) <= 0) { - node = node.getChild(i); - break; - } - } - } - } - - size++; - - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public T remove(T value) { - T removed = null; - Node node = this.getNode(value); - removed = remove(value, node); - return removed; - } - - /** - * {@inheritDoc} - */ - @Override - public void clear() { - root = null; - size = 0; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean contains(T value) { - Node node = getNode(value); - return (node != null); - } - - /** - * Get the node with value. - * - * @param value to find in the tree. - * @return Node with value. - */ - private Node getNode(T value) { - Node node = root; - while (node != null) { - T lesser = node.getKey(0); - if (value.compareTo(lesser) < 0) { - if (node.numberOfChildren() > 0) { - node = node.getChild(0); - } else { - node = null; - } - continue; - } - - int numberOfKeys = node.numberOfKeys(); - int last = numberOfKeys - 1; - T greater = node.getKey(last); - if (value.compareTo(greater) > 0) { - if (node.numberOfChildren() > numberOfKeys) { - node = node.getChild(numberOfKeys); - } else { - node = null; - } - continue; - } - - for (int i = 0; i < numberOfKeys; i++) { - T currentValue = node.getKey(i); - if (currentValue.compareTo(value) == 0) { - return node; - } - - int next = i + 1; - if (next <= last) { - T nextValue = node.getKey(next); - if (currentValue.compareTo(value) < 0 && nextValue.compareTo(value) > 0) { - if (next < node.numberOfChildren()) { - node = node.getChild(next); - break; - } - return null; - } - } - } - } - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public int size() { - return size; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean validate() { - if (root == null) { - return true; - } - return validateNode(root); - } - - /** - * {@inheritDoc} - */ - @Override - public java.util.Collection toCollection() { - return (new JavaCompatibleBinaryTree(this)); - } - - /** - * The node's key size is greater than maxKeySize, split down the middle. - * - * @param nodeToSplit to split. - */ - private void split(Node nodeToSplit) { - Node node = nodeToSplit; - int numberOfKeys = node.numberOfKeys(); - int medianIndex = numberOfKeys / 2; - T medianValue = node.getKey(medianIndex); - - Node left = new Node(null, maxKeySize, maxChildrenSize); - for (int i = 0; i < medianIndex; i++) { - left.addKey(node.getKey(i)); - } - if (node.numberOfChildren() > 0) { - for (int j = 0; j <= medianIndex; j++) { - Node c = node.getChild(j); - left.addChild(c); - } - } - - Node right = new Node(null, maxKeySize, maxChildrenSize); - for (int i = medianIndex + 1; i < numberOfKeys; i++) { - right.addKey(node.getKey(i)); - } - if (node.numberOfChildren() > 0) { - for (int j = medianIndex + 1; j < node.numberOfChildren(); j++) { - Node c = node.getChild(j); - right.addChild(c); - } - } - - if (node.parent == null) { - // new root, height of tree is increased - Node newRoot = new Node(null, maxKeySize, maxChildrenSize); - newRoot.addKey(medianValue); - node.parent = newRoot; - root = newRoot; - node = root; - node.addChild(left); - node.addChild(right); - } else { - // Move the median value up to the parent - Node parent = node.parent; - parent.addKey(medianValue); - parent.removeChild(node); - parent.addChild(left); - parent.addChild(right); - - if (parent.numberOfKeys() > maxKeySize) { - split(parent); - } - } - } - - /** - * Remove the value from the Node and check invariants - * - * @param value T to remove from the tree - * @param node Node to remove value from - * @return True if value was removed from the tree. - */ - private T remove(T value, Node node) { - if (node == null) { - return null; - } - - T removed = null; - int index = node.indexOf(value); - removed = node.removeKey(value); - if (node.numberOfChildren() == 0) { - // leaf node - if (node.parent != null && node.numberOfKeys() < minKeySize) { - this.combined(node); - } else if (node.parent == null && node.numberOfKeys() == 0) { - // Removing root node with no keys or children - root = null; - } - } else { - // internal node - Node lesser = node.getChild(index); - Node greatest = this.getGreatestNode(lesser); - T replaceValue = this.removeGreatestValue(greatest); - node.addKey(replaceValue); - if (greatest.parent != null && greatest.numberOfKeys() < minKeySize) { - this.combined(greatest); - } - if (greatest.numberOfChildren() > maxChildrenSize) { - this.split(greatest); - } - } - - size--; - - return removed; - } - - /** - * Remove greatest valued key from node. - * - * @param node to remove greatest value from. - * @return value removed; - */ - private T removeGreatestValue(Node node) { - T value = null; - if (node.numberOfKeys() > 0) { - value = node.removeKey(node.numberOfKeys() - 1); - } - return value; - } - - /** - * Get the greatest valued child from node. - * - * @param nodeToGet child with the greatest value. - * @return Node child with greatest value. - */ - private Node getGreatestNode(Node nodeToGet) { - Node node = nodeToGet; - while (node.numberOfChildren() > 0) { - node = node.getChild(node.numberOfChildren() - 1); - } - return node; - } - - /** - * Combined children keys with parent when size is less than minKeySize. - * - * @param node with children to combined. - * @return True if combined successfully. - */ - private boolean combined(Node node) { - Node parent = node.parent; - int index = parent.indexOf(node); - int indexOfLeftNeighbor = index - 1; - int indexOfRightNeighbor = index + 1; - - Node rightNeighbor = null; - int rightNeighborSize = -minChildrenSize; - if (indexOfRightNeighbor < parent.numberOfChildren()) { - rightNeighbor = parent.getChild(indexOfRightNeighbor); - rightNeighborSize = rightNeighbor.numberOfKeys(); - } - - // Try to borrow neighbor - if (rightNeighbor != null && rightNeighborSize > minKeySize) { - // Try to borrow from right neighbor - T removeValue = rightNeighbor.getKey(0); - int prev = getIndexOfPreviousValue(parent, removeValue); - T parentValue = parent.removeKey(prev); - T neighborValue = rightNeighbor.removeKey(0); - node.addKey(parentValue); - parent.addKey(neighborValue); - if (rightNeighbor.numberOfChildren() > 0) { - node.addChild(rightNeighbor.removeChild(0)); - } - } else { - Node leftNeighbor = null; - int leftNeighborSize = -minChildrenSize; - if (indexOfLeftNeighbor >= 0) { - leftNeighbor = parent.getChild(indexOfLeftNeighbor); - leftNeighborSize = leftNeighbor.numberOfKeys(); - } - - if (leftNeighbor != null && leftNeighborSize > minKeySize) { - // Try to borrow from left neighbor - T removeValue = leftNeighbor.getKey(leftNeighbor.numberOfKeys() - 1); - int prev = getIndexOfNextValue(parent, removeValue); - T parentValue = parent.removeKey(prev); - T neighborValue = leftNeighbor.removeKey(leftNeighbor.numberOfKeys() - 1); - node.addKey(parentValue); - parent.addKey(neighborValue); - if (leftNeighbor.numberOfChildren() > 0) { - node.addChild(leftNeighbor.removeChild(leftNeighbor.numberOfChildren() - 1)); - } - } else if (rightNeighbor != null && parent.numberOfKeys() > 0) { - // Can't borrow from neighbors, try to combined with right neighbor - T removeValue = rightNeighbor.getKey(0); - int prev = getIndexOfPreviousValue(parent, removeValue); - T parentValue = parent.removeKey(prev); - parent.removeChild(rightNeighbor); - node.addKey(parentValue); - for (int i = 0; i < rightNeighbor.keysSize; i++) { - T v = rightNeighbor.getKey(i); - node.addKey(v); - } - for (int i = 0; i < rightNeighbor.childrenSize; i++) { - Node c = rightNeighbor.getChild(i); - node.addChild(c); - } - - if (parent.parent != null && parent.numberOfKeys() < minKeySize) { - // removing key made parent too small, combined up tree - this.combined(parent); - } else if (parent.numberOfKeys() == 0) { - // parent no longer has keys, make this node the new root - // which decreases the height of the tree - node.parent = null; - root = node; - } - } else if (leftNeighbor != null && parent.numberOfKeys() > 0) { - // Can't borrow from neighbors, try to combined with left neighbor - T removeValue = leftNeighbor.getKey(leftNeighbor.numberOfKeys() - 1); - int prev = getIndexOfNextValue(parent, removeValue); - T parentValue = parent.removeKey(prev); - parent.removeChild(leftNeighbor); - node.addKey(parentValue); - for (int i = 0; i < leftNeighbor.keysSize; i++) { - T v = leftNeighbor.getKey(i); - node.addKey(v); - } - for (int i = 0; i < leftNeighbor.childrenSize; i++) { - Node c = leftNeighbor.getChild(i); - node.addChild(c); - } - - if (parent.parent != null && parent.numberOfKeys() < minKeySize) { - // removing key made parent too small, combined up tree - this.combined(parent); - } else if (parent.numberOfKeys() == 0) { - // parent no longer has keys, make this node the new root - // which decreases the height of the tree - node.parent = null; - root = node; - } - } - } - - return true; - } - - /** - * Get the index of previous key in node. - * - * @param node to find the previous key in. - * @param value to find a previous value for. - * @return index of previous key or -1 if not found. - */ - private int getIndexOfPreviousValue(Node node, T value) { - for (int i = 1; i < node.numberOfKeys(); i++) { - T t = node.getKey(i); - if (t.compareTo(value) >= 0) { - return i - 1; - } - } - return node.numberOfKeys() - 1; - } - - /** - * Get the index of next key in node. - * - * @param node to find the next key in. - * @param value to find a next value for. - * @return index of next key or -1 if not found. - */ - private int getIndexOfNextValue(Node node, T value) { - for (int i = 0; i < node.numberOfKeys(); i++) { - T t = node.getKey(i); - if (t.compareTo(value) >= 0) { - return i; - } - } - return node.numberOfKeys() - 1; - } - - /** - * Validate the node according to the B-Tree invariants. - * - * @param node to validate. - * @return True if valid. - */ - private boolean validateNode(Node node) { - int keySize = node.numberOfKeys(); - if (keySize > 1) { - // Make sure the keys are sorted - for (int i = 1; i < keySize; i++) { - T p = node.getKey(i - 1); - T n = node.getKey(i); - if (p.compareTo(n) > 0) { - return false; - } - } - } - int childrenSize = node.numberOfChildren(); - if (node.parent == null) { - // root - if (keySize > maxKeySize) { - // check max key size. root does not have a min key size - return false; - } else if (childrenSize == 0) { - // if root, no children, and keys are valid - return true; - } else if (childrenSize < minChildrenSize) { - // root should have zero or at least two children - return false; - } else if (childrenSize > maxChildrenSize) { - return false; - } - } else { - // non-root - if (keySize < minKeySize) { - return false; - } else if (keySize > maxKeySize) { - return false; - } else if (childrenSize == 0) { - return true; - } else if (keySize != (childrenSize - 1)) { - // If there are chilren, there should be one more child then - // keys - return false; - } else if (childrenSize < minChildrenSize) { - return false; - } else if (childrenSize > maxChildrenSize) { - return false; - } - } - - Node first = node.getChild(0); - // The first child's last key should be less than the node's first key - if (first.getKey(first.numberOfKeys() - 1).compareTo(node.getKey(0)) > 0) { - return false; - } - - Node last = node.getChild(node.numberOfChildren() - 1); - // The last child's first key should be greater than the node's last key - if (last.getKey(0).compareTo(node.getKey(node.numberOfKeys() - 1)) < 0) { - return false; - } - - // Check that each node's first and last key holds it's invariance - for (int i = 1; i < node.numberOfKeys(); i++) { - T p = node.getKey(i - 1); - T n = node.getKey(i); - Node c = node.getChild(i); - if (p.compareTo(c.getKey(0)) > 0) { - return false; - } - if (n.compareTo(c.getKey(c.numberOfKeys() - 1)) < 0) { - return false; - } - } - - for (int i = 0; i < node.childrenSize; i++) { - Node c = node.getChild(i); - boolean valid = this.validateNode(c); - if (!valid) { - return false; - } - } - - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - return TreePrinter.getString(this); - } - - private static class Node> { - - protected Node parent = null; - - private T[] keys = null; - - private int keysSize = 0; - - private Node[] children = null; - - private int childrenSize = 0; - - private Comparator> comparator = new Comparator>() { - @Override - public int compare(Node arg0, Node arg1) { - return arg0.getKey(0).compareTo(arg1.getKey(0)); - } - }; - - private Node(Node parent, int maxKeySize, int maxChildrenSize) { - this.parent = parent; - this.keys = (T[]) new Comparable[maxKeySize + 1]; - this.keysSize = 0; - this.children = new Node[maxChildrenSize + 1]; - this.childrenSize = 0; - } - - private int indexOf(T value) { - for (int i = 0; i < keysSize; i++) { - if (keys[i].equals(value)) { - return i; - } - } - return -1; - } - - private void addKey(T value) { - keys[keysSize++] = value; - Arrays.sort(keys, 0, keysSize); - } - - private T removeKey(T value) { - T removed = null; - boolean found = false; - if (keysSize == 0) { - return null; - } - for (int i = 0; i < keysSize; i++) { - if (keys[i].equals(value)) { - found = true; - removed = keys[i]; - } else if (found) { - // shift the rest of the keys down - keys[i - 1] = keys[i]; - } - } - if (found) { - keysSize--; - keys[keysSize] = null; - } - return removed; - } - - private T removeKey(int index) { - if (index >= keysSize) { - return null; - } - T value = keys[index]; - for (int i = index + 1; i < keysSize; i++) { - // shift the rest of the keys down - keys[i - 1] = keys[i]; - } - keysSize--; - keys[keysSize] = null; - return value; - } - - private Node getChild(int index) { - if (index >= childrenSize) { - return null; - } - return children[index]; - } - - private int indexOf(Node child) { - for (int i = 0; i < childrenSize; i++) { - if (children[i].equals(child)) { - return i; - } - } - return -1; - } - - private boolean addChild(Node child) { - child.parent = this; - children[childrenSize++] = child; - Arrays.sort(children, 0, childrenSize, comparator); - return true; - } - - private boolean removeChild(Node child) { - boolean found = false; - if (childrenSize == 0) { - return found; - } - for (int i = 0; i < childrenSize; i++) { - if (children[i].equals(child)) { - found = true; - } else if (found) { - // shift the rest of the keys down - children[i - 1] = children[i]; - } - } - if (found) { - childrenSize--; - children[childrenSize] = null; - } - return found; - } - - private Node removeChild(int index) { - if (index >= childrenSize) { - return null; - } - Node value = children[index]; - children[index] = null; - for (int i = index + 1; i < childrenSize; i++) { - // shift the rest of the keys down - children[i - 1] = children[i]; - } - childrenSize--; - children[childrenSize] = null; - return value; - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - - builder.append("keys=["); - for (int i = 0; i < numberOfKeys(); i++) { - T value = getKey(i); - builder.append(value); - if (i < numberOfKeys() - 1) { - builder.append(", "); - } - } - builder.append("]\n"); - - if (parent != null) { - builder.append("parent=["); - for (int i = 0; i < parent.numberOfKeys(); i++) { - T value = parent.getKey(i); - builder.append(value); - if (i < parent.numberOfKeys() - 1) { - builder.append(", "); - } - } - builder.append("]\n"); - } - - if (children != null) { - builder.append("keySize=").append(numberOfKeys()).append(" children=").append(numberOfChildren()) - .append("\n"); - } - - return builder.toString(); - } - - private int numberOfKeys() { - return keysSize; - } - - private T getKey(int index) { - return keys[index]; - } - - private int numberOfChildren() { - return childrenSize; - } - - } - - private static class TreePrinter { - - public static > String getString(BinaryTree tree) { - if (tree.root == null) { - return "Tree has no nodes."; - } - return getString(tree.root, "", true); - } - - private static > String getString(Node node, String prefix, boolean isTail) { - StringBuilder builder = new StringBuilder(); - - builder.append(prefix).append((isTail ? "└── " : "├── ")); - for (int i = 0; i < node.numberOfKeys(); i++) { - T value = node.getKey(i); - builder.append(value); - if (i < node.numberOfKeys() - 1) { - builder.append(", "); - } - } - builder.append("\n"); - - if (node.children != null) { - for (int i = 0; i < node.numberOfChildren() - 1; i++) { - Node obj = node.getChild(i); - builder.append(getString(obj, prefix + (isTail ? " " : "│ "), false)); - } - if (node.numberOfChildren() >= 1) { - Node obj = node.getChild(node.numberOfChildren() - 1); - builder.append(getString(obj, prefix + (isTail ? " " : "│ "), true)); - } - } - - return builder.toString(); - } - - } - - public static class JavaCompatibleBinaryTree> extends java.util.AbstractCollection { - - private BinaryTree tree = null; - - public JavaCompatibleBinaryTree(BinaryTree tree) { - this.tree = tree; - } - - /** - * {@inheritDoc} - */ - @Override - public java.util.Iterator iterator() { - return (new BinaryTreeIterator(this.tree)); - } - - /** - * {@inheritDoc} - */ - @Override - public int size() { - return tree.size(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean contains(Object value) { - return tree.contains((T) value); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean add(T value) { - return tree.add(value); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean remove(Object value) { - return (tree.remove((T) value) != null); - } - - private static class BinaryTreeIterator> implements java.util.Iterator { - - private BinaryTree tree = null; - - private Node lastNode = null; - - private C lastValue = null; - - private int index = 0; - - private Deque> toVisit = new ArrayDeque>(); - - protected BinaryTreeIterator(BinaryTree tree) { - this.tree = tree; - if (tree.root != null && tree.root.keysSize > 0) { - toVisit.add(tree.root); - } - } - - /** - * {@inheritDoc} - */ - @Override - public boolean hasNext() { - boolean toVisitSizeNotZero = toVisit.size() > 0; - boolean lastNodeNotZero = lastNode != null && index < lastNode.keysSize; - if (lastNodeNotZero || toVisitSizeNotZero) { - return true; - } - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public C next() { - if (lastNode != null && (index < lastNode.keysSize)) { - lastValue = lastNode.getKey(index++); - return lastValue; - } - while (toVisit.size() > 0) { - // Go thru the current nodes - Node n = toVisit.pop(); - - // Add non-null children - for (int i = 0; i < n.childrenSize; i++) { - toVisit.add(n.getChild(i)); - } - - // Update last node (used in remove method) - index = 0; - lastNode = n; - lastValue = lastNode.getKey(index++); - return lastValue; - } - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public void remove() { - if (lastNode != null && lastValue != null) { - // On remove, reset the iterator (very inefficient, I know) - tree.remove(lastValue, lastNode); - - lastNode = null; - lastValue = null; - index = 0; - toVisit.clear(); - if (tree.root != null && tree.root.keysSize > 0) { - toVisit.add(tree.root); - } - } - } - - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/NAryTree.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/NAryTree.java new file mode 100644 index 0000000..e442847 --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/NAryTree.java @@ -0,0 +1,32 @@ +package io.github.dunwu.algorithm.tree; + +import java.util.LinkedList; +import java.util.List; + +/** + * N 叉树 + * + * @author Zhang Peng + * @date 2025-10-27 + */ +public class NAryTree> { + + public int val; + public List children; + + public NAryTree() { + val = -1; + children = new LinkedList<>(); + } + + public NAryTree(int val) { + this.val = val; + this.children = new LinkedList<>(); + } + + public NAryTree(int val, List children) { + this.val = val; + this.children = children; + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeNode.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeNode.java index d6e1f92..632d59e 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeNode.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeNode.java @@ -184,10 +184,4 @@ public static List toValueList(TreeNode root) { return list.subList(0, last + 1); } - static enum Order { - PreOrder, - InOrder, - PostOrder - } - } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" new file mode 100644 index 0000000..d821891 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" @@ -0,0 +1,45 @@ +package io.github.dunwu.algorithm.tree.bstree; + +import org.junit.jupiter.api.Assertions; + +/** + * 96. 不同的二叉搜索树 + * + * @author Zhang Peng + * @date 2025-10-22 + */ +public class 不同的二叉搜索树 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + Assertions.assertEquals(5, s.numTrees(3)); + Assertions.assertEquals(1, s.numTrees(1)); + } + + static class Solution { + + public int numTrees(int n) { + int[][] memo = new int[n + 1][n + 1]; + return recursion(1, n, memo); + } + + public int recursion(int begin, int end, int[][] memo) { + if (begin > end) { return 1; } + + if (memo[begin][end] != 0) { return memo[begin][end]; } + + int res = 0; + for (int i = begin; i <= end; i++) { + int left = recursion(begin, i - 1, memo); + int right = recursion(i + 1, end, memo); + res += left * right; + } + memo[begin][end] = res; + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" new file mode 100644 index 0000000..7fb7546 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" @@ -0,0 +1,80 @@ +package io.github.dunwu.algorithm.tree.bstree; + +import cn.hutool.json.JSONUtil; +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * 95. 不同的二叉搜索树 II + * + * @author Zhang Peng + * @date 2025-10-22 + */ +public class 不同的二叉搜索树2 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + List output1 = s.generateTrees(3); + LinkedList> expectList1 = new LinkedList<>(); + expectList1.add(new LinkedList<>(Arrays.asList(1, null, 2, null, 3))); + expectList1.add(new LinkedList<>(Arrays.asList(1, null, 3, 2))); + expectList1.add(new LinkedList<>(Arrays.asList(2, 1, 3))); + expectList1.add(new LinkedList<>(Arrays.asList(3, 1, null, null, 2))); + expectList1.add(new LinkedList<>(Arrays.asList(3, 2, null, 1))); + Assertions.assertEquals(expectList1.size(), output1.size()); + output1.forEach(tree -> { + List expect = expectList1.poll(); + Assertions.assertArrayEquals(expect.toArray(), TreeNode.toValueList(tree).toArray()); + }); + + List output2 = s.generateTrees(1); + LinkedList> expectList2 = new LinkedList<>(); + expectList2.add(new LinkedList<>(Collections.singletonList(1))); + Assertions.assertEquals(expectList2.size(), output2.size()); + output2.forEach(tree -> { + List expect = expectList2.poll(); + Assertions.assertArrayEquals(expect.toArray(), TreeNode.toValueList(tree).toArray()); + }); + } + + static class Solution { + + public List generateTrees(int n) { + if (n == 0) return new LinkedList<>(); + return recursion(1, n); + } + + public List recursion(int begin, int end) { + + List res = new LinkedList<>(); + if (begin > end) { + res.add(null); + return res; + } + + for (int i = begin; i <= end; i++) { + List leftTrees = recursion(begin, i - 1); + List rightTrees = recursion(i + 1, end); + for (TreeNode left : leftTrees) { + for (TreeNode right : rightTrees) { + TreeNode root = new TreeNode(i); + root.left = left; + root.right = right; + res.add(root); + } + } + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" index 5854957..5ce506e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" @@ -19,27 +19,24 @@ public static void main(String[] args) { static class Solution { - int res = 0; - int rank = 0; + private int rank = 1; + private int res = 0; public int kthSmallest(TreeNode root, int k) { - if (root == null) { return -1; } - rank = 0; + rank = 1; res = 0; - traverse(root, k); + dfs(root, k); return res; } - void traverse(TreeNode root, int k) { + void dfs(TreeNode root, int k) { if (root == null) { return; } - traverse(root.left, k); - rank++; - if (rank == k) { - System.out.printf("val: %s, rank: %d\n", root.val, rank); + dfs(root.left, k); + if (rank++ == k) { res = root.val; return; } - traverse(root.right, k); + dfs(root.right, k); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" index cc8445a..795a849 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" @@ -1,81 +1,44 @@ package io.github.dunwu.algorithm.tree.bstree; import io.github.dunwu.algorithm.tree.TreeNode; -import io.github.dunwu.algorithm.tree.btree.二叉树的最近公共祖先; import org.junit.jupiter.api.Assertions; /** - * 235. 二叉搜索树的最近公共祖先 算法实现 + * 235. 二叉搜索树的最近公共祖先 * - * @see 二叉树的最近公共祖先 可以使用二叉树的最近公共祖先,但没有利用二叉搜索树特性,性能略差 - * @see 235. 二叉搜索树的最近公共祖先 + * @author Zhang Peng + * @date 2025-10-22 */ public class 二叉搜索树的最近公共祖先 { public static void main(String[] args) { - TreeNode root = TreeNode.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); - TreeNode p = TreeNode.find(root, 2); - TreeNode q = TreeNode.find(root, 8); - // TreeNode treeNode = lowestCommonAncestor(root, p, q); - TreeNode treeNode = lowestCommonAncestor2(root, p, q); - Assertions.assertNotNull(treeNode); - Assertions.assertEquals(6, treeNode.val); - System.out.println("公共祖先节点 = " + treeNode.val); - TreeNode root2 = TreeNode.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); - TreeNode p2 = TreeNode.find(root2, 2); - TreeNode q2 = TreeNode.find(root2, 4); - // TreeNode treeNode2 = lowestCommonAncestor(root2, p2, q2); - TreeNode treeNode2 = lowestCommonAncestor2(root2, p2, q2); - Assertions.assertNotNull(treeNode2); - Assertions.assertEquals(2, treeNode2.val); - System.out.println("公共祖先节点 = " + treeNode2.val); - } + Solution s = new Solution(); - /** - * 递归方式求解 - *

- * 时间复杂度:O(N) 线性级 - *

- * 空间复杂度:O(2) 常数级 - */ - public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { - // 如果当前节点为空,直接返回 - // 或当前节点就是 p 或 q 其中一个,显然就是要找的最近公共祖先,直接返回 - if (root == null || root == p || root == q) return root; + TreeNode root = TreeNode.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); - if (root.val > p.val && root.val > q.val) { // 如果当前节点值同时大于 p、q 的值,说明 p、q 肯定都在左子树 - return lowestCommonAncestor(root.left, p, q); - } else if (root.val < p.val && root.val < q.val) { // 如果当前节点值同时小于 p、q 的值,说明 p、q 肯定都在右子树 - return lowestCommonAncestor(root.right, p, q); - } else { - return root; - } + TreeNode node1 = s.lowestCommonAncestor(root, TreeNode.find(root, 2), TreeNode.find(root, 8)); + Assertions.assertNotNull(node1); + Assertions.assertEquals(6, node1.val); + + TreeNode node2 = s.lowestCommonAncestor(root, TreeNode.find(root, 2), TreeNode.find(root, 4)); + Assertions.assertNotNull(node2); + Assertions.assertEquals(2, node2.val); } - /** - * 非递归方式求解 - *

- * 时间复杂度:O(N) 线性级 - *

- * 空间复杂度:O(2) 常数级 - */ - public static TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) { - // 如果当前节点为空,直接返回 - // 或当前节点就是 p 或 q 其中一个,显然就是要找的最近公共祖先,直接返回 - if (root == null || root == p || root == q) return root; + static class Solution { + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null) { return null; } + if (root == p || root == q) { return root; } - TreeNode curr = root; - while (curr != null) { - if (curr.val > p.val && curr.val > q.val) { // 如果当前节点值同时大于 p、q 的值,说明 p、q 肯定都在左子树 - curr = curr.left; - } else if (curr.val < p.val && curr.val < q.val) { // 如果当前节点值同时小于 p、q 的值,说明 p、q 肯定都在右子树 - curr = curr.right; - } else { - return curr; - } + TreeNode left = lowestCommonAncestor(root.left, p, q); + TreeNode right = lowestCommonAncestor(root.right, p, q); + if (left != null && right != null) { return root; } + if (left == null && right == null) { return null; } + return left == null ? right : left; } - return curr; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" index 1f629d5..6929f65 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" @@ -1,89 +1,52 @@ package io.github.dunwu.algorithm.tree.bstree; import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** - * 二叉搜索树结点最小距离 算法实现 + * 二叉搜索树结点最小距离 * - *

- * 给定一个二叉搜索树的根结点 root, 返回树中任意两节点的差的最小值。
- *
- * 示例:
- *
- * 输入: root = [4,2,6,1,3,null,null]
- * 输出: 1
- * 解释:
- * 注意,root是树结点对象(TreeNode object),而不是数组。
- *
- * 给定的树 [4,2,6,1,3,null,null] 可表示为下图:
- *
- *           4
- *         /   \
- *       2      6
- *      / \
- *     1   3
- *
- * 最小的差值是 1, 它是节点1和节点2的差值, 也是节点3和节点2的差值。
- * 
- * - * @see 二叉搜索树结点最小距离 + * @author Zhang Peng + * @date 2020-06-18 */ public class 二叉搜索树节点最小距离 { public static void main(String[] args) { - TreeNode tree = TreeNode.buildTree(4, 2, 6, 1, 3, null, null); - System.out.println("result = " + minDiffInBST2(tree)); - } - - // ------------------------------------------------------------------------------------------------- - - // 方法一:排序【通过】 - // 思路和算法:将树中所有节点的值写入数组,之后将数组排序。依次计算相邻数之间的差值,找出其中最小的值。 - public static int minDiffInBST(TreeNode root) { - List list = new ArrayList(); - dfs(root, list); - Collections.sort(list); + Solution s = new Solution(); - int min = Integer.MAX_VALUE; - for (int i = 0; i < list.size() - 1; ++i) { - min = Math.min(min, list.get(i + 1) - list.get(i)); - } - - return min; - } - - public static void dfs(TreeNode node, List list) { - if (node == null) { return; } - list.add(node.val); - dfs(node.left, list); - dfs(node.right, list); + TreeNode tree = TreeNode.buildTree(4, 2, 6, 1, 3); + Assertions.assertEquals(1, s.minDiffInBST(tree)); } - // ------------------------------------------------------------------------------------------------- + static class Solution { - // 方法二:中序遍历【通过】 - // 思路和算法:在二叉搜索树中,中序遍历会将树中节点按数值大小顺序输出。只需要遍历计算相邻数的差值,取其中最小的就可以了。 + int pre = -1; + int min = Integer.MAX_VALUE; - public static Integer prev = null; - public static Integer min = Integer.MAX_VALUE; + public int minDiffInBST(TreeNode root) { + pre = -1; + min = Integer.MAX_VALUE; + dfs(root); + return min; + } - public static int minDiffInBST2(TreeNode root) { - if (root == null) return 0; - dfs2(root); - return min; - } + public void dfs(TreeNode root) { + if (root == null) return; + dfs(root.left); + if (pre == -1) { + pre = root.val; + } else { + min = Math.min(min, Math.abs(pre - root.val)); + pre = root.val; + } + dfs(root.right); + } - public static void dfs2(TreeNode node) { - if (node == null) { return; } - dfs2(node.left); - if (prev != null) min = Math.min(min, node.val - prev); - prev = node.val; - dfs2(node.right); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" index 294af07..536a296 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" @@ -12,58 +12,47 @@ public class 删除二叉搜索树中的节点 { public static void main(String[] args) { - TreeNode input1 = TreeNode.buildTree(5, 3, 6, 2, 4, null, 7); - TreeNode output1 = deleteNode(input1, 3); - Assertions.assertArrayEquals(new Integer[] { 5, 4, 6, 2, null, null, 7 }, - TreeNode.toValueList(output1).toArray()); - TreeNode input2 = TreeNode.buildTree(5, 3, 6, 2, 4, null, 7); - TreeNode output2 = deleteNode(input2, 0); - Assertions.assertArrayEquals(new Integer[] { 5, 3, 6, 2, 4, null, 7 }, - TreeNode.toValueList(output2).toArray()); + Solution s = new Solution(); - TreeNode input3 = TreeNode.buildTree(); - TreeNode output3 = deleteNode(input3, 0); - Assertions.assertNull(output3); + TreeNode output1 = s.deleteNode(TreeNode.buildTree(5, 3, 6, 2, 4, null, 7), 3); + Assertions.assertEquals(TreeNode.buildTree(5, 4, 6, 2, null, null, 7), output1); + + TreeNode output2 = s.deleteNode(TreeNode.buildTree(5, 3, 6, 2, 4, null, 7), 0); + Assertions.assertEquals(TreeNode.buildTree(5, 3, 6, 2, 4, null, 7), output2); + + Assertions.assertNull(s.deleteNode(TreeNode.buildTree(), 0)); } - public static TreeNode deleteNode(TreeNode root, int key) { - if (root == null) { return null; } - if (key == root.val) { - // 找到 key,进行处理 + static class Solution { + + public TreeNode deleteNode(TreeNode root, int key) { + if (root == null) { return null; } + + if (root.val < key) { + root.right = deleteNode(root.right, key); + } else if (root.val > key) { + root.left = deleteNode(root.left, key); + } else { + if (root.left == null) { return root.right; } + if (root.right == null) { return root.left; } + TreeNode minRightNode = getMin(root.right); + root.right = deleteNode(root.right, minRightNode.val); + minRightNode.left = root.left; + minRightNode.right = root.right; + root = minRightNode; + } + return root; + } - if (root.left == null && root.right == null) { - // 情况一、无孩子节点:直接删除 - return null; - } else if (root.left != null && root.right == null) { - // 情况二、有一个孩子节点:用孩子节点替换 - root = root.left; - } else if (root.left == null && root.right != null) { - // 情况二、有一个孩子节点:用孩子节点替换 - root = root.right; - } else if (root.left != null && root.right != null) { - // 情况三、有两个孩子节点: - // 从左子树中找最大的节点替换根节点 - // 或从右子树中找最小的节点替换根节点 - TreeNode minRight = getMin(root.right); - minRight.right = deleteNode(root.right, minRight.val); - minRight.left = root.left; - root = minRight; + public TreeNode getMin(TreeNode root) { + if (root == null) { return null; } + if (root.left == null) { + return root; } - } else if (key < root.val) { - // 在左子树查找、处理 - root.left = deleteNode(root.left, key); - } else if (key > root.val) { - // 在右子树查找、处理 - root.right = deleteNode(root.right, key); + return getMin(root.left); } - return root; - } - static TreeNode getMin(TreeNode root) { - if (root == null) { return null; } - if (root.left == null) { return root; } - return getMin(root.left); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\260\206\346\234\211\345\272\217\346\225\260\347\273\204\350\275\254\346\215\242\344\270\272\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\260\206\346\234\211\345\272\217\346\225\260\347\273\204\350\275\254\346\215\242\344\270\272\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" index e40f46e..13f1b29 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\260\206\346\234\211\345\272\217\346\225\260\347\273\204\350\275\254\346\215\242\344\270\272\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\260\206\346\234\211\345\272\217\346\225\260\347\273\204\350\275\254\346\215\242\344\270\272\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" @@ -1,32 +1,50 @@ package io.github.dunwu.algorithm.tree.bstree; import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; /** + * 二叉搜索树结点最小距离 + * * @author Zhang Peng * @since 2020-07-07 */ public class 将有序数组转换为二叉搜索树 { public static void main(String[] args) { - System.out.println("result = " + sortedArrayToBST(new int[] { -10, -3, 0, 5, 9 })); + Solution s = new Solution(); + TreeNode output1 = s.sortedArrayToBST(new int[] { -10, -3, 0, 5, 9 }); + Assertions.assertArrayEquals(new Integer[] { 0, -3, 9, -10, null, 5 }, TreeNode.toValueList(output1).toArray()); } - public static TreeNode sortedArrayToBST(int[] nums) { - if (nums == null || nums.length == 0) return null; - return backtrack(nums, 0, nums.length - 1); - } + static class Solution { + + public TreeNode sortedArrayToBST(int[] nums) { + if (nums == null || nums.length == 0) { return null; } + TreeNode root = new TreeNode(nums[0]); + for (int i = 1; i < nums.length; i++) { + insert(root, nums[i]); + } + return root; + } - public static TreeNode backtrack(int[] nums, int left, int right) { - if (left > right) return null; - // always choose left middle node as a root - int p = (left + right) / 2; + public void insert(TreeNode root, int val) { + if (root == null) { return; } + if (val < root.val) { + if (root.left == null) { + root.left = new TreeNode(val); + } else { + insert(root.left, val); + } + } else if (val > root.val) { + if (root.right == null) { + root.right = new TreeNode(val); + } else { + insert(root.right, val); + } + } + } - // inorder traversal: left -> node -> right - TreeNode root = new TreeNode(nums[p]); - root.left = backtrack(nums, left, p - 1); - root.right = backtrack(nums, p + 1, right); - return root; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" index adb4acb..28fe59b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" @@ -13,25 +13,30 @@ public class 验证二叉搜索树 { public static void main(String[] args) { - TreeNode root = TreeNode.buildTree(2, 1, 3); - TreeNode root2 = TreeNode.buildTree(5, 1, 4, null, null, 3, 6); - TreeNode root3 = TreeNode.buildTree(1, 1); - - Assertions.assertTrue(isValidBST(root)); - Assertions.assertFalse(isValidBST(root2)); - Assertions.assertFalse(isValidBST(root3)); + Solution s = new Solution(); + Assertions.assertTrue(s.isValidBST(TreeNode.buildTree(2, 1, 3))); + Assertions.assertFalse(s.isValidBST(TreeNode.buildTree(5, 1, 4, null, null, 3, 6))); + Assertions.assertFalse(s.isValidBST(TreeNode.buildTree(2, 2, 2))); + Assertions.assertFalse(s.isValidBST(TreeNode.buildTree(5, 4, 6, null, null, 3, 7))); } - public static boolean isValidBST(TreeNode root) { - return isValidBST(root, null, null); - } + static class Solution { + + public boolean isValidBST(TreeNode root) { + return isValidBST(root, null, null); + } + + // 限定以 root 为根的子树节点必须满足 max.val > root.val > min.val + boolean isValidBST(TreeNode root, TreeNode min, TreeNode max) { + if (root == null) { return true; } + // 若 root.val 不符合 max 和 min 的限制,说明不是合法 BST + if (min != null && root.val <= min.val) { return false; } + if (max != null && root.val >= max.val) { return false; } + // 限定左子树的最大值是 root.val,右子树的最小值是 root.val + return isValidBST(root.left, min, root) + && isValidBST(root.right, root, max); + } - static boolean isValidBST(TreeNode root, Integer min, Integer max) { - if (root == null) { return true; } - // BST 树中,任意节点的值应该大于所有左子树节点,小于所有右子树节点 - if (min != null && root.val <= min) { return false; } - if (max != null && root.val >= max) { return false; } - return isValidBST(root.left, min, root.val) && isValidBST(root.right, root.val, max); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 0000000..4caf155 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,82 @@ +package io.github.dunwu.algorithm.tree.btree.bfs; + +import java.util.LinkedList; +import java.util.List; + +/** + * 429. N 叉树的层序遍历 + * + * @author Zhang Peng + * @date 2025-10-27 + */ +public class N叉树的层序遍历 { + + public static void main(String[] args) { + Solution s = new Solution(); + Node node3 = new Node(3); + node3.children.add(new Node(5)); + node3.children.add(new Node(6)); + Node root = new Node(1); + root.children.add(node3); + root.children.add(new Node(2)); + root.children.add(new Node(4)); + List> res = s.levelOrder(root); + System.out.printf("res: %s\n", res); + } + + static class Solution { + + public List> levelOrder(Node root) { + if (root == null) { return new LinkedList<>(); } + + int depth = 1; + LinkedList> res = new LinkedList<>(); + LinkedList queue = new LinkedList<>(); + queue.addLast(root); + while (!queue.isEmpty()) { + int size = queue.size(); + List list = new LinkedList<>(); + for (int i = 0; i < size; i++) { + Node node = queue.removeFirst(); + if (node == null) { + continue; + } + list.add(node.val); + if (node.children != null && node.children.size() > 0) { + for (Node child : node.children) { + queue.addLast(child); + } + } + } + System.out.printf("[depth: %d]nodes: %s\n", depth, list); + res.add(list); + depth++; + } + return res; + } + + } + + static class Node { + + public int val; + public List children; + + public Node() { + val = -1; + children = new LinkedList<>(); + } + + public Node(int val) { + this.val = val; + this.children = new LinkedList<>(); + } + + public Node(int val, List children) { + this.val = val; + this.children = children; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" new file mode 100644 index 0000000..37b294f --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" @@ -0,0 +1,72 @@ +package io.github.dunwu.algorithm.tree.btree.bfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * 1302. 层数最深叶子节点的和 + * + * @author Zhang Peng + * @date 2025-08-18 + */ +public class 完全二叉树插入器 { + + public static void main(String[] args) { + TreeNode root = TreeNode.buildTree(1, 2); + Solution cBTInserter = new Solution(root); + cBTInserter.insert(3); // 返回 1 + cBTInserter.insert(4); // 返回 2 + cBTInserter.get_root(); // 返回 [1, 2, 3, 4] + } + + static class Solution { + + private TreeNode root = null; + private Queue q = null; + + public Solution(TreeNode root) { + this.root = root; + this.q = new LinkedList<>(); + // 进行普通的 BFS,目的是找到底部可插入的节点 + Queue temp = new LinkedList<>(); + temp.offer(root); + while (!temp.isEmpty()) { + TreeNode cur = temp.poll(); + if (cur.left != null) { + temp.offer(cur.left); + } + if (cur.right != null) { + temp.offer(cur.right); + } + if (cur.right == null || cur.left == null) { + // 找到完全二叉树底部可以进行插入的节点 + q.offer(cur); + } + } + } + + public int insert(int val) { + TreeNode node = new TreeNode(val); + TreeNode cur = q.peek(); + // 进行插入 + if (cur.left == null) { + cur.left = node; + } else if (cur.right == null) { + cur.right = node; + q.poll(); + } + // 新节点的左右节点也是可以插入的 + q.offer(node); + return cur.val; + } + + public TreeNode get_root() { + return root; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\225.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\225.java" new file mode 100644 index 0000000..e09b2d4 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\225.java" @@ -0,0 +1,44 @@ +package io.github.dunwu.algorithm.tree.btree.bfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * LCR 149. 彩灯装饰记录 I + * + * @author Zhang Peng + * @since 2025-10-28 + */ +public class 彩灯装饰记录 { + + public static void main(String[] args) { + Solution s = new Solution(); + TreeNode root = TreeNode.buildTree(8, 17, 21, 18, null, null, 6); + Assertions.assertArrayEquals(new int[] { 8, 17, 21, 18, 6 }, s.decorateRecord(root)); + } + + static class Solution { + + public int[] decorateRecord(TreeNode root) { + ArrayList list = new ArrayList<>(); + LinkedList queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + TreeNode node = queue.poll(); + if (node == null) { continue; } + list.add(node.val); + if (node.left != null) { queue.offer(node.left); } + if (node.right != null) { queue.offer(node.right); } + } + return list.stream().mapToInt(Integer::intValue).toArray(); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\2252.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\2252.java" new file mode 100644 index 0000000..26ba27f --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\2252.java" @@ -0,0 +1,57 @@ +package io.github.dunwu.algorithm.tree.btree.bfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * LCR 150. 彩灯装饰记录 II + * + * @author Zhang Peng + * @since 2025-10-28 + */ +public class 彩灯装饰记录2 { + + public static void main(String[] args) { + Solution s = new Solution(); + TreeNode root = TreeNode.buildTree(8, 17, 21, 18, null, null, 6); + List> expectList = new ArrayList<>(); + expectList.add(Arrays.asList(8)); + expectList.add(Arrays.asList(17, 21)); + expectList.add(Arrays.asList(18, 6)); + List> output = s.decorateRecord(root); + for (int i = 0; i < expectList.size(); i++) { + Assertions.assertArrayEquals(expectList.get(i).toArray(), output.get(i).toArray()); + } + } + + static class Solution { + + public List> decorateRecord(TreeNode root) { + List> res = new ArrayList<>(); + LinkedList queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + List list = new ArrayList<>(); + int size = queue.size(); + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + if (node == null) { continue; } + list.add(node.val); + if (node.left != null) { queue.offer(node.left); } + if (node.right != null) { queue.offer(node.right); } + } + if (list.size() != 0) { + res.add(list); + } + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\2253.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\2253.java" new file mode 100644 index 0000000..7985e9f --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\2253.java" @@ -0,0 +1,63 @@ +package io.github.dunwu.algorithm.tree.btree.bfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * LCR 151. 彩灯装饰记录 III + * + * @author Zhang Peng + * @since 2025-10-28 + */ +public class 彩灯装饰记录3 { + + public static void main(String[] args) { + Solution s = new Solution(); + TreeNode root = TreeNode.buildTree(8, 17, 21, 18, null, null, 6); + List> expectList = new ArrayList<>(); + expectList.add(Arrays.asList(8)); + expectList.add(Arrays.asList(21, 17)); + expectList.add(Arrays.asList(18, 6)); + List> output = s.decorateRecord(root); + for (int i = 0; i < expectList.size(); i++) { + Assertions.assertArrayEquals(expectList.get(i).toArray(), output.get(i).toArray()); + } + } + + static class Solution { + + public List> decorateRecord(TreeNode root) { + List> res = new LinkedList<>(); + LinkedList queue = new LinkedList<>(); + queue.offer(root); + boolean reverse = false; + while (!queue.isEmpty()) { + LinkedList list = new LinkedList<>(); + int size = queue.size(); + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + if (node == null) { continue; } + if (reverse) { + list.addFirst(node.val); + } else { + list.addLast(node.val); + } + if (node.left != null) { queue.offer(node.left); } + if (node.right != null) { queue.offer(node.right); } + } + if (list.size() != 0) { + res.add(list); + } + reverse = !reverse; + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\345\211\252\346\236\235.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\345\211\252\346\236\235.java" new file mode 100644 index 0000000..649b851 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\345\211\252\346\236\235.java" @@ -0,0 +1,38 @@ +package io.github.dunwu.algorithm.tree.btree.dfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +/** + * 814. 二叉树剪枝 + * + * @author Zhang Peng + * @since 2025-10-30 + */ +public class 二叉树剪枝 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(TreeNode.buildTree(1, null, 0, null, 1), + s.pruneTree(TreeNode.buildTree(1, null, 0, 0, 1))); + Assertions.assertEquals(TreeNode.buildTree(1, null, 1, null, 1), + s.pruneTree(TreeNode.buildTree(1, 0, 1, 0, 0, 0, 1))); + Assertions.assertEquals(TreeNode.buildTree(1, 1, 0, 1, 1, null, 1), + s.pruneTree(TreeNode.buildTree(1, 1, 0, 1, 1, 0, 1, 0))); + } + + static class Solution { + + public TreeNode pruneTree(TreeNode root) { + if (root == null) { return null; } + root.left = pruneTree(root.left); + root.right = pruneTree(root.right); + if (root.val == 0 && root.left == null && root.right == null) { + return null; + } + return root; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 0000000..0572005 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,53 @@ +package io.github.dunwu.algorithm.tree.btree.dfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.List; + +/** + * 94. 二叉树的中序遍历 + * + * @author Zhang Peng + * @since 2020-07-06 + */ +public class 二叉树的中序遍历 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new Integer[] { 1, 3, 2 }, + s.inorderTraversal(TreeNode.buildTree(1, null, 2, 3)).toArray()); + Assertions.assertArrayEquals(new Integer[] {}, + s.inorderTraversal(TreeNode.buildTree()).toArray()); + Assertions.assertArrayEquals(new Integer[] { 1 }, + s.inorderTraversal(TreeNode.buildTree(1)).toArray()); + } + + private static class Solution { + + List values; + + public List inorderTraversal(TreeNode root) { + values = new ArrayList<>(); + traverse(root); + return values; + } + + public void traverse(TreeNode root) { + if (root == null) return; + // 【前序】 + // System.out.printf("[node -> left]从节点 %s 进入节点 %s\n", root, root.left); + traverse(root.left); + // 【中序】 + // System.out.printf("\t[left -> node]从节点 %s 回到节点 %s\n", root.left, root); + // System.out.printf("\t[node -> right]从节点 %s 进入节点 %s\n", root, root.right); + values.add(root.val); + traverse(root.right); + // 【后序】 + // System.out.printf("\t[right -> node]从节点 %s 回到节点 %s\n", root.right, root); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 0000000..ba15417 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,79 @@ +package io.github.dunwu.algorithm.tree.btree.dfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.List; + +/** + * 144. 二叉树的前序遍历 + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 二叉树的前序遍历 { + + public static void main(String[] args) { + + Solution s1 = new Solution(); + Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, + s1.preorderTraversal(TreeNode.buildTree(1, null, 2, 3)).toArray()); + Assertions.assertArrayEquals(new Integer[] {}, + s1.preorderTraversal(TreeNode.buildTree()).toArray()); + Assertions.assertArrayEquals(new Integer[] { 1 }, + s1.preorderTraversal(TreeNode.buildTree(1)).toArray(new Integer[0])); + + Solution2 s2 = new Solution2(); + Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, + s2.preorderTraversal(TreeNode.buildTree(1, null, 2, 3)).toArray()); + Assertions.assertArrayEquals(new Integer[] {}, + s2.preorderTraversal(TreeNode.buildTree()).toArray()); + Assertions.assertArrayEquals(new Integer[] { 1 }, + s2.preorderTraversal(TreeNode.buildTree(1)).toArray(new Integer[0])); + } + + /** + * 【分解】思路解法 + */ + private static class Solution { + + public List preorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + if (root == null) { + return res; + } + // 前序遍历的结果,root.val 在第一个 + res.add(root.val); + // 利用函数定义,后面接着左子树的前序遍历结果 + res.addAll(preorderTraversal(root.left)); + // 利用函数定义,最后接着右子树的前序遍历结果 + res.addAll(preorderTraversal(root.right)); + return res; + } + + } + + /** + * 【遍历】思路解法 + */ + private static class Solution2 { + + List res; + + public List preorderTraversal(TreeNode root) { + res = new ArrayList<>(); + traverse(root); + return res; + } + + public void traverse(TreeNode root) { + if (root == null) { return; } + res.add(root.val); + traverse(root.left); + traverse(root.right); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 0000000..cdbcba2 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,55 @@ +package io.github.dunwu.algorithm.tree.btree.dfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.List; + +/** + * 145. 二叉树的后序遍历 + * + * @author Zhang Peng + * @since 2020-07-06 + */ +public class 二叉树的后序遍历 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new Integer[] { 3, 2, 1 }, + s.postorderTraversal(TreeNode.buildTree(1, null, 2, 3)).toArray()); + Assertions.assertArrayEquals(new Integer[] {}, + s.postorderTraversal(TreeNode.buildTree()).toArray()); + Assertions.assertArrayEquals(new Integer[] { 1 }, + s.postorderTraversal(TreeNode.buildTree(1)).toArray()); + Assertions.assertArrayEquals(new Integer[] { 4, 6, 7, 5, 2, 9, 8, 3, 1 }, + s.postorderTraversal(TreeNode.buildTree(1, 2, 3, 4, 5, null, 8, null, null, 6, 7, 9)).toArray()); + } + + private static class Solution { + + List values = null; + + public List postorderTraversal(TreeNode root) { + values = new ArrayList<>(); + traverse(root); + return values; + } + + public void traverse(TreeNode root) { + if (root == null) return; + // 【前序】 + System.out.printf("[node -> left]从节点 %s 进入节点 %s\n", root, root.left); + traverse(root.left); + // 【中序】 + System.out.printf("\t[left -> node]从节点 %s 回到节点 %s\n", root.left, root); + System.out.printf("\t[node -> right]从节点 %s 进入节点 %s\n", root, root.right); + traverse(root.right); + // 【后序】 + System.out.printf("\t[right -> node]从节点 %s 回到节点 %s\n", root.right, root); + values.add(root.val); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\235\241\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\235\241\345\272\246.java" new file mode 100644 index 0000000..2d5500b --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\235\241\345\272\246.java" @@ -0,0 +1,41 @@ +package io.github.dunwu.algorithm.tree.btree.dfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +/** + * 110. 平衡二叉树 + * + * @author Zhang Peng + * @since 2025-10-30 + */ +public class 二叉树的坡度 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(1, s.findTilt(TreeNode.buildTree(1, 2, 3))); + Assertions.assertEquals(15, s.findTilt(TreeNode.buildTree(4, 2, 9, 3, 5, null, 7))); + Assertions.assertEquals(9, s.findTilt(TreeNode.buildTree(21, 7, 14, 1, 1, 2, 2, 3, 3))); + } + + static class Solution { + + int res = 0; + + public int findTilt(TreeNode root) { + res = 0; + sum(root); + return res; + } + + public int sum(TreeNode root) { + if (root == null) { return 0; } + int left = sum(root.left); + int right = sum(root.right); + res += Math.abs(left - right); + return left + right + root.val; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" new file mode 100644 index 0000000..f4a79ee --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" @@ -0,0 +1,61 @@ +package io.github.dunwu.algorithm.tree.btree.dfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 508. 出现次数最多的子树元素和 + * + * @author Zhang Peng + * @since 2020-07-06 + */ +public class 出现次数最多的子树元素和 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new int[] { 2, -3, 4 }, s.findFrequentTreeSum(TreeNode.buildTree(5, 2, -3))); + } + + static class Solution { + + private HashMap map = new HashMap<>(); + + public int[] findFrequentTreeSum(TreeNode root) { + + sum(root); + + int max = Integer.MIN_VALUE; + for (int cnt : map.values()) { + max = Math.max(max, cnt); + } + + List list = new ArrayList<>(); + for (Integer key : map.keySet()) { + if (map.get(key) == max) { + list.add(key); + } + } + int[] res = new int[list.size()]; + for (int i = 0; i < list.size(); i++) { + res[i] = list.get(i); + } + return res; + } + + public int sum(TreeNode root) { + if (root == null) { return 0; } + int leftSum = sum(root.left); + int rightSum = sum(root.right); + int sum = leftSum + rightSum + root.val; + map.put(sum, map.getOrDefault(sum, 0) + 1); + return sum; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\210\240\351\231\244\347\273\231\345\256\232\345\200\274\347\232\204\345\217\266\345\255\220\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\210\240\351\231\244\347\273\231\345\256\232\345\200\274\347\232\204\345\217\266\345\255\220\350\212\202\347\202\271.java" new file mode 100644 index 0000000..f273bae --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\210\240\351\231\244\347\273\231\345\256\232\345\200\274\347\232\204\345\217\266\345\255\220\350\212\202\347\202\271.java" @@ -0,0 +1,38 @@ +package io.github.dunwu.algorithm.tree.btree.dfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +/** + * 814. 二叉树剪枝 + * + * @author Zhang Peng + * @since 2025-10-30 + */ +public class 删除给定值的叶子节点 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(TreeNode.buildTree(1, null, 3, null, 4), + s.removeLeafNodes(TreeNode.buildTree(1, 2, 3, 2, null, 2, 4), 2)); + Assertions.assertEquals(TreeNode.buildTree(1, 3, null, null, 2), + s.removeLeafNodes(TreeNode.buildTree(1, 3, 3, 3, 2), 3)); + Assertions.assertEquals(TreeNode.buildTree(1), + s.removeLeafNodes(TreeNode.buildTree(1, 2, null, 2, null, 2), 2)); + } + + static class Solution { + + public TreeNode removeLeafNodes(TreeNode root, int target) { + if (root == null) { return null; } + root.left = removeLeafNodes(root.left, target); + root.right = removeLeafNodes(root.right, target); + if (root.left == null && root.right == null && root.val == target) { + return null; + } + return root; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" new file mode 100644 index 0000000..e1463ce --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" @@ -0,0 +1,55 @@ +package io.github.dunwu.algorithm.tree.btree.dfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * LCR 149. 彩灯装饰记录 I + * + * @author Zhang Peng + * @since 2025-10-28 + */ +public class 叶子相似的树 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.leafSimilar(TreeNode.buildTree(3, 5, 1, 6, 2, 9, 8, null, null, 7, 4), + TreeNode.buildTree(3, 5, 1, 6, 7, 4, 2, null, null, null, null, null, null, 9, 8))); + } + + static class Solution { + + public boolean leafSimilar(TreeNode root1, TreeNode root2) { + List root1Leafs = new ArrayList<>(); + List root2Leafs = new ArrayList<>(); + getLeafs(root1, root1Leafs); + getLeafs(root2, root2Leafs); + if (root1Leafs.size() != root2Leafs.size()) { + return false; + } + for (int i = 0; i < root1Leafs.size(); i++) { + if (!Objects.equals(root1Leafs.get(i), root2Leafs.get(i))) { + return false; + } + } + return true; + } + + public void getLeafs(TreeNode root, List leafs) { + if (root == null) { + return; + } + if (root.left == null && root.right == null) { + leafs.add(root.val); + } + getLeafs(root.left, leafs); + getLeafs(root.right, leafs); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" new file mode 100644 index 0000000..b67c5f4 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" @@ -0,0 +1,44 @@ +package io.github.dunwu.algorithm.tree.btree.dfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +/** + * 110. 平衡二叉树 + * + * @author Zhang Peng + * @since 2020-07-06 + */ +public class 平衡二叉树 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.isBalanced(TreeNode.buildTree(3, 9, 20, null, null, 15, 7))); + Assertions.assertFalse(s.isBalanced(TreeNode.buildTree(1, 2, 2, 3, 3, null, null, 4, 4))); + Assertions.assertTrue(s.isBalanced(TreeNode.buildTree())); + } + + static class Solution { + + boolean isOk = true; + + public boolean isBalanced(TreeNode root) { + isOk = true; + maxDepth(root); + return isOk; + } + + public int maxDepth(TreeNode root) { + if (root == null) { return 0; } + if (root.left == null && root.right == null) { return 1; } + int leftDepth = maxDepth(root.left); + int rightDepth = maxDepth(root.right); + if (Math.abs(leftDepth - rightDepth) > 1) { + isOk = false; + } + return Math.max(leftDepth, rightDepth) + 1; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" new file mode 100644 index 0000000..820c810 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" @@ -0,0 +1,41 @@ +package io.github.dunwu.algorithm.tree.btree.divide; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +/** + * 124. 二叉树中的最大路径和 + * + * @author Zhang Peng + * @since 2020-07-06 + */ +public class 二叉树中的最大路径和 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(6, s.maxPathSum(TreeNode.buildTree(1, 2, 3))); + Assertions.assertEquals(42, s.maxPathSum(TreeNode.buildTree(-10, 9, 20, null, null, 15, 7))); + } + + static class Solution { + + int res = Integer.MIN_VALUE; + + public int maxPathSum(TreeNode root) { + if (root == null) { return 0; } + oneSideMax(root); + return res; + } + + int oneSideMax(TreeNode root) { + if (root == null) { return 0; } + int left = Math.max(oneSideMax(root.left), 0); + int right = Math.max(oneSideMax(root.right), 0); + int pathMaxSum = root.val + left + right; + res = Math.max(res, pathMaxSum); + return Math.max(left, right) + root.val; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" index 9504da0..b0b70bf 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" @@ -3,9 +3,7 @@ import io.github.dunwu.algorithm.tree.TreeNode; import org.junit.jupiter.api.Assertions; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -18,19 +16,23 @@ public class 从中序与后序遍历序列构造二叉树 { public static void main(String[] args) { + Solution s = new Solution(); + TreeNode output1 = s.buildTree(new int[] { 9, 3, 15, 20, 7 }, new int[] { 9, 15, 7, 20, 3 }); - List list = TreeNode.toValueList(output1); - System.out.println(list); - Assertions.assertArrayEquals(Arrays.asList(3, 9, 20, null, null, 15, 7).toArray(), list.toArray()); + Assertions.assertEquals(TreeNode.buildTree(3, 9, 20, null, null, 15, 7), output1); + + TreeNode output2 = s.buildTree(new int[] { -1 }, new int[] { -1 }); + Assertions.assertEquals(TreeNode.buildTree(-1), output2); } static class Solution { - Map map = new HashMap<>(); + Map map = null; public TreeNode buildTree(int[] inorder, int[] postorder) { if (inorder == null || postorder == null) { return null; } + map = new HashMap<>(inorder.length); for (int i = 0; i < inorder.length; i++) { map.put(inorder[i], i); } @@ -38,17 +40,16 @@ public TreeNode buildTree(int[] inorder, int[] postorder) { postorder, 0, postorder.length - 1); } - public TreeNode build(int[] inorder, int inBegin, int inEnd, - int[] postorder, int postBegin, int postEnd) { - if (postBegin > postEnd) { return null; } - int rootVal = postorder[postEnd]; - int rootPos = map.get(rootVal); - int leftSize = rootPos - inBegin; - TreeNode root = new TreeNode(rootVal); - root.left = build(inorder, inBegin, rootPos - 1, - postorder, postBegin, postBegin + leftSize - 1); - root.right = build(inorder, rootPos + 1, inEnd, - postorder, postBegin + leftSize, postEnd - 1); + public TreeNode build(int[] inorder, int inLow, int inHigh, + int[] postorder, int postLow, int postHigh) { + if (postLow > postHigh) { return null; } + int inMid = map.get(postorder[postHigh]); + int leftLen = inMid - inLow; + TreeNode root = new TreeNode(postorder[postHigh]); + root.left = build(inorder, inLow, inMid - 1, + postorder, postLow, postLow + leftLen - 1); + root.right = build(inorder, inMid + 1, inHigh, + postorder, postLow + leftLen, postHigh - 1); return root; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" index b3b367f..af00d0e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" @@ -3,9 +3,7 @@ import io.github.dunwu.algorithm.tree.TreeNode; import org.junit.jupiter.api.Assertions; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -22,22 +20,19 @@ public static void main(String[] args) { Solution s = new Solution(); TreeNode output1 = s.buildTree(new int[] { 3, 9, 20, 15, 7 }, new int[] { 9, 3, 15, 20, 7 }); - List list = TreeNode.toValueList(output1); - System.out.println(list); - Assertions.assertArrayEquals(Arrays.asList(3, 9, 20, null, null, 15, 7).toArray(), list.toArray()); + Assertions.assertEquals(TreeNode.buildTree(3, 9, 20, null, null, 15, 7), output1); TreeNode output2 = s.buildTree(new int[] { -1 }, new int[] { -1 }); - List list2 = TreeNode.toValueList(output2); - System.out.println(list2); - Assertions.assertArrayEquals(Arrays.asList(-1).toArray(), list2.toArray()); + Assertions.assertEquals(TreeNode.buildTree(-1), output2); } static class Solution { - Map map = new HashMap<>(); + Map map = null; public TreeNode buildTree(int[] preorder, int[] inorder) { - if (preorder == null || inorder == null) { return null; } + if (inorder == null || preorder == null) { return null; } + map = new HashMap<>(inorder.length); for (int i = 0; i < inorder.length; i++) { map.put(inorder[i], i); } @@ -45,17 +40,16 @@ public TreeNode buildTree(int[] preorder, int[] inorder) { inorder, 0, inorder.length - 1); } - public TreeNode build(int[] preorder, int preBegin, int preEnd, - int[] inorder, int inBegin, int inEnd) { - if (preBegin > preEnd) { return null; } - int rootVal = preorder[preBegin]; - int rootPos = map.get(rootVal); - int leftSize = rootPos - inBegin; - TreeNode root = new TreeNode(rootVal); - root.left = build(preorder, preBegin + 1, preBegin + leftSize, - inorder, inBegin, rootPos - 1); - root.right = build(preorder, preBegin + leftSize + 1, preEnd, - inorder, rootPos + 1, inEnd); + public TreeNode build(int[] preorder, int preLow, int preHigh, + int[] inorder, int inLow, int inHigh) { + if (preLow > preHigh) { return null; } + int inMid = map.get(preorder[preLow]); + int leftLen = inMid - inLow; + TreeNode root = new TreeNode(preorder[preLow]); + root.left = build(preorder, preLow + 1, preLow + leftLen, + inorder, inLow, inMid - 1); + root.right = build(preorder, preLow + leftLen + 1, preHigh, + inorder, inMid + 1, inHigh); return root; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" index 28deff6..075881f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" @@ -1,11 +1,16 @@ package io.github.dunwu.algorithm.tree.btree.divide; import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; +import java.util.stream.Stream; /** * 1110. 删点成林 @@ -18,24 +23,34 @@ public class 删点成林 { public static void main(String[] args) { Solution s = new Solution(); - TreeNode input = TreeNode.buildTree(1, 2, 3, 4, 5, 6, 7); - List output = s.delNodes(input, new int[] { 3, 5 }); - for (TreeNode tree : output) { - System.out.println(TreeNode.toValueList(tree)); + List output = s.delNodes(TreeNode.buildTree(1, 2, 3, 4, 5, 6, 7), new int[] { 3, 5 }); + List expect = new ArrayList<>(); + expect.add(TreeNode.buildTree(1, 2, null, 4)); + expect.add(TreeNode.buildTree(6)); + expect.add(TreeNode.buildTree(7)); + for (int i = 0; i < output.size(); i++) { + Assertions.assertEquals(expect.get(i), output.get(i)); } - // List result1 = TreeNode.toValueList(output); - // Assertions.assertArrayEquals(new Integer[] { 5, 4, null, 1, 3, null, null, 2 }, result1.toArray()); + List output2 = s.delNodes(TreeNode.buildTree(1, 2, 4, null, 3), new int[] { 3 }); + List expect2 = new ArrayList<>(); + expect2.add(TreeNode.buildTree(1, 2, 4)); + for (int i = 0; i < output2.size(); i++) { + Assertions.assertEquals(expect2.get(i), output2.get(i)); + } } static class Solution { - Set delValSet = new HashSet<>(); - List res = new LinkedList<>(); + private Set set = null; + private List res = null; public List delNodes(TreeNode root, int[] to_delete) { + if (root == null) { return new ArrayList<>(); } + set = new HashSet<>(); + res = new LinkedList<>(); for (int val : to_delete) { - delValSet.add(val); + set.add(val); } traverse(root, false); return res; @@ -43,7 +58,7 @@ public List delNodes(TreeNode root, int[] to_delete) { public TreeNode traverse(TreeNode root, boolean hasParent) { if (root == null) { return null; } - boolean deleted = delValSet.contains(root.val); + boolean deleted = set.contains(root.val); if (!deleted && !hasParent) { res.add(root); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" new file mode 100644 index 0000000..0daa7f4 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" @@ -0,0 +1,38 @@ +package io.github.dunwu.algorithm.tree.btree.divide; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +/** + * 101. 对称二叉树 + * + * @author Zhang Peng + * @date 2020-01-28 + */ +public class 对称二叉树 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.isSymmetric(TreeNode.buildTree(1, 2, 2, 3, 4, 4, 3))); + Assertions.assertFalse(s.isSymmetric(TreeNode.buildTree(1, 2, 2, null, 3, null, 3))); + } + + static class Solution { + + public boolean isSymmetric(TreeNode root) { + if (root == null) { return true; } + return isSymmetric(root.left, root.right); + } + + boolean isSymmetric(TreeNode left, TreeNode right) { + if (left == null && right == null) { return true; } + if (left == null || right == null) { return false; } + // 两个根节点需要相同 + if (left.val != right.val) { return false; } + // 左右子树也需要镜像对称 + return isSymmetric(left.left, right.right) && isSymmetric(left.right, right.left); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" index e0e8079..6be6338 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" @@ -23,30 +23,32 @@ public static void main(String[] args) { static class Solution { - List[] memo; + LinkedList[] memo = null; public List allPossibleFBT(int n) { - if (n % 2 == 0) { - return new LinkedList<>(); + + if (memo == null) { + memo = new LinkedList[n + 1]; } - memo = new LinkedList[n + 1]; - return build(n); - } - public List build(int n) { - List res = new LinkedList<>(); - if (n == 1) { - res.add(new TreeNode(0)); + LinkedList res = new LinkedList<>(); + // 根据真二叉树定义,节点数必为奇数 + if (n % 2 == 0) { return res; } if (memo[n] != null) { return memo[n]; } - for (int i = 1; i < n; i += 2) { - int j = n - i - 1; + if (n == 1) { + res.add(new TreeNode(0)); + memo[n] = res; + return res; + } - List leftSubTree = build(i); - List rightSubTree = build(j); + for (int leftNum = 1; leftNum < n; leftNum += 2) { + int rightNum = n - leftNum - 1; + List leftSubTree = allPossibleFBT(leftNum); + List rightSubTree = allPossibleFBT(rightNum); for (TreeNode left : leftSubTree) { for (TreeNode right : rightSubTree) { TreeNode node = new TreeNode(0); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" index a256d07..5ac28da 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" @@ -14,38 +14,35 @@ public class 最大二叉树2 { public static void main(String[] args) { - TreeNode input = TreeNode.buildTree(4, 1, 3, null, null, 2); - TreeNode output = insertIntoMaxTree(input, 5); - List result1 = TreeNode.toValueList(output); - Assertions.assertArrayEquals(new Integer[] { 5, 4, null, 1, 3, null, null, 2 }, result1.toArray()); - - TreeNode input2 = TreeNode.buildTree(5, 2, 4, null, 1); - TreeNode output2 = insertIntoMaxTree(input2, 3); - List result2 = TreeNode.toValueList(output2); - Assertions.assertArrayEquals(new Integer[] { 5, 2, 4, null, 1, null, 3 }, result2.toArray()); - - TreeNode input3 = TreeNode.buildTree(3, 2); - TreeNode output3 = insertIntoMaxTree(input3, 1); - List result3 = TreeNode.toValueList(output3); - Assertions.assertArrayEquals(new Integer[] { 3, 2, null, null, 1 }, result3.toArray()); + + Solution s = new Solution(); + + Assertions.assertEquals(TreeNode.buildTree(5, 4, null, 1, 3, null, null, 2), + s.insertIntoMaxTree(TreeNode.buildTree(4, 1, 3, null, null, 2), 5)); + + Assertions.assertEquals(TreeNode.buildTree(5, 2, 4, null, 1, null, 3), + s.insertIntoMaxTree(TreeNode.buildTree(5, 2, 4, null, 1), 3)); + + Assertions.assertEquals(TreeNode.buildTree(5, 2, 4, null, 1, 3), + s.insertIntoMaxTree(TreeNode.buildTree(5, 2, 3, null, 1), 4)); } - public static TreeNode insertIntoMaxTree(TreeNode root, int val) { - if (root == null) { - return new TreeNode(val); - } - if (root.val < val) { - // 如果 val 是整棵树最大的,那么原来的这棵树应该是 val 节点的左子树, - // 因为 val 节点是接在原始数组 a 的最后一个元素 - TreeNode temp = root; - root = new TreeNode(val); - root.left = temp; - } else { - // 如果 val 不是最大的,那么就应该在右子树上, - // 因为 val 节点是接在原始数组 a 的最后一个元素 - root.right = insertIntoMaxTree(root.right, val); + static class Solution { + + public TreeNode insertIntoMaxTree(TreeNode root, int val) { + + if (root == null) { return new TreeNode(val); } + + if (val > root.val) { + TreeNode temp = root; + root = new TreeNode(val); + root.left = temp; + } else { + root.right = insertIntoMaxTree(root.right, val); + } + return root; } - return root; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" index 60759ba..5bb6c8f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" @@ -3,9 +3,7 @@ import io.github.dunwu.algorithm.tree.TreeNode; import org.junit.jupiter.api.Assertions; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -18,39 +16,41 @@ public class 根据前序和后序遍历构造二叉树 { public static void main(String[] args) { - TreeNode output1 = new Solution().constructFromPrePost(new int[] { 1, 2, 4, 5, 3, 6, 7 }, + + Solution s = new Solution(); + TreeNode output1 = s.constructFromPrePost(new int[] { 1, 2, 4, 5, 3, 6, 7 }, new int[] { 4, 5, 2, 6, 7, 3, 1 }); - List list = TreeNode.toValueList(output1); - // System.out.println(list); - Assertions.assertArrayEquals(Arrays.asList(1, 2, 3, 4, 5, 6, 7).toArray(), list.toArray()); + Assertions.assertEquals(TreeNode.buildTree(1, 2, 3, 4, 5, 6, 7), output1); + + TreeNode output2 = s.constructFromPrePost(new int[] { 1 }, new int[] { 1 }); + Assertions.assertEquals(TreeNode.buildTree(1), output2); } static class Solution { - Map postPosMap = new HashMap<>(); + Map map = new HashMap<>(); public TreeNode constructFromPrePost(int[] preorder, int[] postorder) { if (preorder.length == 0 || postorder.length == 0) { return null; } for (int i = 0; i < postorder.length; i++) { - postPosMap.put(postorder[i], i); + map.put(postorder[i], i); } return build(preorder, 0, preorder.length - 1, postorder, 0, postorder.length - 1); } - public TreeNode build(int[] preorder, int preBegin, int preEnd, - int[] postorder, int postBegin, int postEnd) { - if (preBegin > preEnd) { return null; } - if (preBegin == preEnd) { return new TreeNode(preorder[preBegin]); } - int rootVal = preorder[preBegin]; - int nextRootVal = preorder[preBegin + 1]; - int nextRootPos = postPosMap.get(nextRootVal); - int leftSize = nextRootPos - postBegin + 1; - TreeNode root = new TreeNode(rootVal); - root.left = build(preorder, preBegin + 1, preBegin + leftSize, - postorder, postBegin, nextRootPos); - root.right = build(preorder, preBegin + leftSize + 1, preEnd, - postorder, nextRootPos + 1, postEnd - 1); + public TreeNode build(int[] preorder, int preLow, int preHigh, + int[] postorder, int postLow, int postHigh) { + if (preLow > preHigh) { return null; } + if (preLow == preHigh) { return new TreeNode(preorder[preLow]); } + int leftRootVal = preorder[preLow + 1]; + int leftPostHigh = map.get(leftRootVal); + int leftLen = leftPostHigh - postLow + 1; + TreeNode root = new TreeNode(preorder[preLow]); + root.left = build(preorder, preLow + 1, preLow + leftLen, + postorder, postLow, leftPostHigh); + root.right = build(preorder, preLow + leftLen + 1, preHigh, + postorder, leftPostHigh + 1, postHigh - 1); return root; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\233\270\345\220\214\347\232\204\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\233\270\345\220\214\347\232\204\346\240\221.java" new file mode 100644 index 0000000..04205a8 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\233\270\345\220\214\347\232\204\346\240\221.java" @@ -0,0 +1,32 @@ +package io.github.dunwu.algorithm.tree.btree.divide; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +/** + * 100. 相同的树 + * + * @author Zhang Peng + * @date 2020-01-28 + */ +public class 相同的树 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.isSameTree(TreeNode.buildTree(1, 2, 3), TreeNode.buildTree(1, 2, 3))); + Assertions.assertFalse(s.isSameTree(TreeNode.buildTree(1, 2), TreeNode.buildTree(1, 2, 3))); + Assertions.assertFalse(s.isSameTree(TreeNode.buildTree(1, 2, 1), TreeNode.buildTree(1, 1, 2))); + } + + static class Solution { + + public boolean isSameTree(TreeNode p, TreeNode q) { + if (p == null && q == null) { return true; } + if (p == null || q == null) { return false; } + if (p.val != q.val) { return false; } + return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" new file mode 100644 index 0000000..4b597e9 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" @@ -0,0 +1,40 @@ +package io.github.dunwu.algorithm.tree.btree.divide; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +/** + * 951. 翻转等价二叉树 + * + * @author Zhang Peng + * @date 2025-10-29 + */ +public class 翻转等价二叉树 { + + public static void main(String[] args) { + Solution s = new Solution(); + TreeNode p = TreeNode.buildTree(1, 2, 3, 4, 5, 6, null, null, null, 7, 8); + TreeNode q = TreeNode.buildTree(1, 3, 2, null, 6, 4, 5, null, null, null, null, 8, 7); + Assertions.assertTrue(s.flipEquiv(p, q)); + Assertions.assertTrue(s.flipEquiv(TreeNode.buildTree(), TreeNode.buildTree())); + Assertions.assertFalse(s.flipEquiv(TreeNode.buildTree(), TreeNode.buildTree(1))); + } + + static class Solution { + + public boolean flipEquiv(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 == null) { return true; } + if (root1 == null || root2 == null) { return false; } + if (root1.val != root2.val) { return false; } + return ( + // 不翻转子树 + flipEquiv(root1.left, root2.left) && flipEquiv(root1.right, root2.right) + ) || ( + // 翻转子树 + flipEquiv(root1.right, root2.left) && flipEquiv(root1.left, root2.right) + ); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" index 180ab12..3c76bba 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" @@ -1,7 +1,9 @@ package io.github.dunwu.algorithm.tree.btree.divide; +import io.github.dunwu.algorithm.tree.TreeNode; import org.junit.jupiter.api.Assertions; +import java.util.Arrays; import java.util.LinkedList; /** @@ -13,32 +15,32 @@ public class 验证二叉树的前序序列化 { public static void main(String[] args) { - Assertions.assertTrue(isValidSerialization("9,3,4,#,#,1,#,#,2,#,6,#,#")); - Assertions.assertFalse(isValidSerialization("1,#")); - Assertions.assertFalse(isValidSerialization("9,#,#,1")); + Solution s = new Solution(); + Assertions.assertTrue(s.isValidSerialization("9,3,4,#,#,1,#,#,2,#,6,#,#")); + Assertions.assertFalse(s.isValidSerialization("1,#")); + Assertions.assertFalse(s.isValidSerialization("9,#,#,1")); } - public static boolean isValidSerialization(String preorder) { - // 将字符串转化成列表 - LinkedList nodes = new LinkedList<>(); - for (String s : preorder.split(",")) { - nodes.addLast(s); + static class Solution { + + /** + * 参考题解:https://leetcode.cn/problems/verify-preorder-serialization-of-a-binary-tree/solutions/651132/pai-an-jiao-jue-de-liang-chong-jie-fa-zh-66nt + */ + public boolean isValidSerialization(String preorder) { + LinkedList values = new LinkedList<>(Arrays.asList(preorder.split(","))); + int diff = 1; + for (String val : values) { + diff -= 1; + if (diff < 0) { + return false; + } + if (!val.equals("#")) { + diff += 2; + } + } + return diff == 0; } - return deserialize(nodes) && nodes.isEmpty(); - } - - public static boolean deserialize(LinkedList nodes) { - if (nodes.isEmpty()) { - return false; - } - - // ***** 前序遍历位置 ***** - // 列表最左侧就是根节点 - String first = nodes.removeFirst(); - if (first.equals("#")) return true; - // ********************* - return deserialize(nodes) && deserialize(nodes); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" index 37d8dec..3ac124c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" @@ -16,52 +16,55 @@ public class 二叉树中的伪回文路径 { public static void main(String[] args) { + Solution s = new Solution(); Assertions.assertEquals(2, - new Solution().pseudoPalindromicPaths(TreeNode.buildTree(2, 3, 1, 3, 1, null, 1))); + s.pseudoPalindromicPaths(TreeNode.buildTree(2, 3, 1, 3, 1, null, 1))); Assertions.assertEquals(1, - new Solution().pseudoPalindromicPaths(TreeNode.buildTree(2, 1, 1, 1, 3, null, null, null, null, null, 1))); + s.pseudoPalindromicPaths(TreeNode.buildTree(2, 1, 1, 1, 3, null, null, null, null, null, 1))); + Assertions.assertEquals(1, + s.pseudoPalindromicPaths(TreeNode.buildTree(9))); } static class Solution { - int num = 0; - LinkedList paths = new LinkedList<>(); + int res = 0; + // 计数数组,题目说了 1 <= root.val <= 9 + int[] count; public int pseudoPalindromicPaths(TreeNode root) { + res = 0; + count = new int[10]; traverse(root); - return num; + return res; } public void traverse(TreeNode root) { if (root == null) { return; } - paths.addLast(root.val); + // 选择 if (root.left == null && root.right == null) { - // System.out.println("paths: " + paths); - if (isPalindromic(paths)) { - num++; + count[root.val]++; + int odd = 0; + for (int cnt : count) { + if (cnt % 2 != 0) { + odd++; + } } - } else { - traverse(root.left); - traverse(root.right); - } - paths.removeLast(); - } - - public boolean isPalindromic(LinkedList paths) { - if (paths.isEmpty()) { return false; } - if (paths.size() == 1) { return true; } - Map counter = new HashMap<>(paths.size()); - for (Integer path : paths) { - counter.compute(path, (k, v) -> v == null ? 1 : v + 1); - } - int oddNum = 0; - for (Integer v : counter.values()) { - if (v % 2 != 0) { - oddNum++; + if (odd <= 1) { + res++; } + count[root.val]--; + return; } - return oddNum < 2; + + // 选择 + count[root.val]++; + + traverse(root.left); + traverse(root.right); + + // 取消选择 + count[root.val]--; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" index 8fa2c7e..844aeac 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" @@ -4,6 +4,8 @@ import org.junit.jupiter.api.Assertions; import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; @@ -16,44 +18,81 @@ public class 二叉树的右视图 { public static void main(String[] args) { + + Solution s = new Solution(); Assertions.assertArrayEquals(new Integer[] { 1, 3, 4 }, - new Solution().rightSideView(TreeNode.buildTree(1, 2, 3, null, 5, null, 4)).toArray(new Integer[0])); + s.rightSideView(TreeNode.buildTree(1, 2, 3, null, 5, null, 4)).toArray()); + Assertions.assertArrayEquals(new Integer[] { 1, 3, 4, 5 }, + s.rightSideView(TreeNode.buildTree(1, 2, 3, 4, null, null, null, 5)).toArray()); + Assertions.assertArrayEquals(new Integer[] { 1, 3 }, + s.rightSideView(TreeNode.buildTree(1, null, 3)).toArray()); + Assertions.assertArrayEquals(new Integer[] {}, + s.rightSideView(TreeNode.buildTree()).toArray()); + Solution2 s2 = new Solution2(); + Assertions.assertArrayEquals(new Integer[] { 1, 3, 4 }, + s2.rightSideView(TreeNode.buildTree(1, 2, 3, null, 5, null, 4)).toArray()); Assertions.assertArrayEquals(new Integer[] { 1, 3, 4, 5 }, - new Solution().rightSideView(TreeNode.buildTree(1, 2, 3, 4, null, null, null, 5)).toArray(new Integer[0])); + s2.rightSideView(TreeNode.buildTree(1, 2, 3, 4, null, null, null, 5)).toArray()); + Assertions.assertArrayEquals(new Integer[] { 1, 3 }, + s2.rightSideView(TreeNode.buildTree(1, null, 3)).toArray()); + Assertions.assertArrayEquals(new Integer[] {}, + s2.rightSideView(TreeNode.buildTree()).toArray()); + } + // 【层序遍历】思路 static class Solution { + LinkedList res = null; + public List rightSideView(TreeNode root) { - if (root == null) { - return new ArrayList<>(); - } + if (root == null) { return new LinkedList<>(); } - List res = new LinkedList<>(); - LinkedList q = new LinkedList<>(); - q.offer(root); + res = new LinkedList<>(); + LinkedList queue = new LinkedList<>(); + queue.offer(root); - while (!q.isEmpty()) { - int size = q.size(); - TreeNode node = null; + while (!queue.isEmpty()) { + int size = queue.size(); + // 每层将最后一个元素加入结果集 for (int i = 0; i < size; i++) { - node = q.poll(); - if (node.left != null) { - q.offer(node.left); - } - if (node.right != null) { - q.offer(node.right); + TreeNode node = queue.poll(); + if (node.left != null) { queue.offer(node.left); } + if (node.right != null) { queue.offer(node.right); } + if (i == size - 1) { + res.add(node.val); } } - if (node != null) { - res.add(node.val); - } } - return res; } } + // 【遍历递归】思路 + static class Solution2 { + + int depth = 0; + LinkedHashMap map = null; + + public List rightSideView(TreeNode root) { + map = new LinkedHashMap<>(); + traverse(root); + return new LinkedList<>(map.values()); + } + + public void traverse(TreeNode root) { + if (root == null) { return; } + depth++; + if (!map.containsKey(depth)) { + map.put(depth, root.val); + } + traverse(root.right); + traverse(root.left); + depth--; + } + + } + } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" index 121ea23..8da62a1 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Assertions; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -18,18 +19,20 @@ public class 二叉树的所有路径 { public static void main(String[] args) { Solution s = new Solution(); - TreeNode tree = TreeNode.buildTree(1, 2, 3, 5); - List list = s.binaryTreePaths(tree); Assertions.assertArrayEquals(Arrays.asList("1->2->5", "1->3").toArray(), - list.toArray(new String[0])); + s.binaryTreePaths(TreeNode.buildTree(1, 2, 3, 5)).toArray()); + Assertions.assertArrayEquals(Collections.singletonList("1").toArray(), + s.binaryTreePaths(TreeNode.buildTree(1)).toArray()); } static class Solution { - LinkedList res = new LinkedList<>(); - LinkedList paths = new LinkedList<>(); + LinkedList res = null; + LinkedList paths = null; public List binaryTreePaths(TreeNode root) { + res = new LinkedList<>(); + paths = new LinkedList<>(); traverse(root); return res; } @@ -44,19 +47,15 @@ public void traverse(TreeNode root) { // System.out.printf("res: %s\n", JSONUtil.toJsonStr(res)); } - // 遍历左子树 - if (root.left != null) { - // System.out.format("root: %s -> root.left: %s\n", root.val, root.left.val); - traverse(root.left); - // System.out.format("root.left: %s -> root: %s\n", root.left.val, root.val); - } - - // 遍历右子树 - if (root.right != null) { - // System.out.format("root: %s -> root.right: %s\n", root.val, root.right.val); - traverse(root.right); - // System.out.format("root.right: %s -> root: %s\n", root.right.val, root.val); - } + // 【前序】 + // System.out.format("root: %s -> root.left: %s\n", root.val, root.left.val); + traverse(root.left); + // 【中序】 + // System.out.format("root.left: %s -> root: %s\n", root.left.val, root.val); + // System.out.format("root: %s -> root.right: %s\n", root.val, root.right.val); + traverse(root.right); + // 【后序】 + // System.out.format("root.right: %s -> root: %s\n", root.right.val, root.val); // 取消选择 paths.removeLast(); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" index 6a373ee..cabcee9 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" @@ -14,46 +14,56 @@ public class 从叶结点开始的最小字符串 { public static void main(String[] args) { + + Solution s = new Solution(); Assertions.assertEquals("dba", - new Solution().smallestFromLeaf(TreeNode.buildTree(0, 1, 2, 3, 4, 3, 4))); + s.smallestFromLeaf(TreeNode.buildTree(0, 1, 2, 3, 4, 3, 4))); Assertions.assertEquals("adz", - new Solution().smallestFromLeaf(TreeNode.buildTree(25, 1, 3, 1, 3, 0, 2))); + s.smallestFromLeaf(TreeNode.buildTree(25, 1, 3, 1, 3, 0, 2))); Assertions.assertEquals("abc", - new Solution().smallestFromLeaf(TreeNode.buildTree(2, 2, 1, null, 1, 0, null, 0))); + s.smallestFromLeaf(TreeNode.buildTree(2, 2, 1, null, 1, 0, null, 0))); } static class Solution { - String max = null; - LinkedList paths = new LinkedList<>(); + String res = null; + LinkedList nodes = null; public String smallestFromLeaf(TreeNode root) { + res = null; + nodes = new LinkedList<>(); traverse(root); - return max; + return res; } public void traverse(TreeNode root) { + // 校验 if (root == null) { return; } - char c = (char) (root.val + 'a'); - paths.addLast(c); + // 选择 + nodes.addLast(root.val); if (root.left == null && root.right == null) { - StringBuilder sb = new StringBuilder(); - for (int i = paths.size() - 1; i >= 0; i--) { - sb.append(paths.get(i)); - } - if (max == null) { - max = sb.toString(); - } else { - if (max.compareTo(sb.toString()) > 0) { - max = sb.toString(); - } + String str = toString(nodes); + // System.out.printf("\tstr: %s\n", str); + if (res == null || str.compareTo(res) < 0) { + res = str; } - } else { - traverse(root.left); - traverse(root.right); } - paths.removeLast(); + + traverse(root.left); + traverse(root.right); + + // 取消选择 + nodes.removeLast(); + } + + public String toString(LinkedList nodes) { + StringBuilder sb = new StringBuilder(); + for (int node : nodes) { + char c = (char) (node + 'a'); + sb.insert(0, c); + } + return sb.toString(); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" index ca2d004..6b45eec 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" @@ -14,37 +14,48 @@ public class 从根到叶的二进制数之和 { public static void main(String[] args) { - Assertions.assertEquals(22, - new Solution().sumRootToLeaf(TreeNode.buildTree(1, 0, 1, 0, 1, 0, 1))); - Assertions.assertEquals(0, - new Solution().sumRootToLeaf(TreeNode.buildTree(0))); + Solution s = new Solution(); + Assertions.assertEquals(22, s.sumRootToLeaf(TreeNode.buildTree(1, 0, 1, 0, 1, 0, 1))); + Assertions.assertEquals(0, s.sumRootToLeaf(TreeNode.buildTree(0))); } static class Solution { int sum = 0; - LinkedList paths = new LinkedList<>(); + LinkedList nodes; public int sumRootToLeaf(TreeNode root) { + sum = 0; + nodes = new LinkedList<>(); traverse(root); return sum; } - public void traverse(TreeNode root) { - if (root == null) { return; } + public void traverse(TreeNode node) { + // 校验 + if (node == null) return; - paths.addLast(root.val); - if (root.left == null && root.right == null) { - int num = 0; - for (Integer value : paths) { - num = num * 2 + value; - } + // 选择 + nodes.addLast(node.val); + if (node.left == null && node.right == null) { + Integer num = toNum(nodes); + System.out.printf("\tnum: %d\n", num); sum += num; - } else { - traverse(root.left); - traverse(root.right); } - paths.removeLast(); + + traverse(node.left); + traverse(node.right); + + // 取消选择 + nodes.removeLast(); + } + + Integer toNum(LinkedList nodes) { + int num = 0; + for (int node : nodes) { + num = num * 2 + node; + } + return num; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" index 9b8e09a..737d9b7 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" @@ -4,7 +4,6 @@ import org.junit.jupiter.api.Assertions; import java.util.LinkedList; -import java.util.List; /** * 求根节点到叶节点数字之和 @@ -15,48 +14,45 @@ public class 求根节点到叶节点数字之和 { public static void main(String[] args) { - Assertions.assertEquals(25, new Solution().sumNumbers(TreeNode.buildTree(1, 2, 3))); - Assertions.assertEquals(1026, new Solution().sumNumbers(TreeNode.buildTree(4, 9, 0, 5, 1))); + Solution s = new Solution(); + Assertions.assertEquals(25, s.sumNumbers(TreeNode.buildTree(1, 2, 3))); + Assertions.assertEquals(1026, s.sumNumbers(TreeNode.buildTree(4, 9, 0, 5, 1))); } static class Solution { - TreeNode root = null; - List nums = new LinkedList<>(); - LinkedList paths = new LinkedList<>(); + int res = 0; + LinkedList paths = null; public int sumNumbers(TreeNode root) { - this.root = root; + res = 0; + paths = new LinkedList<>(); traverse(root); - if (nums.size() == 0) { return 0; } - return nums.stream().mapToInt(Integer::intValue).sum(); + return res; } - public void traverse(TreeNode node) { - if (node == null) { return; } - if (node.left == null && node.right == null) { - paths.addLast(node); - if (paths.getFirst() == this.root) { - int num = toNum(paths); - nums.add(num); + public void traverse(TreeNode root) { + // 【校验】 + if (root == null) { return; } + + // 选择 + paths.addLast(root.val); + if (root.left == null && root.right == null) { + int num = 0; + for (Integer path : paths) { + num = num * 10 + path; } - paths.removeLast(); - return; + res += num; } - paths.addLast(node); - traverse(node.left); - traverse(node.right); - paths.removeLast(); - } + // 【前序】 + traverse(root.left); + // 【中序】 + traverse(root.right); + // 【后序】 - public int toNum(List paths) { - if (paths.size() == 0) { return 0; } - int num = 0; - for (TreeNode node : paths) { - num = num * 10 + node.val; - } - return num; + // 取消选择 + paths.removeLast(); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" deleted file mode 100644 index 8a04657..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @see 124. 二叉树中的最大路径和 - * @since 2020-07-06 - */ -public class 二叉树中的最大路径和 { - - public static void main(String[] args) { - 二叉树中的最大路径和 demo = new 二叉树中的最大路径和(); - TreeNode tree = TreeNode.buildTree(1, 2, 3); - Assertions.assertEquals(6, demo.maxPathSum(tree)); - TreeNode tree2 = TreeNode.buildTree(-10, 9, 20, null, null, 15, 7); - Assertions.assertEquals(42, demo.maxPathSum(tree2)); - TreeNode tree3 = TreeNode.buildTree(2, -1); - Assertions.assertEquals(2, demo.maxPathSum(tree3)); - TreeNode tree4 = TreeNode.buildTree(-2, -1); - Assertions.assertEquals(-1, demo.maxPathSum(tree4)); - } - - int maxSum; - - public int maxPathSum(TreeNode root) { - maxSum = Integer.MIN_VALUE; - maxGain(root); - return maxSum; - } - - public int maxGain(TreeNode node) { - if (node == null) { - return 0; - } - - // 递归计算左右子节点的最大贡献值 - // 只有在最大贡献值大于 0 时,才会选取对应子节点 - int left = Math.max(maxGain(node.left), 0); - int right = Math.max(maxGain(node.right), 0); - - // 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值 - int current = node.val + left + right; - - // 更新答案 - maxSum = Math.max(maxSum, current); - - // 返回节点的最大贡献值 - return node.val + Math.max(left, right); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" index 005e6e5..a29aa65 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" @@ -3,8 +3,6 @@ import io.github.dunwu.algorithm.tree.TreeNode; import org.junit.jupiter.api.Assertions; -import java.util.List; - /** * 114. 二叉树展开为链表 * @@ -19,42 +17,47 @@ public static void main(String[] args) { TreeNode root = TreeNode.buildTree(1, 2, 5, 3, 4, null, 6); s.flatten(root); - List list = TreeNode.toValueList(root); Assertions.assertArrayEquals(new Integer[] { 1, null, 2, null, 3, null, 4, null, 5, null, 6 }, - list.toArray(new Integer[0])); + TreeNode.toValueList(root).toArray()); TreeNode root2 = TreeNode.buildTree(0); s.flatten(root2); - List list2 = TreeNode.toValueList(root2); - Assertions.assertArrayEquals(new Integer[] { 0 }, - list2.toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 0 }, TreeNode.toValueList(root2).toArray()); TreeNode root3 = TreeNode.buildTree(); s.flatten(root3); - List list3 = TreeNode.toValueList(root3); - Assertions.assertArrayEquals(new Integer[] {}, - list3.toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] {}, TreeNode.toValueList(root3).toArray()); } static class Solution { public void flatten(TreeNode root) { - traverse(root); - } - void traverse(TreeNode root) { + // 【校验】 if (root == null) { return; } - traverse(root.left); - traverse(root.right); - if (root.left == null) { return; } + + // 【前序】 + // 左子树展开为链表 + flatten(root.left); + // 【中序】 + // 右子树展开为链表 + flatten(root.right); + // 【后序】 + + // 1. 此时,左右子树已展开为链表 + TreeNode left = root.left; TreeNode right = root.right; - root.right = root.left; - TreeNode p = root.left; + + // 2、将左子树作为右子树 + root.left = null; + root.right = left; + + // 3. 将旧右子树接到新右子树末端 + TreeNode p = root; while (p.right != null) { p = p.right; } p.right = right; - root.left = null; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" deleted file mode 100644 index 252b62e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" +++ /dev/null @@ -1,49 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; - -/** - * 94. 二叉树的中序遍历 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 二叉树的中序遍历 { - - public static void main(String[] args) { - Solution s1 = new Solution(); - TreeNode root = TreeNode.buildTree(1, null, 2, 3); - Assertions.assertArrayEquals(new Integer[] { 1, 3, 2 }, s1.inorderTraversal(root).toArray(new Integer[0])); - - Solution s2 = new Solution(); - TreeNode root2 = TreeNode.buildTree(); - Assertions.assertArrayEquals(new Integer[] {}, s2.inorderTraversal(root2).toArray(new Integer[0])); - - Solution s3 = new Solution(); - TreeNode root3 = TreeNode.buildTree(1); - Assertions.assertArrayEquals(new Integer[] { 1 }, s3.inorderTraversal(root3).toArray(new Integer[0])); - } - - private static class Solution { - - List values = new ArrayList<>(); - - public List inorderTraversal(TreeNode root) { - traverse(root); - return values; - } - - public void traverse(TreeNode root) { - if (root == null) return; - traverse(root.left); - values.add(root.val); - traverse(root.right); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" deleted file mode 100644 index 06c1168..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" +++ /dev/null @@ -1,67 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; - -/** - * 144. 二叉树的前序遍历 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 二叉树的前序遍历 { - - public static void main(String[] args) { - Solution s1 = new Solution(); - TreeNode root = TreeNode.buildTree(1, null, 2, 3); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, s1.preorderTraversal(root).toArray(new Integer[0])); - - Solution s2 = new Solution(); - TreeNode root2 = TreeNode.buildTree(); - Assertions.assertArrayEquals(new Integer[] {}, s2.preorderTraversal(root2).toArray(new Integer[0])); - - Solution s3 = new Solution(); - TreeNode root3 = TreeNode.buildTree(1); - Assertions.assertArrayEquals(new Integer[] { 1 }, s3.preorderTraversal(root3).toArray(new Integer[0])); - } - - private static class Solution { - - List res = new ArrayList<>(); - - /** - * 遍历思路的递归 - */ - public List preorderTraversal(TreeNode root) { - traverse(root); - return res; - } - - public void traverse(TreeNode root) { - if (root == null) return; - res.add(root.val); - traverse(root.left); - traverse(root.right); - } - - /** - * 分解思路的递归 - */ - public List preorderTraversal2(TreeNode root) { - List res = new ArrayList<>(); - if (root == null) return res; - // 前序遍历的结果,root.val 在第一个 - res.add(root.val); - // 利用函数定义,后面接着左子树的前序遍历结果 - res.addAll(preorderTraversal(root.left)); - // 利用函数定义,最后接着右子树的前序遍历结果 - res.addAll(preorderTraversal(root.right)); - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" deleted file mode 100644 index 5f72ca1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" +++ /dev/null @@ -1,54 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; - -/** - * 145. 二叉树的后序遍历 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 二叉树的后序遍历 { - - public static void main(String[] args) { - Solution s1 = new Solution(); - TreeNode root = TreeNode.buildTree(1, null, 2, 3); - Assertions.assertArrayEquals(new Integer[] { 3, 2, 1 }, s1.postorderTraversal(root).toArray(new Integer[0])); - - Solution s2 = new Solution(); - TreeNode root2 = TreeNode.buildTree(); - Assertions.assertArrayEquals(new Integer[] {}, s2.postorderTraversal(root2).toArray(new Integer[0])); - - Solution s3 = new Solution(); - TreeNode root3 = TreeNode.buildTree(1); - Assertions.assertArrayEquals(new Integer[] { 1 }, s3.postorderTraversal(root3).toArray(new Integer[0])); - - Solution s4 = new Solution(); - TreeNode root4 = TreeNode.buildTree(1, 2, 3, 4, 5, null, 8, null, null, 6, 7, 9); - Assertions.assertArrayEquals(new Integer[] { 4, 6, 7, 5, 2, 9, 8, 3, 1 }, - s4.postorderTraversal(root4).toArray(new Integer[0])); - } - - private static class Solution { - - List values = new ArrayList<>(); - - public List postorderTraversal(TreeNode root) { - traverse(root); - return values; - } - - public void traverse(TreeNode root) { - if (root == null) return; - traverse(root.left); - traverse(root.right); - values.add(root.val); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" index 515e471..3bede39 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" @@ -15,47 +15,57 @@ public class 二叉树的序列化与反序列化 { public static void main(String[] args) { + String input1 = "1,2,3,null,null,4,5,null,null,null,null,"; - TreeNode tree1 = deserialize(input1); - Assertions.assertEquals(input1, serialize(tree1)); + String input2 = "null,"; + String input3 = "1,null,null,"; + String input4 = "1,2,null,null,null,"; + + Solution s = new Solution(); + Assertions.assertEquals(input1, s.serialize(s.deserialize(input1))); + Assertions.assertEquals(input2, s.serialize(s.deserialize(input2))); + Assertions.assertEquals(input3, s.serialize(s.deserialize(input3))); + Assertions.assertEquals(input4, s.serialize(s.deserialize(input4))); } - static final String SEP = ","; - static final String NULL = "null"; + static class Solution { - public static String serialize(TreeNode root) { - StringBuilder sb = new StringBuilder(); - doSerialize(root, sb); - return sb.toString(); - } + public static final String SEP = ","; + public static final String NULL = "null"; - static void doSerialize(TreeNode root, StringBuilder sb) { - if (root == null) { - sb.append(NULL).append(SEP); - return; + public String serialize(TreeNode root) { + StringBuilder sb = new StringBuilder(); + serialize(root, sb); + return sb.toString(); } - sb.append(root.val).append(SEP); - doSerialize(root.left, sb); - doSerialize(root.right, sb); - } - public static TreeNode deserialize(String data) { - LinkedList nodes = new LinkedList<>(Arrays.asList(data.split(SEP))); - return doDeserialize(nodes); - } + void serialize(TreeNode root, StringBuilder sb) { + if (root == null) { + sb.append(NULL).append(SEP); + return; + } + sb.append(root.val).append(SEP); + serialize(root.left, sb); + serialize(root.right, sb); + } - static TreeNode doDeserialize(LinkedList nodes) { - if (nodes.isEmpty()) return null; + public TreeNode deserialize(String data) { + LinkedList values = new LinkedList<>(Arrays.asList(data.split(SEP))); + return deserialize(values); + } - // =============== 前序遍历处理 =============== - String val = nodes.removeFirst(); - if (NULL.equals(val)) { return null; } - TreeNode root = new TreeNode(Integer.parseInt(val)); - // ========================================== + public TreeNode deserialize(LinkedList values) { + if (values == null || values.isEmpty()) { return null; } + String val = values.removeFirst(); + if (val.equals(NULL)) { + return null; + } + TreeNode root = new TreeNode(Integer.parseInt(val)); + root.left = deserialize(values); + root.right = deserialize(values); + return root; + } - root.left = doDeserialize(nodes); - root.right = doDeserialize(nodes); - return root; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" index 87aab90..c01f06a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" @@ -12,43 +12,71 @@ public class 二叉树的最大深度 { public static void main(String[] args) { + Solution s = new Solution(); - TreeNode root = TreeNode.buildTree(3, 9, 20, null, null, 15, 7); - Assertions.assertEquals(3, s.maxDepth(root)); + Assertions.assertEquals(3, s.maxDepth(TreeNode.buildTree(3, 9, 20, null, null, 15, 7))); + Assertions.assertEquals(2, s.maxDepth(TreeNode.buildTree(1, null, 2))); - TreeNode root2 = TreeNode.buildTree(1, null, 2); - Assertions.assertEquals(2, s.maxDepth(root2)); + Solution2 s2 = new Solution2(); + Assertions.assertEquals(3, s2.maxDepth(TreeNode.buildTree(3, 9, 20, null, null, 15, 7))); + Assertions.assertEquals(2, s2.maxDepth(TreeNode.buildTree(1, null, 2))); } + /** + * 【分解】思路解法 + */ static class Solution { - int depth = 0; + public int maxDepth(TreeNode root) { + if (root == null) { return 0; } + + // 计算左右子树的最大深度 + int left = maxDepth(root.left); + int right = maxDepth(root.right); + + // 根据左右子树的最大深度推出原二叉树的最大深度 + // 整棵树的最大深度等于左右子树的最大深度取最大值, + // 然后再加上根节点自己 + return Math.max(left, right) + 1; + } + + } + + /** + * 【遍历】思路解法 + */ + static class Solution2 { + + // 记录最大深度 int res = 0; + // 记录遍历到的节点的深度 + int depth = 0; public int maxDepth(TreeNode root) { + // 重置全局变量 + res = 0; + depth = 0; traverse(root); return res; } - public void traverse(TreeNode root) { - if (root == null) return; + // 遍历二叉树 + void traverse(TreeNode root) { + if (root == null) { return; } + + // 【前序遍历位置】(进入节点)增加深度 depth++; + // 遍历到叶子节点时记录最大深度 if (root.left == null && root.right == null) { res = Math.max(res, depth); } traverse(root.left); + // 【中序遍历位置】 traverse(root.right); - + // 【后序遍历位置】(离开节点)减少深度 depth--; } - public int maxDepth2(TreeNode root) { - if (root == null) { return 0; } - int left = maxDepth(root.left); - int right = maxDepth(root.right); - return Math.max(left, right) + 1; - } - } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" index 7a871d1..47c3c79 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" @@ -13,43 +13,33 @@ public class 二叉树的最近公共祖先 { public static void main(String[] args) { + + Solution s = new Solution(); + TreeNode root = TreeNode.buildTree(3, 5, 1, 6, 2, 0, 8, null, null, 7, 4); - TreeNode p = TreeNode.find(root, 5); - TreeNode q = TreeNode.find(root, 1); - TreeNode treeNode = lowestCommonAncestor(root, p, q); - Assertions.assertNotNull(treeNode); - Assertions.assertEquals(3, treeNode.val); - System.out.println("公共祖先节点 = " + treeNode.val); - - TreeNode p2 = TreeNode.find(root, 5); - TreeNode q2 = TreeNode.find(root, 4); - TreeNode treeNode2 = lowestCommonAncestor(root, p2, q2); - Assertions.assertNotNull(treeNode2); - Assertions.assertEquals(5, treeNode2.val); - System.out.println("公共祖先节点 = " + treeNode2.val); + TreeNode node1 = s.lowestCommonAncestor(root, TreeNode.find(root, 5), TreeNode.find(root, 1)); + Assertions.assertNotNull(node1); + Assertions.assertEquals(3, node1.val); + + TreeNode node2 = s.lowestCommonAncestor(root, TreeNode.find(root, 5), TreeNode.find(root, 4)); + Assertions.assertNotNull(node2); + Assertions.assertEquals(5, node2.val); } - /** - * 递归方式求解 - *

- * 时间复杂度:O(N) 线性级 - *

- * 空间复杂度:O(2) 常数级 - */ - public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { - - if (root == null) { return null; } - if (root == p || root == q) { return root; } - - TreeNode left = lowestCommonAncestor(root.left, p, q); - TreeNode right = lowestCommonAncestor(root.right, p, q); - if (left != null && right != null) { - return root; - } - if (left == null && right == null) { - return null; + static class Solution { + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + + if (root == null) { return null; } + if (root == p || root == q) { return root; } + + TreeNode left = lowestCommonAncestor(root.left, p, q); + TreeNode right = lowestCommonAncestor(root.right, p, q); + if (left != null && right != null) { return root; } + if (left == null && right == null) { return null; } + return left == null ? right : left; } - return left == null ? right : left; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" index 9d7020a..de506ae 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" @@ -13,30 +13,38 @@ public class 二叉树的直径 { public static void main(String[] args) { Solution s = new Solution(); - TreeNode root = TreeNode.buildTree(1, 2, 3, 4, 5); - Assertions.assertEquals(3, s.diameterOfBinaryTree(root)); - - Solution s2 = new Solution(); - TreeNode root2 = TreeNode.buildTree(1, 2); - Assertions.assertEquals(1, s2.diameterOfBinaryTree(root2)); + Assertions.assertEquals(3, s.diameterOfBinaryTree(TreeNode.buildTree(1, 2, 3, 4, 5))); + Assertions.assertEquals(1, s.diameterOfBinaryTree(TreeNode.buildTree(1, 2))); + Assertions.assertEquals(0, s.diameterOfBinaryTree(TreeNode.buildTree(1))); + Assertions.assertEquals(2, s.diameterOfBinaryTree(TreeNode.buildTree(2, 3, null, 1))); } static class Solution { - private int max = 0; + int max = 0; public int diameterOfBinaryTree(TreeNode root) { - if (root == null) { return 0; } - maxDepth(root); + max = 0; + traverse(root); return max; } + public void traverse(TreeNode root) { + if (root == null) { return; } + + traverse(root.left); + traverse(root.right); + + int left = maxDepth(root.left); + int right = maxDepth(root.right); + max = Math.max(max, left + right); + } + public int maxDepth(TreeNode root) { if (root == null) { return 0; } + if (root.left == null && root.right == null) { return 1; } int left = maxDepth(root.left); int right = maxDepth(root.right); - int temp = left + right; - max = Math.max(max, temp); return Math.max(left, right) + 1; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" index be830dd..e6aeaec 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" @@ -13,24 +13,16 @@ public class 完全二叉树的节点个数 { public static void main(String[] args) { Solution s = new Solution(); - - TreeNode root = TreeNode.buildTree(1, 2, 3, 4, 5, 6); - Assertions.assertEquals(6, s.countNodes(root)); - - TreeNode root2 = TreeNode.buildTree(); - Assertions.assertEquals(0, s.countNodes(root2)); - - TreeNode root3 = TreeNode.buildTree(1); - Assertions.assertEquals(1, s.countNodes(root3)); + Assertions.assertEquals(6, s.countNodes(TreeNode.buildTree(1, 2, 3, 4, 5, 6))); + Assertions.assertEquals(0, s.countNodes(TreeNode.buildTree())); + Assertions.assertEquals(1, s.countNodes(TreeNode.buildTree(1))); } static class Solution { public int countNodes(TreeNode root) { if (root == null) { return 0; } - int left = countNodes(root.left); - int right = countNodes(root.right); - return left + right + 1; + return countNodes(root.left) + countNodes(root.right) + 1; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" deleted file mode 100644 index 0daf9e0..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" +++ /dev/null @@ -1,51 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; - -/** - * 101. 对称二叉树 算法实现 - *

- * 给定一个二叉树,检查它是否是镜像对称的。 - *

- * 例如,二叉树 [1,2,2,3,4,4,3] 是对称的。 - *

- *     1
- *    / \
- *   2   2
- *  / \ / \
- * 3  4 4  3
- * 
- * 但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的: - *
- *     1
- *    / \
- *   2   2
- *    \   \
- *    3    3
- * 
- * 说明:如果你可以运用递归和迭代两种方法解决这个问题,会很加分。 - * - * @see 101. 对称二叉树 - */ -public class 对称二叉树 { - - public static void main(String[] args) { - TreeNode tree = TreeNode.buildTree(1, 2, 2, 3, 4, 4, 3); - System.out.println("result = " + isSymmetric(tree)); - - tree = TreeNode.buildTree(1, 2, 2, null, 3, null, 3); - System.out.println("result = " + isSymmetric(tree)); - } - - public static boolean isSymmetric(TreeNode root) { - return isMirror(root, root); - } - - private static boolean isMirror(TreeNode tree1, TreeNode tree2) { - if (tree1 == null && tree2 == null) return true; - if (tree1 == null || tree2 == null) return false; - if (tree1.val != tree2.val) return false; - return isMirror(tree1.left, tree2.right) && isMirror(tree1.right, tree2.left); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" deleted file mode 100644 index 21958c1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" +++ /dev/null @@ -1,42 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 平衡二叉树 { - - public static void main(String[] args) { - TreeNode tree = TreeNode.buildTree(3, 9, 20, null, null, 15, 7); - TreeNode tree2 = TreeNode.buildTree(1, 2, 2, 3, 3, null, null, 4, 4); - TreeNode tree3 = TreeNode.buildTree(null); - 平衡二叉树 demo = new 平衡二叉树(); - Assertions.assertTrue(demo.isBalanced(tree)); - Assertions.assertFalse(demo.isBalanced(tree2)); - Assertions.assertTrue(demo.isBalanced(tree3)); - } - - private boolean flag = true; - - public boolean isBalanced(TreeNode root) { - if (root == null) return true; - backtrack(root); - return flag; - } - - public int backtrack(TreeNode root) { - if (root == null) return 0; - if (root.left == null && root.right == null) return 1; - int left = backtrack(root.left); - int right = backtrack(root.right); - int temp = left - right; - if (temp > 1 || temp < -1) { - flag = false; - } - return Math.max(left, right) + 1; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" index 2882f5f..1012c25 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" @@ -14,37 +14,39 @@ public class 最大二叉树 { public static void main(String[] args) { - TreeNode output = constructMaximumBinaryTree(new int[] { 3, 2, 1, 6, 0, 5 }); + Solution s = new Solution(); + TreeNode output = s.constructMaximumBinaryTree(new int[] { 3, 2, 1, 6, 0, 5 }); List outputList = TreeNode.toValueList(output); Assertions.assertArrayEquals(new Integer[] { 6, 3, 5, null, 2, 0, null, null, 1 }, outputList.toArray()); - TreeNode root = constructMaximumBinaryTree(new int[] { 3, 2, 1 }); + TreeNode root = s.constructMaximumBinaryTree(new int[] { 3, 2, 1 }); List list = TreeNode.toValueList(root); Assertions.assertArrayEquals(new Integer[] { 3, null, 2, null, 1 }, list.toArray()); } - public static TreeNode constructMaximumBinaryTree(int[] nums) { - return traverse(nums, 0, nums.length - 1); - } + static class Solution { - public static TreeNode traverse(int[] nums, int left, int right) { - if (left > right) { - return null; + public TreeNode constructMaximumBinaryTree(int[] nums) { + if (nums == null || nums.length == 0) { return null; } + return build(nums, 0, nums.length - 1); } - int index = -1; - int max = Integer.MIN_VALUE; - for (int i = left; i <= right; i++) { - if (max < nums[i]) { - index = i; - max = nums[i]; + public TreeNode build(int[] nums, int low, int high) { + if (low > high) { return null; } + int mid = 0; + int max = Integer.MIN_VALUE; + for (int i = low; i <= high; i++) { + if (nums[i] > max) { + max = nums[i]; + mid = i; + } } + TreeNode root = new TreeNode(max); + root.left = build(nums, low, mid - 1); + root.right = build(nums, mid + 1, high); + return root; } - TreeNode root = new TreeNode(max); - root.left = traverse(nums, left, index - 1); - root.right = traverse(nums, index + 1, right); - return root; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\233\270\345\220\214\347\232\204\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\233\270\345\220\214\347\232\204\346\240\221.java" deleted file mode 100644 index 7d6ec15..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\233\270\345\220\214\347\232\204\346\240\221.java" +++ /dev/null @@ -1,71 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; - -/** - * 100. 相同的树 算法实现 - *

- * 给定两个二叉树,编写一个函数来检验它们是否相同。 - *

- * 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。 - *

- * 示例 1: - *

- * 输入:       1         1
- *           / \       / \
- *          2   3     2   3
- *
- *         [1,2,3],   [1,2,3]
- *
- * 输出: true
- * 
- * 示例 2: - *
- * 输入:      1          1
- *           /           \
- *          2             2
- *
- *         [1,2],     [1,null,2]
- *
- * 输出: false
- * 
- * 示例 3: - *
- * 输入:       1         1
- *           / \       / \
- *          2   1     1   2
- *
- *         [1,2,1],   [1,1,2]
- *
- * 输出: false
- * 
- * - * @see 100. 相同的树 - */ -public class 相同的树 { - - public static void main(String[] args) { - TreeNode tree1 = TreeNode.buildTree(1, 2, 3); - TreeNode tree2 = TreeNode.buildTree(1, 2, 3); - System.out.println("result = " + isSameTree(tree1, tree2)); - - tree1 = TreeNode.buildTree(1, 2); - tree2 = TreeNode.buildTree(1, 2, 3); - System.out.println("result = " + isSameTree(tree1, tree2)); - - tree1 = TreeNode.buildTree(1, 2, 1); - tree2 = TreeNode.buildTree(1, 1, 2); - System.out.println("result = " + isSameTree(tree1, tree2)); - } - - public static boolean isSameTree(TreeNode p, TreeNode q) { - if (p == null && q == null) return true; - - if (p == null || q == null) return false; - - if (p.val != q.val) return false; - - return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" index 736aa53..30885c1 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" @@ -1,6 +1,7 @@ package io.github.dunwu.algorithm.tree.btree; import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; /** * 226. 翻转二叉树 @@ -11,37 +12,68 @@ public class 翻转二叉树 { public static void main(String[] args) { - TreeNode tree = TreeNode.buildTree(4, 2, 7, 1, 3, 6, 9); - System.out.println("result = " + invertTree2(tree)); + Solution s = new Solution(); + Assertions.assertEquals(TreeNode.buildTree(4, 2, 7, 1, 3, 6, 9), + s.invertTree(TreeNode.buildTree(4, 7, 2, 9, 6, 3, 1))); + Assertions.assertEquals(TreeNode.buildTree(2, 3, 1), + s.invertTree(TreeNode.buildTree(2, 1, 3))); + Assertions.assertEquals(TreeNode.buildTree(), + s.invertTree(TreeNode.buildTree())); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals(TreeNode.buildTree(4, 2, 7, 1, 3, 6, 9), + s2.invertTree(TreeNode.buildTree(4, 7, 2, 9, 6, 3, 1))); + Assertions.assertEquals(TreeNode.buildTree(2, 3, 1), + s2.invertTree(TreeNode.buildTree(2, 1, 3))); + Assertions.assertEquals(TreeNode.buildTree(), + s2.invertTree(TreeNode.buildTree())); } /** - * 分解递归 + * 【分解】思路解法 */ - public static TreeNode invertTree(TreeNode root) { - if (root == null) return null; - TreeNode left = invertTree(root.left); - TreeNode right = invertTree(root.right); - root.right = left; - root.left = right; - return root; + static class Solution { + + public TreeNode invertTree(TreeNode root) { + if (root == null) { return root; } + TreeNode left = invertTree(root.left); + TreeNode right = invertTree(root.right); + root.right = left; + root.left = right; + return root; + } + } /** - * 遍历递归 + * 【遍历】思路解法 */ - public static TreeNode invertTree2(TreeNode root) { - traverse(root); - return root; - } + static class Solution2 { + + public TreeNode invertTree(TreeNode root) { + traverse(root); + return root; + } + + // 遍历二叉树 + void traverse(TreeNode root) { + if (root == null) { return; } + + // 【前序】 + // System.out.printf("[node -> left]从节点 %s 进入节点 %s\n", root, root.left); + traverse(root.left); + // 【中序】 + // System.out.printf("\t[left -> node]从节点 %s 回到节点 %s\n", root.left, root); + // System.out.printf("\t[node -> right]从节点 %s 进入节点 %s\n", root, root.right); + traverse(root.right); + // 【后序】 + // System.out.printf("\t[right -> node]从节点 %s 回到节点 %s\n", root.right, root); + + TreeNode temp = root.left; + root.left = root.right; + root.right = temp; + } - public static void traverse(TreeNode root) { - if (root == null) return; - TreeNode tmp = root.left; - root.left = root.right; - root.right = tmp; - traverse(root.left); - traverse(root.right); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\344\272\214\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\344\272\214\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" new file mode 100644 index 0000000..7fbb430 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\344\272\214\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" @@ -0,0 +1,30 @@ +package io.github.dunwu.algorithm.tree.template; + +import io.github.dunwu.algorithm.tree.TreeNode; + +/** + * 二叉树递归遍历框架 + * + * @author Zhang Peng + * @date 2025-10-23 + */ +public class 二叉树遍历框架 { + + /** + * 二叉树的遍历框架 + */ + public void traverse(TreeNode root) { + // 【校验】 + if (root == null) { return; } + // 【前序】 + System.out.printf("[node -> left]从节点 %s 进入节点 %s\n", root, root.left); + traverse(root.left); + // 【中序】 + System.out.printf("\t[left -> node]从节点 %s 回到节点 %s\n", root.left, root); + System.out.printf("\t[node -> right]从节点 %s 进入节点 %s\n", root, root.right); + traverse(root.right); + // 【后序】 + System.out.printf("\t[right -> node]从节点 %s 回到节点 %s\n", root.right, root); + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\345\244\232\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\345\244\232\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" new file mode 100644 index 0000000..8835333 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\345\244\232\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" @@ -0,0 +1,35 @@ +package io.github.dunwu.algorithm.tree.template; + +import java.util.List; + +/** + * 多叉树遍历框架 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 多叉树遍历框架 { + + // 多叉树的遍历框架 + void traverse(Node root) { + // base case + if (root == null) { + return; + } + // 前序位置 + System.out.println("visit " + root.val); + for (Node child : root.children) { + traverse(child); + } + // 后序位置 + } + + // 多叉树节点 + static class Node { + + int val; + List children; + + } + +} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/map/LRUCacheTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/map/LRUCacheTest.java deleted file mode 100644 index b1b3272..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/map/LRUCacheTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.github.dunwu.algorithm.map; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * @author Zhang Peng - * @since 2020-01-18 - */ -public class LRUCacheTest { - - @Test - public void test() { - LRUCache cache = new LRUCache(3); - Assertions.assertEquals(-1, cache.get(2)); - cache.put(2, 6); - Assertions.assertEquals(-1, cache.get(1)); - cache.put(1, 5); - cache.put(1, 2); - Assertions.assertEquals(2, cache.get(1)); - Assertions.assertEquals(6, cache.get(2)); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BinaryTreeTests.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BinaryTreeTests.java deleted file mode 100644 index 140f3f2..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BinaryTreeTests.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.github.dunwu.algorithm.tree; - -import io.github.dunwu.algorithm.common.JavaCollectionTest; -import io.github.dunwu.algorithm.common.TreeTest; -import io.github.dunwu.algorithm.common.Utils; -import org.junit.jupiter.api.Test; - -import java.util.Collection; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class BinaryTreeTests { - - @Test - public void testBTree() { - Utils.TestData data = Utils.generateTestData(1000); - - String bstName = "B-Tree"; - BinaryTree bst = new BinaryTree(2); - Collection bstCollection = bst.toCollection(); - - assertTrue(TreeTest.testTree(bst, Integer.class, bstName, data.unsorted, data.invalid)); - assertTrue(JavaCollectionTest.testCollection(bstCollection, Integer.class, bstName, data.unsorted, data.sorted, - data.invalid)); - } - -} From 5fb7476fd18ee852e56c100573678ca8a90c7ab1 Mon Sep 17 00:00:00 2001 From: dunwu Date: Thu, 13 Nov 2025 07:42:18 +0800 Subject: [PATCH 11/21] =?UTF-8?q?feat:=20leetcode=20=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 300 +++++++++++++----- ...\350\247\243\346\225\260\347\213\254.java" | 44 --- ...\346\217\222\345\205\245\345\231\250.java" | 70 ++++ ...\350\275\254\347\233\230\351\224\201.java" | 102 ++++++ ...\345\233\240\345\217\230\345\214\226.java" | 100 ++++++ ...\347\232\204\346\251\230\345\255\220.java" | 108 +++++++ ...\346\210\267\345\220\210\345\271\266.java" | 37 +++ ...\347\232\204\345\207\272\345\217\243.java" | 94 ++++++ ...\345\222\214\346\210\277\351\227\264.java" | 58 ++++ ...\345\261\277\346\225\260\351\207\217.java" | 78 +++++ ...\345\244\247\351\235\242\347\247\257.java" | 69 ++++ ...\345\255\220\345\262\233\345\261\277.java" | 93 ++++++ ...\347\232\204\346\225\260\347\233\256.java" | 92 ++++++ ...\347\232\204\346\225\260\351\207\217.java" | 80 +++++ ...\345\205\250\346\216\222\345\210\227.java" | 29 +- ...345\205\250\346\216\222\345\210\2272.java" | 59 ++++ .../dfs/\345\255\220\351\233\206.java" | 59 ++++ .../dfs/\345\255\220\351\233\2062.java" | 76 +++++ ...\346\257\215\347\273\204\345\220\210.java" | 51 +++ .../dfs/\347\273\204\345\220\210.java" | 58 ++++ ...\345\220\210\346\200\273\345\222\214.java" | 66 ++++ ...345\220\210\346\200\273\345\222\2142.java" | 79 +++++ ...345\220\210\346\200\273\345\222\2143.java" | 85 +++++ ...\350\247\243\346\225\260\347\213\254.java" | 88 +++++ ...\347\232\204\346\225\260\345\255\227.java" | 50 +++ .../dunwu/algorithm/dp/fib/package-info.java | 7 + ...\347\210\254\346\245\274\346\242\257.java" | 37 +++ ...\345\276\227\347\202\271\346\225\260.java" | 51 +++ ...\345\256\266\345\212\253\350\210\215.java" | 67 ++++ ...\351\202\243\345\245\221\346\225\260.java" | 110 +++++++ ...\347\210\254\346\245\274\346\242\257.java" | 71 +++++ ...\351\202\243\345\245\221\346\225\260.java" | 37 +++ .../algorithm/dp/matrix/package-info.java | 7 + ...\350\267\257\345\276\204\345\222\214.java" | 51 +++ ...\346\234\200\345\260\217\345\222\214.java" | 54 ++++ ...\345\220\214\350\267\257\345\276\204.java" | 39 +++ ...345\220\214\350\267\257\345\276\2042.java" | 69 ++++ ...\346\255\243\346\226\271\345\275\242.java" | 56 ++++ ...\350\267\257\345\276\204\345\222\214.java" | 40 +++ .../{dynamic => dp}/package-info.java | 2 +- ...\344\275\263\346\227\266\346\234\272.java" | 2 +- ...44\275\263\346\227\266\346\234\272II.java" | 2 +- ...4\275\263\346\227\266\346\234\272III.java" | 2 +- ...44\275\263\346\227\266\346\234\272IV.java" | 2 +- ...\346\211\213\347\273\255\350\264\271.java" | 2 +- ...\345\206\267\345\206\273\346\234\237.java" | 2 +- ...\345\255\220\345\272\217\345\210\227.java" | 52 +++ ...\345\255\220\345\272\217\345\222\214.java" | 5 +- ...\345\255\220\345\272\217\345\210\227.java" | 5 +- ...\345\255\220\345\272\217\345\210\227.java" | 57 ++++ ...\345\255\220\345\272\217\345\210\227.java" | 46 +++ ...\345\210\222\346\250\241\346\235\277.java" | 25 ++ ...\351\231\244\346\223\215\344\275\234.java" | 57 ++++ ...\345\255\220\346\225\260\347\273\204.java" | 2 +- ...\345\222\214\345\255\220\351\233\206.java" | 55 ++++ ...\346\225\260\347\273\204\345\222\214.java" | 41 +++ ...\350\276\221\350\267\235\347\246\273.java" | 63 ++++ ...\351\222\261\345\205\221\346\215\242.java" | 83 +++++ ...351\222\261\345\205\221\346\215\2422.java" | 43 +++ .../dunwu/algorithm/dynamic/MaxSubArray.java | 38 --- ...\350\267\257\345\276\204\345\222\214.java" | 101 ------ ...\345\255\220\345\272\217\345\210\227.java" | 39 --- ...\347\210\254\346\245\274\346\242\257.java" | 63 ---- ...\350\276\221\350\267\235\347\246\273.java" | 38 --- ...\351\222\261\345\205\221\346\215\242.java" | 39 --- .../io/github/dunwu/algorithm/graph/Edge.java | 16 + .../github/dunwu/algorithm/graph/Graph.java | 25 ++ .../github/dunwu/algorithm/graph/State.java | 17 + .../github/dunwu/algorithm/graph/Vertex.java | 11 + ...\351\201\215\345\216\206\345\233\276.java" | 87 +++++ ...\346\234\211\350\212\202\347\202\271.java" | 32 +- ...\346\211\200\346\234\211\350\276\271.java" | 45 +++ ...\345\256\236\347\216\260\345\233\276.java" | 138 ++++++++ ...\345\256\236\347\216\260\345\233\276.java" | 159 ++++++++++ ...\347\232\204\350\267\257\345\276\204.java" | 9 +- ...\350\267\203\346\270\270\346\210\217.java" | 57 ++++ ...350\267\203\346\270\270\346\210\2172.java" | 31 ++ .../io/github/dunwu/algorithm/tree/Node.java | 11 + .../io/github/dunwu/algorithm/tree/State.java | 15 + ...\345\216\206\346\241\206\346\236\266.java" | 76 ++++- .../dunwu/algorithm/util/ArrayUtil.java | 32 +- 81 files changed, 3853 insertions(+), 495 deletions(-) delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\350\247\243\346\225\260\347\213\254.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\211\223\345\274\200\350\275\254\347\233\230\351\224\201.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\234\200\345\260\217\345\237\272\345\233\240\345\217\230\345\214\226.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\205\220\347\203\202\347\232\204\346\251\230\345\255\220.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\351\222\245\345\214\231\345\222\214\346\210\277\351\227\264.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\346\225\260\351\207\217.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\255\220\345\262\233\345\261\277.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\260\201\351\227\255\345\262\233\345\261\277\347\232\204\346\225\260\347\233\256.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\351\243\236\345\234\260\347\232\204\346\225\260\351\207\217.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\345\205\250\346\216\222\345\210\227.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\227.java" (59%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\2272.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\206.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\2062.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2142.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2143.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\247\243\346\225\260\347\213\254.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\277\236\347\273\255\345\267\256\347\233\270\345\220\214\347\232\204\346\225\260\345\255\227.java" create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/package-info.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\344\275\277\347\224\250\346\234\200\345\260\217\350\212\261\350\264\271\347\210\254\346\245\274\346\242\257.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\211\223\345\256\266\345\212\253\350\210\215.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\210\254\346\245\274\346\242\257.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\254\254N\344\270\252\346\263\260\346\263\242\351\202\243\345\245\221\346\225\260.java" create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/package-info.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{dynamic => dp}/package-info.java (72%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" (97%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II.java" (96%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272III.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272III.java" (97%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272IV.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272IV.java" (97%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272\345\220\253\346\211\213\347\273\255\350\264\271.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272\345\220\253\346\211\213\347\273\255\350\264\271.java" (96%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.java" (96%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" (86%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227.java" (84%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/template/\345\212\250\346\200\201\350\247\204\345\210\222\346\250\241\346\235\277.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204.java" (97%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\347\274\226\350\276\221\350\267\235\347\246\273.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\242.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\2422.java" delete mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/MaxSubArray.java delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\347\210\254\346\245\274\346\242\257.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\347\274\226\350\276\221\350\267\235\347\246\273.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\351\233\266\351\222\261\345\205\221\346\215\242.java" create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Edge.java create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Graph.java create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/State.java create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Vertex.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/BFS\351\201\215\345\216\206\345\233\276.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\233\276\347\232\204DFS\351\201\215\345\216\206\346\241\206\346\236\266.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\212\202\347\202\271.java" (52%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\347\237\251\351\230\265\345\256\236\347\216\260\345\233\276.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\350\241\250\345\256\236\347\216\260\345\233\276.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\350\267\263\350\267\203\346\270\270\346\210\217.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\350\267\263\350\267\203\346\270\270\346\210\2172.java" create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/Node.java create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/State.java diff --git a/README.md b/README.md index 33ba586..0ae606e 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,9 @@

-

ALGORITHM-TUTORIAL

+

ALGORITHM

-> 💾 algorithm-tutorial 是一个数据结构与算法教程。 +> 💾 algorithm 是一个数据结构与算法学习笔记。 > > 掌握数据结构与算法,你看待问题的深度,解决问题的角度就会完全不一样。 > @@ -113,17 +113,17 @@ #### 数组双指针经典习题 -| 题目 | 掌握度 | -| -------------------------------------------------------------------------------------------------------------------------- | ------ | -| [80. 删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/) | ✔️ | -| [125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/) | ✔️ | -| [75. 颜色分类](https://leetcode.cn/problems/sort-colors/) | ✔️ | -| [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/) | ❗ | -| [977. 有序数组的平方](https://labuladong.online/algo/problem-set/array-two-pointers/#slug_squares-of-a-sorted-array) | ✔️ | -| [1329. 将矩阵按对角线排序](https://labuladong.online/algo/problem-set/array-two-pointers/#slug_sort-the-matrix-diagonally) | ❗ | -| [1260. 二维网格迁移](https://leetcode.cn/problems/shift-2d-grid/) | ❌ | -| [867. 转置矩阵](https://labuladong.online/algo/problem-set/array-two-pointers/#slug_transpose-matrix) | ✔️ | -| [14. 最长公共前缀](https://leetcode.cn/problems/longest-common-prefix/) | ✔️ | +| 题目 | 掌握度 | +| ----------------------------------------------------------------------------------------------------- | ------ | +| [80. 删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/) | ✔️ | +| [125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/) | ✔️ | +| [75. 颜色分类](https://leetcode.cn/problems/sort-colors/) | ✔️ | +| [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/) | ❗ | +| [977. 有序数组的平方](https://leetcode.cn/problems/squares-of-a-sorted-array/) | ✔️ | +| [1329. 将矩阵按对角线排序](https://leetcode.cn/problems/sort-the-matrix-diagonally/) | ❗ | +| [1260. 二维网格迁移](https://leetcode.cn/problems/shift-2d-grid/) | ❌ | +| [867. 转置矩阵](https://leetcode.cn/problems/transpose-matrix/) | ✔️ | +| [14. 最长公共前缀](https://leetcode.cn/problems/longest-common-prefix/) | ✔️ | #### 二维数组的花式遍历技巧 @@ -146,7 +146,7 @@ | [1004. 最大连续 1 的个数 III](https://leetcode.cn/problems/max-consecutive-ones-iii/) | ✔️ | | [424. 替换后的最长重复字符](https://leetcode.cn/problems/longest-repeating-character-replacement/) | ❗ | | [219. 存在重复元素 II](https://leetcode.cn/problems/contains-duplicate-ii/) | ❗ | -| [220. 存在重复元素 III](https://labuladong.online/algo/problem-set/sliding-window/#slug_contains-duplicate-iii) | ❌ | +| [220. 存在重复元素 III](https://leetcode.cn/problems/contains-duplicate-iii/) | ❌ | | [209. 长度最小的子数组](https://leetcode.cn/problems/minimum-size-subarray-sum/) | ❌ | | [395. 至少有 K 个重复字符的最长子串](https://leetcode.cn/problems/longest-substring-with-at-least-k-repeating-characters/) | ❌ | @@ -194,7 +194,7 @@ | [20. 有效的括号](https://leetcode.cn/problems/valid-parentheses/) | ✔️ | | [150. 逆波兰表达式求值](https://leetcode.cn/problems/evaluate-reverse-polish-notation/) | ✔️ | | [388. 文件的最长绝对路径](https://leetcode.cn/problems/longest-absolute-file-path/) | ❌ | -| [155. 最小栈](https://leetcode.cn/problems/min-stack/) | ❌ | +| [155. 最小栈](https://leetcode.cn/problems/min-stack/) | ✔️ | | 最大频率栈](https://leetcode.cn/problems/maximum-frequency-stack/) | ❌ | #### 队列的经典习题 @@ -222,28 +222,38 @@ | ---------------------------------------------------------------------------------------------------- | ------ | | [104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) | ✔️ | | [111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/) | ✔️ | -| [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/) | ✔️ | -| [94. 二叉树的中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal/) | ✔️ | -| [145. 二叉树的后序遍历](https://leetcode.cn/problems/binary-tree-postorder-traversal/) | ✔️ | | [543. 二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree/) | ❌ | -| [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/) | ✔️ | +| [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/) | ❗ | | [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/) | ✔️ | | [654. 最大二叉树](https://leetcode.cn/problems/maximum-binary-tree/) | ✔️ | | [297. 二叉树的序列化与反序列化](https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/) | ❌ | | [222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/) | ✔️ | +#### DFS + +| 题目 | 掌握度 | +| -------------------------------------------------------------------------------------- | ------ | +| [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/) | ✔️ | +| [94. 二叉树的中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal/) | ✔️ | +| [145. 二叉树的后序遍历](https://leetcode.cn/problems/binary-tree-postorder-traversal/) | ✔️ | +| [872. 叶子相似的树](https://leetcode.cn/problems/leaf-similar-trees/) | ✔️ | + #### 用「遍历」思维解题 -| 题目 | 掌握度 | -| ----------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -| [257. 二叉树的所有路径](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_binary-tree-paths) | ❌ | -| [129. 求根节点到叶节点数字之和](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_sum-root-to-leaf-numbers) | ✔️ | -| [199. 二叉树的右视图](https://leetcode.cn/problems/binary-tree-right-side-view/) | ✔️ | -| [988. 从叶结点开始的最小字符串](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_smallest-string-starting-from-leaf) | ✔️ | -| [1022. 从根到叶的二进制数之和](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_sum-of-root-to-leaf-binary-numbers) | ✔️ | -| [1457. 二叉树中的伪回文路径](https://labuladong.online/algo/problem-set/binary-tree-traverse-i/#slug_pseudo-palindromic-paths-in-a-binary-tree) | ✔️ | -| [404. 左叶子之和](https://leetcode.cn/problems/sum-of-left-leaves/) | ✔️ | -| [623. 在二叉树中增加一行](https://leetcode.cn/problems/add-one-row-to-tree/) | ✔️ | +| 题目 | 掌握度 | +| ----------------------------------------------------------------------------------------------------- | ------ | +| [257. 二叉树的所有路径](https://leetcode.cn/problems/binary-tree-paths/) | ✔️ | +| [129. 求根节点到叶节点数字之和](https://leetcode.cn/problems/sum-root-to-leaf-numbers/) | ✔️ | +| [199. 二叉树的右视图](https://leetcode.cn/problems/binary-tree-right-side-view/) | ✔️ | +| [988. 从叶结点开始的最小字符串](https://leetcode.cn/problems/smallest-string-starting-from-leaf/) | ✔️ | +| [1022. 从根到叶的二进制数之和](https://leetcode.cn/problems/sum-of-root-to-leaf-binary-numbers/) | ✔️ | +| [1457. 二叉树中的伪回文路径](https://leetcode.cn/problems/pseudo-palindromic-paths-in-a-binary-tree/) | ✔️ | +| [404. 左叶子之和](https://leetcode.cn/problems/sum-of-left-leaves/) | ✔️ | +| [623. 在二叉树中增加一行](https://leetcode.cn/problems/add-one-row-to-tree/) | ✔️ | +| [508. 出现次数最多的子树元素和](https://leetcode.cn/problems/most-frequent-subtree-sum/) | ❌ | +| [563. 二叉树的坡度](https://leetcode.cn/problems/binary-tree-tilt/) | ❗ | +| [814. 二叉树剪枝](https://leetcode.cn/problems/binary-tree-pruning/) | ❌ | +| [1325. 删除给定值的叶子节点](https://leetcode.cn/problems/delete-leaves-with-a-given-value/) | ✔️ | #### 用「分解」思维解题 @@ -256,61 +266,192 @@ | [894. 所有可能的真二叉树](https://leetcode.cn/problems/all-possible-full-binary-trees/) | ❌ | | [998. 最大二叉树 II](https://leetcode.cn/problems/maximum-binary-tree-ii/) | ❌ | | [1110. 删点成林](https://leetcode.cn/problems/delete-nodes-and-return-forest/) | ❌ | +| [100. 相同的树](https://leetcode.cn/problems/same-tree/) | ✔️ | +| [101. 对称二叉树](https://leetcode.cn/problems/symmetric-tree/) | ✔️ | +| [951. 翻转等价二叉树](https://leetcode.cn/problems/flip-equivalent-binary-trees/) | ❌ | +| [124. 二叉树中的最大路径和](https://leetcode.cn/problems/binary-tree-maximum-path-sum/) | | #### 用「层序遍历」思维解题 -| 题目 | 掌握度 | -| -------------------------------------------------------------------------------------------------------------------------- | ------ | -| [102. 二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal/) | ✔️ | -| [107. 二叉树的层序遍历 II](https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/) | ✔️ | -| [103. 二叉树的锯齿形层序遍历](https://leetcode.cn/problems/binary-tree-zigzag-level-order-traversal/) | ✔️ | -| [116. 填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) | ✔️ | -| [117. 填充每个节点的下一个右侧节点指针 II](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/) | ✔️ | -| [662. 二叉树最大宽度](https://leetcode.cn/problems/maximum-width-of-binary-tree/) | ✔️ | -| [515. 在每个树行中找最大值](https://leetcode.cn/problems/find-largest-value-in-each-tree-row/) | ✔️ | -| [637. 二叉树的层平均值](https://leetcode.cn/problems/average-of-levels-in-binary-tree/) | ✔️ | -| [958. 二叉树的完全性检验](https://leetcode.cn/problems/check-completeness-of-a-binary-tree/) | ✔️ | -| [1161. 最大层内元素和](https://leetcode.cn/problems/maximum-level-sum-of-a-binary-tree/) | ✔️ | -| [1302. 层数最深叶子节点的和](https://leetcode.cn/problems/deepest-leaves-sum/) | ✔️ | -| [1609. 奇偶树](https://leetcode.cn/problems/even-odd-tree/) | ✔️ | -| [429. N 叉树的层序遍历](https://leetcode.cn/problems/n-ary-tree-level-order-traversal/) | | -| [919. 完全二叉树插入器](https://leetcode.cn/problems/complete-binary-tree-inserter/) | | -| [剑指 Offer 32 - II. 从上到下打印二叉树 II](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/) | | -| [剑指 Offer 32 - III. 从上到下打印二叉树 III](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-iii-lcof/) | | -| [剑指 Offer 32 - I. 从上到下打印二叉树](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/) | | +| 题目 | 掌握度 | +| ------------------------------------------------------------------------------------------------------------------------ | ------ | +| [102. 二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal/) | ✔️ | +| [107. 二叉树的层序遍历 II](https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/) | ✔️ | +| [103. 二叉树的锯齿形层序遍历](https://leetcode.cn/problems/binary-tree-zigzag-level-order-traversal/) | ✔️ | +| [116. 填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) | ✔️ | +| [117. 填充每个节点的下一个右侧节点指针 II](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/) | ✔️ | +| [662. 二叉树最大宽度](https://leetcode.cn/problems/maximum-width-of-binary-tree/) | ✔️ | +| [515. 在每个树行中找最大值](https://leetcode.cn/problems/find-largest-value-in-each-tree-row/) | ✔️ | +| [637. 二叉树的层平均值](https://leetcode.cn/problems/average-of-levels-in-binary-tree/) | ✔️ | +| [958. 二叉树的完全性检验](https://leetcode.cn/problems/check-completeness-of-a-binary-tree/) | ✔️ | +| [1161. 最大层内元素和](https://leetcode.cn/problems/maximum-level-sum-of-a-binary-tree/) | ✔️ | +| [1302. 层数最深叶子节点的和](https://leetcode.cn/problems/deepest-leaves-sum/) | ✔️ | +| [1609. 奇偶树](https://leetcode.cn/problems/even-odd-tree/) | ✔️ | +| [429. N 叉树的层序遍历](https://leetcode.cn/problems/n-ary-tree-level-order-traversal/) | ✔️ | +| [919. 完全二叉树插入器](https://leetcode.cn/problems/complete-binary-tree-inserter/) | ❌ | +| [863. 二叉树中所有距离为 K 的结点](https://leetcode.cn/problems/all-nodes-distance-k-in-binary-tree/) | ❌ | +| [LCR 149. 彩灯装饰记录 I](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/) | ✔️ | +| [LCR 150. 彩灯装饰记录 II](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/) | ✔️ | +| [LCR 151. 彩灯装饰记录 III](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-iii-lcof/) | ✔️ | #### 二叉搜索树 -| 题目 | 掌握度 | -| --------------------------------------------------------------------------------------------- | ------ | -| [230. 二叉搜索树中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-bst/) | ❗ | -| [538. 把二叉搜索树转换为累加树](https://leetcode.cn/problems/convert-bst-to-greater-tree/) | ✔️ | -| [450. 删除二叉搜索树中的节点](https://leetcode.cn/problems/delete-node-in-a-bst/) | ❌ | -| [700. 二叉搜索树中的搜索](https://leetcode.cn/problems/search-in-a-binary-search-tree/) | ✔️ | -| [701. 二叉搜索树中的插入操作](https://leetcode.cn/problems/insert-into-a-binary-search-tree/) | ✔️ | -| [98. 验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree/) | ❌ | -| | | -| | | -| | | -| | | -| | | -| | | -| | | +| 题目 | 掌握度 | +| ------------------------------------------------------------------------------------------------------------- | ------ | +| [230. 二叉搜索树中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-bst/) | ✔️ | +| [538. 把二叉搜索树转换为累加树](https://leetcode.cn/problems/convert-bst-to-greater-tree/) | ✔️ | +| [450. 删除二叉搜索树中的节点](https://leetcode.cn/problems/delete-node-in-a-bst/) | ❌ | +| [700. 二叉搜索树中的搜索](https://leetcode.cn/problems/search-in-a-binary-search-tree/) | ✔️ | +| [701. 二叉搜索树中的插入操作](https://leetcode.cn/problems/insert-into-a-binary-search-tree/) | ✔️ | +| [98. 验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree/) | ❗ | +| [96. 不同的二叉搜索树](https://leetcode.cn/problems/unique-binary-search-trees/) | ❌ | +| [95. 不同的二叉搜索树 II](https://leetcode.cn/problems/unique-binary-search-trees-ii/) | ❌ | +| [108. 将有序数组转换为二叉搜索树](https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/) | | +| [783. 二叉搜索树节点最小距离](https://leetcode.cn/problems/minimum-distance-between-bst-nodes/) | ❌ | +| [235. 二叉搜索树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/) | | + +### 图 + +| 题目 | 掌握度 | +| ------------------------------------------------------------------------------------ | ------ | +| [797. 所有可能的路径](https://leetcode.cn/problems/all-paths-from-source-to-target/) | ❌ | +| | | + +#### 二分图判定算法 + +| 题目 | 掌握度 | +| :---------------------------------------------------------------------- | ------ | +| [785. 判断二分图](https://leetcode.cn/problems/is-graph-bipartite/) | ❌ | +| [886. 可能的二分法](https://leetcode.cn/problems/possible-bipartition/) | ❌ | +| [剑指 Offer II 106. 二分图](https://leetcode.cn/problems/vEAB3K/) | ❌ | + +#### 环检测及拓扑排序算法 + +| 题目 | 掌握度 | +| :----------------------------------------------------------------- | ------ | +| [207. 课程表](https://leetcode.cn/problems/course-schedule/) | | +| [210. 课程表 II](https://leetcode.cn/problems/course-schedule-ii/) | | + +### DFS + +子集、组合、排列相关问题,都可以考虑使用回溯算法求解。 + +#### 数独、N 皇后问题 + +| 题目 | 掌握度 | +| :-------------------------------------------------------- | ------ | +| [37. 解数独](https://leetcode.cn/problems/sudoku-solver/) | | +| [51. N 皇后](https://leetcode.cn/problems/n-queens/) | | +| [52. N皇后 II](https://leetcode.cn/problems/n-queens-ii/) | | + +#### 排列、组合、子集问题 + +| 题目 | 掌握度 | +| :--------------------------------------------------------------------- | ------ | +| [77. 组合](https://leetcode.cn/problems/combinations/) | ❌ | +| [78. 子集](https://leetcode.cn/problems/subsets/) | ❌ | +| [90. 子集 II](https://leetcode.cn/problems/subsets-ii/) | ❌ | +| [39. 组合总和](https://leetcode.cn/problems/combination-sum/) | ❌ | +| [40. 组合总和 II](https://leetcode.cn/problems/combination-sum-ii/) | ❌ | +| [216. 组合总和 III](https://leetcode.cn/problems/combination-sum-iii/) | ❌ | +| [46. 全排列](https://leetcode.cn/problems/permutations/) | ❌ | +| [47. 全排列 II](https://leetcode.cn/problems/permutations-ii/) | ❌ | + +#### 岛屿问题 + +| 题目 | 掌握度 | +| :--------------------------------------------------------------------------------- | ------ | +| [1020. 飞地的数量](https://leetcode.cn/problems/number-of-enclaves/) | ❌ | +| [1254. 统计封闭岛屿的数目](https://leetcode.cn/problems/number-of-closed-islands/) | ❌ | +| [1905. 统计子岛屿](https://leetcode.cn/problems/count-sub-islands/) | ❌ | +| [200. 岛屿数量](https://leetcode.cn/problems/number-of-islands/) | ❌ | +| [695. 岛屿的最大面积](https://leetcode.cn/problems/max-area-of-island/) | ❌ | +| [694. 不同岛屿的数量](https://leetcode.cn/problems/number-of-distinct-islands/)🔒 | | + +#### 练习 + +| 题目 | 掌握度 | +| :----------------------------------------------------------------------------------------------- | ------ | +| [967. 连续差相同的数字](https://leetcode.cn/problems/numbers-with-same-consecutive-differences/) | ❌ | +| [491. 递增子序列](https://leetcode.cn/problems/non-decreasing-subsequences/) | | +| [980. 不同路径 III](https://leetcode.cn/problems/unique-paths-iii/) | | +| [131. 分割回文串](https://leetcode.cn/problems/palindrome-partitioning/) | | +| [93. 复原 IP 地址](https://leetcode.cn/problems/restore-ip-addresses/) | | +| [17. 电话号码的字母组合](https://leetcode.cn/problems/letter-combinations-of-a-phone-number/) | ❌ | +| [79. 单词搜索](https://leetcode.cn/problems/word-search/) | | + +### BFS + +| 题目 | 难度 | 掌握度 | +| :----------------------------------------------------------------------------------------------- | :--: | ------ | +| [752. 打开转盘锁](https://leetcode.cn/problems/open-the-lock/) | 💛 | ❌ | +| [773. 滑动谜题](https://leetcode.cn/problems/sliding-puzzle/) | ❤️ | ❌ | +| [919. 完全二叉树插入器](https://leetcode.cn/problems/complete-binary-tree-inserter/) | 💛 | ❗ | +| [841. 钥匙和房间](https://leetcode.cn/problems/keys-and-rooms/) | 💛 | ✔️ | +| [433. 最小基因变化](https://leetcode.cn/problems/minimum-genetic-mutation/) | 💛 | ❗ | +| [1926. 迷宫中离入口最近的出口](https://leetcode.cn/problems/nearest-exit-from-entrance-in-maze/) | 💛 | ✔️ | +| [1091. 二进制矩阵中的最短路径](https://leetcode.cn/problems/shortest-path-in-binary-matrix/) | 💛 | ❌ | +| [994. 腐烂的橘子](https://leetcode.cn/problems/rotting-oranges/) | 💛 | ❌ | +| [721. 账户合并](https://leetcode.cn/problems/accounts-merge/) | 💛 | ❓ | +| [127. 单词接龙](https://leetcode.cn/problems/word-ladder/) | 🔴 | | +| [365. 水壶问题](https://leetcode.cn/problems/water-and-jug-problem/) | 💛 | ❓ | ### 动态规划 -| 题目 | 掌握度 | -| ----------------------------------------------------------------- | ------ | -| [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | | -| [509. 斐波那契数](https://leetcode.cn/problems/fibonacci-number/) | | -| | | +#### 斐波那契 + +| 题目 | 难度 | 掌握度 | +| --------------------------------------------------------------------------------- | :--: | :----: | +| [509. 斐波那契数](https://leetcode.cn/problems/fibonacci-number/) | 💚 | ✔️ | +| [1137. 第 N 个泰波那契数](https://leetcode.cn/problems/n-th-tribonacci-number/) | 💚 | ✔️ | +| [70. 爬楼梯](https://leetcode.cn/problems/climbing-stairs/) | 💚 | ❗ | +| [746. 使用最小花费爬楼梯](https://leetcode.cn/problems/min-cost-climbing-stairs/) | 💚 | ❗ | +| [198. 打家劫舍](https://leetcode.cn/problems/house-robber/) | 💛 | ❌ | +| [740. 删除并获得点数](https://leetcode.cn/problems/delete-and-earn/) | 💛 | ❌ | + +#### 矩阵 + +| 题目 | 难度 | 掌握度 | +| ----------------------------------------------------------------------------- | :--: | :----: | +| [62. 不同路径](https://leetcode.cn/problems/unique-paths/) | 💛 | ❌ | +| [63. 不同路径 II](https://leetcode.cn/problems/unique-paths-ii/) | 💛 | ❌ | +| [64. 最小路径和](https://leetcode.cn/problems/minimum-path-sum/) | 💛 | ✔️ | +| [120. 三角形最小路径和](https://leetcode.cn/problems/triangle/) | 💛 | ❌ | +| [931. 下降路径最小和](https://leetcode.cn/problems/minimum-falling-path-sum/) | 💛 | ❌ | +| [221. 最大正方形](https://leetcode.cn/problems/maximal-square/) | 💛 | ❌ | + +#### 字符串 + +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------------ | :--: | :----: | +| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | | | +| | | | +| | | | +| | | | +| | | | +| | | | + +#### 其他 + +| 题目 | 难度 | 掌握度 | +| ---------------------------------------------------------------------------------------------------------- | ---- | ------ | +| [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | 💛 | ❌ | +| [300. 最长递增子序列](https://leetcode.cn/problems/longest-increasing-subsequence/) | 💛 | ❌ | +| [354. 俄罗斯套娃信封问题](https://leetcode.cn/problems/russian-doll-envelopes/) | ❤️ | | +| [72. 编辑距离](https://leetcode.cn/problems/edit-distance/) | 💛 | ❌ | +| [53. 最大子数组和](https://leetcode.cn/problems/maximum-subarray/) | 💛 | ❌ | +| [712. 两个字符串的最小ASCII删除和](https://leetcode.cn/problems/minimum-ascii-delete-sum-for-two-strings/) | 💛 | ❌ | +| [583. 两个字符串的删除操作](https://leetcode.cn/problems/delete-operation-for-two-strings/) | 💛 | ❌ | +| [1143. 最长公共子序列](https://leetcode.cn/problems/longest-common-subsequence/) | 💛 | ❌ | +| [416. 分割等和子集](https://leetcode.cn/problems/partition-equal-subset-sum/) | | | +| [518. 零钱兑换 II](https://leetcode.cn/problems/coin-change-ii/) | | | ### 贪心算法 -| 题目 | 掌握度 | -| ------------------------------------------------------------- | ------ | -| [55. 跳跃游戏](https://leetcode.cn/problems/jump-game/) | | -| [45. 跳跃游戏 II](https://leetcode.cn/problems/jump-game-ii/) | | +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------------- | ---- | ------ | +| [55. 跳跃游戏](https://leetcode.cn/problems/jump-game/) | 💛 | | +| [45. 跳跃游戏 II](https://leetcode.cn/problems/jump-game-ii/) | 💛 | | ### 分治算法 @@ -327,19 +468,20 @@ - 《编程之法:面试和算法心得》 - 《算法谜题》 都是思维题 - 基础 - - 《[编程珠玑(第 2 版)](https://www.amazon.cn/gp/product/B00SFZH0DC/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00SFZH0DC&linkCode=as2&tag=vastwork-23)》 - - 《[编程珠玑(续)](https://www.amazon.cn/gp/product/B0150BMQDM/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B0150BMQDM&linkCode=as2&tag=vastwork-23)》 - - 《[数据结构与算法分析 : C++描述(第 4 版)](https://www.amazon.cn/gp/product/B01LDG2DSG/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B01LDG2DSG&linkCode=as2&tag=vastwork-23)》 - - 《[数据结构与算法分析 : C 语言描述(第 2 版)](https://www.amazon.cn/gp/product/B002WC7NGS/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B002WC7NGS&linkCode=as2&tag=vastwork-23)》 - - 《[数据结构与算法分析 : Java 语言描述(第 2 版)](https://www.amazon.cn/gp/product/B01CNP0CG6/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B01CNP0CG6&linkCode=as2&tag=vastwork-23)》 - - 《[算法(第 4 版)](https://www.amazon.cn/gp/product/B009OCFQ0O/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B009OCFQ0O&linkCode=as2&tag=vastwork-23)》 + - [《编程珠玑(第 2 版)》](https://www.amazon.cn/gp/product/B00SFZH0DC/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00SFZH0DC&linkCode=as2&tag=vastwork-23) + - [《编程珠玑(续)》](https://www.amazon.cn/gp/product/B0150BMQDM/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B0150BMQDM&linkCode=as2&tag=vastwork-23) + - [《数据结构与算法分析 : C++描述(第 4 版)》](https://www.amazon.cn/gp/product/B01LDG2DSG/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B01LDG2DSG&linkCode=as2&tag=vastwork-23) + - [《数据结构与算法分析 : C 语言描述(第 2 版)》](https://www.amazon.cn/gp/product/B002WC7NGS/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B002WC7NGS&linkCode=as2&tag=vastwork-23) + - [《数据结构与算法分析 : Java 语言描述(第 2 版)》](https://www.amazon.cn/gp/product/B01CNP0CG6/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B01CNP0CG6&linkCode=as2&tag=vastwork-23) + - [《算法(第 4 版)》](https://www.amazon.cn/gp/product/B009OCFQ0O/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B009OCFQ0O&linkCode=as2&tag=vastwork-23) - 算法设计 - - 《[算法设计与分析基础(第 3 版)](https://www.amazon.cn/gp/product/B00S4HCQUI/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00S4HCQUI&linkCode=as2&tag=vastwork-23)》 + - [《算法设计与分析基础(第 3 版)》](https://www.amazon.cn/gp/product/B00S4HCQUI/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00S4HCQUI&linkCode=as2&tag=vastwork-23) - 《Algorithm Design Manual》 - 算法设计手册 红皮书 - [《算法导论》](https://www.amazon.cn/gp/product/B00AK7BYJY/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00AK7BYJY&linkCode=as2&tag=vastwork-23) - 是一本对算法介绍比较全面的经典书籍 - 《Algorithms on Strings,Trees and Sequences》 - 《Advanced Data Structures》 - 各种诡异高级的数据结构和算法 如元胞自动机、斐波纳契堆、线段树 600 块 - **学习网站** + - https://labuladong.online/algo/ - https://github.com/TheAlgorithms/Java - https://github.com/nonstriater/Learn-Algorithms - https://github.com/trekhleb/javascript-algorithms diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\350\247\243\346\225\260\347\213\254.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\350\247\243\346\225\260\347\213\254.java" deleted file mode 100644 index 4f4d548..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\350\247\243\346\225\260\347\213\254.java" +++ /dev/null @@ -1,44 +0,0 @@ -package io.github.dunwu.algorithm.backtrack; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 37. 解数独 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 解数独 { - - public static void main(String[] args) { - Solution s = new Solution(); - char[][] input = new char[][] { { '5', '3', '.', '.', '7', '.', '.', '.', '.' }, - { '6', '.', '.', '1', '9', '5', '.', '.', '.' }, { '.', '9', '8', '.', '.', '.', '.', '6', '.' }, - { '8', '.', '.', '.', '6', '.', '.', '.', '3' }, { '4', '.', '.', '8', '.', '3', '.', '.', '1' }, - { '7', '.', '.', '.', '2', '.', '.', '.', '6' }, { '.', '6', '.', '.', '.', '.', '2', '8', '.' }, - { '.', '.', '.', '4', '1', '9', '.', '.', '5' }, { '.', '.', '.', '.', '8', '.', '.', '7', '9' } }; - char[][] expect = new char[][] { { '5', '3', '4', '6', '7', '8', '9', '1', '2' }, - { '6', '7', '2', '1', '9', '5', '3', '4', '8' }, { '1', '9', '8', '3', '4', '2', '5', '6', '7' }, - { '8', '5', '9', '7', '6', '1', '4', '2', '3' }, { '4', '2', '6', '8', '5', '3', '7', '9', '1' }, - { '7', '1', '3', '9', '2', '4', '8', '5', '6' }, { '9', '6', '1', '5', '3', '7', '2', '8', '4' }, - { '2', '8', '7', '4', '1', '9', '6', '3', '5' }, { '3', '4', '5', '2', '8', '6', '1', '7', '9' } }; - s.solveSudoku(input); - Assertions.assertArrayEquals(expect, input); - } - - static class Solution { - - public void solveSudoku(char[][] board) { - - } - - public void backtrack(char[][] board, LinkedList track, boolean[] used) { - - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" new file mode 100644 index 0000000..e51ebae --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" @@ -0,0 +1,70 @@ +package io.github.dunwu.algorithm.bfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 919. 完全二叉树插入器 + * + * @author Zhang Peng + * @date 2025-11-07 + */ +public class 完全二叉树插入器 { + + public static void main(String[] args) { + CBTInserter c = new CBTInserter(TreeNode.buildTree(1, 2)); + Assertions.assertEquals(1, c.insert(3)); + Assertions.assertEquals(2, c.insert(4)); + Assertions.assertEquals(TreeNode.buildTree(1, 2, 3, 4), c.get_root()); + } + + static class CBTInserter { + + private final TreeNode root; + private final LinkedList candidate; + + public CBTInserter(TreeNode root) { + this.root = root; + this.candidate = new LinkedList<>(); + + LinkedList queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + int size = queue.size(); + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + if (node.left != null) { + queue.offer(node.left); + } + if (node.right != null) { + queue.offer(node.right); + } + if (node.left == null || node.right == null) { + candidate.offer(node); + } + } + } + } + + public int insert(int val) { + TreeNode child = new TreeNode(val); + TreeNode node = candidate.peek(); + if (node.left == null) { + node.left = child; + } else { + node.right = child; + candidate.poll(); + } + candidate.offer(child); + return node.val; + } + + public TreeNode get_root() { + return root; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\211\223\345\274\200\350\275\254\347\233\230\351\224\201.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\211\223\345\274\200\350\275\254\347\233\230\351\224\201.java" new file mode 100644 index 0000000..c6e533c --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\211\223\345\274\200\350\275\254\347\233\230\351\224\201.java" @@ -0,0 +1,102 @@ +package io.github.dunwu.algorithm.bfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * 297. 二叉树的序列化与反序列化 + * + * @author Zhang Peng + * @date 2025-11-06 + */ +public class 打开转盘锁 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + String[] deadends = new String[] { "0201", "0101", "0102", "1212", "2002" }; + Assertions.assertEquals(6, s.openLock(deadends, "0202")); + + // String[] deadends2 = new String[] { "8888" }; + // Assertions.assertEquals(1, s.openLock(deadends2, "0009")); + // + // String[] deadends3 = new String[] { "8887", "8889", "8878", "8898", "8788", "8988", "7888", "9888" }; + // Assertions.assertEquals(-1, s.openLock(deadends3, "8888")); + } + + static class Solution { + + public int openLock(String[] deadends, String target) { + Set black = new HashSet<>(); + for (String d : deadends) { + black.add(d); + } + + int step = 0; + Set visited = new HashSet<>(); + LinkedList queue = new LinkedList<>(); + queue.offer("0000"); + visited.add("0000"); + + while (!queue.isEmpty()) { + int size = queue.size(); + System.out.printf("step: %d\n", step); + for (int i = 0; i < size; i++) { + + String node = queue.poll(); + + if (target.equals(node)) { + return step; + } + + List neighbors = getNeighbors(node); + System.out.printf("\tnode: %s, neighbors: %s\n", node, neighbors); + for (String neighbor : getNeighbors(node)) { + if (!visited.contains(neighbor) && !black.contains(neighbor)) { + queue.offer(neighbor); + visited.add(neighbor); + } + } + } + step++; + } + return -1; + } + + String plus(String s, int i) { + char[] ch = s.toCharArray(); + if (ch[i] == '9') { + ch[i] = '0'; + } else { + ch[i] += 1; + } + return new String(ch); + } + + String minus(String s, int i) { + char[] ch = s.toCharArray(); + if (ch[i] == '0') { + ch[i] = '9'; + } else { + ch[i] -= 1; + } + return new String(ch); + } + + List getNeighbors(String s) { + List neighbors = new LinkedList<>(); + for (int i = 0; i < s.length(); i++) { + neighbors.add(plus(s, i)); + neighbors.add(minus(s, i)); + } + return neighbors; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\234\200\345\260\217\345\237\272\345\233\240\345\217\230\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\234\200\345\260\217\345\237\272\345\233\240\345\217\230\345\214\226.java" new file mode 100644 index 0000000..72fd5e6 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\234\200\345\260\217\345\237\272\345\233\240\345\217\230\345\214\226.java" @@ -0,0 +1,100 @@ +package io.github.dunwu.algorithm.bfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * 433. 最小基因变化 + * + * @author Zhang Peng + * @date 2025-11-07 + */ +public class 最小基因变化 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(1, + s.minMutation("AACCGGTT", "AACCGGTA", new String[] { "AACCGGTA" })); + Assertions.assertEquals(2, + s.minMutation("AACCGGTT", "AAACGGTA", new String[] { "AACCGGTA", "AACCGCTA", "AAACGGTA" })); + Assertions.assertEquals(3, + s.minMutation("AAAAACCC", "AACCCCCC", new String[] { "AAAACCCC", "AAACCCCC", "AACCCCCC" })); + Assertions.assertEquals(-1, + s.minMutation("AACCGGTT", "AACCGGTA", new String[] {})); + Assertions.assertEquals(-1, + s.minMutation("AAAAAAAA", "CCCCCCCC", + new String[] { "AAAAAAAA", "AAAAAAAC", "AAAAAACC", "AAAAACCC", "AAAACCCC", "AACACCCC", "ACCACCCC", + "ACCCCCCC", "CCCCCCCA" })); + } + + static class Solution { + + final char[] options = new char[] { 'A', 'C', 'G', 'T' }; + + public int minMutation(String startGene, String endGene, String[] bank) { + return bfs(startGene, endGene, bank); + } + + public int bfs(String startGene, String endGene, String[] bank) { + + Set bankSet = new HashSet<>(Arrays.asList(bank)); + // 最终结果不在有效基因集合中,直接返回 + if (!bankSet.contains(endGene)) { + return -1; + } + + Set visited = new HashSet<>(); + LinkedList queue = new LinkedList<>(); + queue.offer(startGene); + + int step = 0; + while (!queue.isEmpty()) { + int size = queue.size(); + for (int i = 0; i < size; i++) { + String cur = queue.poll(); + if (cur.equals(endGene)) { + return step; + } + + List neighbors = getNeighbors(cur, bankSet); + System.out.printf("%s 的邻居:%s\n", cur, neighbors); + for (String str : neighbors) { + if (visited.contains(str)) { + continue; + } + visited.add(str); + queue.offer(str); + } + } + step++; + } + return -1; + } + + public List getNeighbors(String s, Set bankSet) { + List list = new LinkedList<>(); + char[] ch = s.toCharArray(); + for (int i = 0; i < ch.length; i++) { + char oldChar = ch[i]; + for (char newChar : options) { + if (oldChar != newChar) { + ch[i] = newChar; + String str = new String(ch); + if (bankSet.contains(str)) { + list.add(str); + } + } + } + ch[i] = oldChar; + } + return list; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\205\220\347\203\202\347\232\204\346\251\230\345\255\220.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\205\220\347\203\202\347\232\204\346\251\230\345\255\220.java" new file mode 100644 index 0000000..d81a625 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\205\220\347\203\202\347\232\204\346\251\230\345\255\220.java" @@ -0,0 +1,108 @@ +package io.github.dunwu.algorithm.bfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * 994. 腐烂的橘子 + * + * @author Zhang Peng + * @date 2025-11-07 + */ +public class 腐烂的橘子 { + + public static void main(String[] args) { + Solution s = new Solution(); + + int[][] input1 = new int[][] { { 2, 1, 1 }, { 1, 1, 0 }, { 0, 1, 1 } }; + Assertions.assertEquals(4, s.orangesRotting(input1)); + + int[][] input2 = new int[][] { { 2, 1, 1 }, { 0, 1, 1 }, { 1, 0, 1 } }; + Assertions.assertEquals(-1, s.orangesRotting(input2)); + + int[][] input3 = new int[][] { { 0, 2 } }; + Assertions.assertEquals(0, s.orangesRotting(input3)); + + int[][] input4 = new int[][] { { 1 } }; + Assertions.assertEquals(-1, s.orangesRotting(input4)); + + int[][] input5 = new int[][] { { 1, 2 } }; + Assertions.assertEquals(1, s.orangesRotting(input5)); + } + + static class Solution { + + // 四个方向偏移量(上、下、左、右) + private static final int[][] DIRS = { { 0, 1 }, { 0, -1 }, { -1, 0 }, { 1, 0 } }; + + public int orangesRotting(int[][] grid) { + + int m = grid.length, n = grid[0].length; + + // 1. 初始化:收集腐烂橘子,统计新鲜橘子数量 + int freshNum = 0; + Queue queue = new LinkedList<>(); + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == 2) { + // 腐烂橘子入队(BFS起点) + queue.offer(new int[] { i, j }); + } else if (grid[i][j] == 1) { + freshNum++; + } + } + } + + // 边界情况:无新鲜橘子,直接返回 + if (freshNum == 0) { + return 0; + } + + // BFS 算法框架 + int step = 0; + while (!queue.isEmpty()) { + + // 当前分钟要处理的腐烂橘子数量 + int size = queue.size(); + // 标记当前分钟是否有新鲜橘子腐烂 + boolean hasRotten = false; + + // 处理当前层级所有腐烂橘子 + for (int i = 0; i < size; i++) { + int[] cur = queue.poll(); + + // 遍历四个相邻方向 + for (int[] dir : DIRS) { + int x = cur[0] + dir[0]; + int y = cur[1] + dir[1]; + + // 检查相邻单元格是否合法且为新鲜橘子 + if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1) { + freshNum--; + grid[x][y] = 2; + hasRotten = true; + queue.offer(new int[] { x, y }); + } + } + } + + // 只有当前分钟有橘子腐烂时,才增加层级 + if (hasRotten) { + step++; + } + + // 提前终止:所有新鲜橘子已腐烂,无需继续遍历 + if (freshNum == 0) { + break; + } + } + + // 3. 最终判断:是否所有新鲜橘子都腐烂 + return freshNum == 0 ? step : -1; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" new file mode 100644 index 0000000..b38cb51 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" @@ -0,0 +1,37 @@ +package io.github.dunwu.algorithm.bfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * 721. 账户合并 + * + * @author Zhang Peng + * @date 2025-11-07 + */ +public class 账户合并 { + + public static void main(String[] args) { + Solution solution = new Solution(); + List> input1 = new LinkedList<>(); + input1.add(Arrays.asList("John", "johnsmith@mail.com", "john00@mail.com")); + input1.add(Arrays.asList("John", "johnnybravo@mail.com")); + input1.add(Arrays.asList("John", "johnsmith@mail.com", "john_newyork@mail.com")); + input1.add(Arrays.asList("Mary", "mary@mail.com")); + List> output1 = solution.accountsMerge(input1); + System.out.println("output1: " + output1); + } + + static class Solution { + + public List> accountsMerge(List> accounts) { + return null; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" new file mode 100644 index 0000000..aa8556c --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" @@ -0,0 +1,94 @@ +package io.github.dunwu.algorithm.bfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; + +/** + * 1926. 迷宫中离入口最近的出口 + * + * @author Zhang Peng + * @date 2025-11-07 + */ +public class 迷宫中离入口最近的出口 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + char[][] maze1 = new char[][] { { '+', '+', '.', '+' }, { '.', '.', '.', '+' }, { '+', '+', '+', '.' } }; + int[] entrance1 = new int[] { 1, 2 }; + Assertions.assertEquals(1, s.nearestExit(maze1, entrance1)); + + char[][] maze2 = new char[][] { { '+', '+', '+' }, { '.', '.', '.' }, { '+', '+', '+' } }; + int[] entrance2 = new int[] { 1, 0 }; + Assertions.assertEquals(2, s.nearestExit(maze2, entrance2)); + + char[][] maze3 = new char[][] { { '.', '+' } }; + int[] entrance3 = new int[] { 0, 0 }; + Assertions.assertEquals(-1, s.nearestExit(maze3, entrance3)); + + char[][] maze4 = new char[][] { + { '+', '.', '+', '+', '+', '+', '+' }, + { '+', '.', '+', '.', '.', '.', '+' }, + { '+', '.', '+', '.', '+', '.', '+' }, + { '+', '.', '.', '.', '+', '.', '+' }, + { '+', '+', '+', '+', '+', '+', '.' } + }; + int[] entrance4 = new int[] { 0, 1 }; + Assertions.assertEquals(-1, s.nearestExit(maze4, entrance4)); + } + + static class Solution { + + public int nearestExit(char[][] maze, int[] entrance) { + + int M = maze.length, N = maze[0].length; + int[][] dirs = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } }; + + int step = 0; + boolean[][] visited = new boolean[M][N]; + visited[entrance[0]][entrance[1]] = true; + LinkedList queue = new LinkedList<>(); + queue.offer(entrance); + while (!queue.isEmpty()) { + int size = queue.size(); + step++; + // 扩散当前队列中的所有节点 + for (int i = 0; i < size; i++) { + int[] cur = queue.poll(); + // 每个节点都会尝试向上下左右四个方向扩展一步 + for (int[] dir : dirs) { + + int row = cur[0] + dir[0]; + int column = cur[1] + dir[1]; + + // 无效路径,返回 + if (row < 0 || row >= M || column < 0 || column >= N) { + continue; + } + if (visited[row][column]) { + continue; + } + if (maze[row][column] == '+') { + continue; + } + + // 找到出口,退出 + if (row == 0 || row == M - 1 || column == 0 || column == N - 1) { + return step; + } + + visited[row][column] = true; + queue.offer(new int[] { row, column }); + } + } + } + return -1; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\351\222\245\345\214\231\345\222\214\346\210\277\351\227\264.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\351\222\245\345\214\231\345\222\214\346\210\277\351\227\264.java" new file mode 100644 index 0000000..5ac816c --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\351\222\245\345\214\231\345\222\214\346\210\277\351\227\264.java" @@ -0,0 +1,58 @@ +package io.github.dunwu.algorithm.bfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * 841. 钥匙和房间 + * + * @author Zhang Peng + * @date 2025-11-07 + */ +public class 钥匙和房间 { + + public static void main(String[] args) { + Solution s = new Solution(); + + List> input1 = new LinkedList<>(); + input1.add(Collections.singletonList(1)); + input1.add(Collections.singletonList(2)); + input1.add(Collections.singletonList(3)); + input1.add(new LinkedList<>()); + Assertions.assertTrue(s.canVisitAllRooms(input1)); + } + + static class Solution { + + public boolean canVisitAllRooms(List> rooms) { + + Set visited = new HashSet<>(); + LinkedList queue = new LinkedList<>(); + queue.offer(0); + + while (!queue.isEmpty()) { + Integer cur = queue.poll(); + if (visited.contains(cur)) { + continue; + } + visited.add(cur); + if (visited.size() == rooms.size()) { + return true; + } + + for (Integer room : rooms.get(cur)) { + queue.offer(room); + } + } + + return false; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\346\225\260\351\207\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\346\225\260\351\207\217.java" new file mode 100644 index 0000000..4733c62 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\346\225\260\351\207\217.java" @@ -0,0 +1,78 @@ +package io.github.dunwu.algorithm.dfs.island; + +import org.junit.jupiter.api.Assertions; + +/** + * 200. 岛屿数量 + *

+ * 元素不可重复,不可复选 + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 岛屿数量 { + + public static void main(String[] args) { + Solution s = new Solution(); + + char[][] input = new char[][] { + { '1', '1', '1', '1', '0' }, + { '1', '1', '0', '1', '0' }, + { '1', '1', '0', '0', '0' }, + { '0', '0', '0', '0', '0' } + }; + Assertions.assertEquals(1, s.numIslands(input)); + + char[][] input2 = new char[][] { + { '1', '1', '0', '0', '0' }, + { '1', '1', '0', '0', '0' }, + { '0', '0', '1', '0', '0' }, + { '0', '0', '0', '1', '1' } + }; + Assertions.assertEquals(3, s.numIslands(input2)); + } + + static class Solution { + + public int numIslands(char[][] grid) { + + if (grid == null || grid.length == 0 || grid[0].length == 0) { return 0; } + + int res = 0; + int M = grid.length, N = grid[0].length; + + // 遍历 grid + for (int row = 0; row < M; row++) { + for (int column = 0; column < N; column++) { + if (grid[row][column] == '1') { + // 每发现一个岛屿,岛屿数量加一 + res++; + // 然后使用 dfs 将岛屿淹了 + dfs(grid, row, column); + } + } + } + return res; + } + + public void dfs(char[][] grid, int row, int column) { + + // 坐标超过边界,无效 + int M = grid.length, N = grid[0].length; + if (row < 0 || row >= M || column < 0 || column >= N) { return; } + + // 已经是海水了 + if (grid[row][column] == '0') { return; } + // 将 (row, column) 变成海水 + grid[row][column] = '0'; + + // 淹没上下左右的陆地 + dfs(grid, row - 1, column); + dfs(grid, row + 1, column); + dfs(grid, row, column - 1); + dfs(grid, row, column + 1); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.java" new file mode 100644 index 0000000..6fd8187 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.java" @@ -0,0 +1,69 @@ +package io.github.dunwu.algorithm.dfs.island; + +import org.junit.jupiter.api.Assertions; + +/** + * 695. 岛屿的最大面积 + * + * @author Zhang Peng + * @date 2025-11-05 + */ +public class 岛屿的最大面积 { + + public static void main(String[] args) { + Solution s = new Solution(); + + int[][] input = new int[][] { + { 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0 }, + { 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0 }, + { 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 } + }; + Assertions.assertEquals(6, s.maxAreaOfIsland(input)); + + int[][] input2 = new int[][] { + { 0, 0, 0, 0, 0, 0, 0, 0 } + }; + Assertions.assertEquals(0, s.maxAreaOfIsland(input2)); + } + + static class Solution { + + public int maxAreaOfIsland(int[][] grid) { + if (grid == null || grid.length == 0 || grid[0].length == 0) { return 0; } + + int max = 0; + int M = grid.length, N = grid[0].length; + for (int row = 0; row < M; row++) { + for (int column = 0; column < N; column++) { + max = Math.max(max, dfs(grid, row, column)); + } + } + return max; + } + + public int dfs(int[][] grid, int row, int column) { + + // 坐标超过边界,无效 + int M = grid.length, N = grid[0].length; + if (row < 0 || row >= M || column < 0 || column >= N) { return 0; } + + // 已经是海水了 + if (grid[row][column] == 0) { return 0; } + // 将 (row, column) 变成海水 + grid[row][column] = 0; + + // 淹没上下左右的陆地 + return 1 + dfs(grid, row - 1, column) + + dfs(grid, row + 1, column) + + dfs(grid, row, column - 1) + + dfs(grid, row, column + 1); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\255\220\345\262\233\345\261\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\255\220\345\262\233\345\261\277.java" new file mode 100644 index 0000000..2fa0742 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\255\220\345\262\233\345\261\277.java" @@ -0,0 +1,93 @@ +package io.github.dunwu.algorithm.dfs.island; + +import org.junit.jupiter.api.Assertions; + +/** + * 1905. 统计子岛屿 + * + * @author Zhang Peng + * @date 2025-11-05 + */ +public class 统计子岛屿 { + + public static void main(String[] args) { + Solution s = new Solution(); + + int[][] gridA1 = new int[][] { + { 1, 1, 1, 0, 0 }, + { 0, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0 }, + { 1, 1, 0, 1, 1 } + }; + int[][] gridB1 = new int[][] { + { 1, 1, 1, 0, 0 }, + { 0, 0, 1, 1, 1 }, + { 0, 1, 0, 0, 0 }, + { 1, 0, 1, 1, 0 }, + { 0, 1, 0, 1, 0 } + }; + Assertions.assertEquals(3, s.countSubIslands(gridA1, gridB1)); + + int[][] gridA2 = new int[][] { + { 1, 0, 1, 0, 1 }, + { 1, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 0 }, + { 1, 1, 1, 1, 1 }, + { 1, 0, 1, 0, 1 } + }; + int[][] gridB2 = new int[][] { + { 0, 0, 0, 0, 0 }, + { 1, 1, 1, 1, 1 }, + { 0, 1, 0, 1, 0 }, + { 0, 1, 0, 1, 0 }, + { 1, 0, 0, 0, 1 } + }; + Assertions.assertEquals(2, s.countSubIslands(gridA2, gridB2)); + } + + static class Solution { + + public int countSubIslands(int[][] gridA, int[][] gridB) { + int M = gridB.length, N = gridB[0].length; + for (int row = 0; row < M; row++) { + for (int column = 0; column < N; column++) { + if (gridA[row][column] == 0 && gridB[row][column] == 1) { + dfs(gridB, row, column); + } + } + } + + int res = 0; + for (int row = 0; row < M; row++) { + for (int column = 0; column < N; column++) { + if (gridB[row][column] == 1) { + res++; + dfs(gridB, row, column); + } + } + } + return res; + } + + public void dfs(int[][] grid, int row, int column) { + + // 坐标超过边界,无效 + int M = grid.length, N = grid[0].length; + if (row < 0 || row >= M || column < 0 || column >= N) { return; } + + // 已经是海水了 + if (grid[row][column] == 0) { return; } + // 将 (row, column) 变成海水 + grid[row][column] = 0; + + // 淹没上下左右的陆地 + dfs(grid, row - 1, column); + dfs(grid, row + 1, column); + dfs(grid, row, column - 1); + dfs(grid, row, column + 1); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\260\201\351\227\255\345\262\233\345\261\277\347\232\204\346\225\260\347\233\256.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\260\201\351\227\255\345\262\233\345\261\277\347\232\204\346\225\260\347\233\256.java" new file mode 100644 index 0000000..82283c4 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\260\201\351\227\255\345\262\233\345\261\277\347\232\204\346\225\260\347\233\256.java" @@ -0,0 +1,92 @@ +package io.github.dunwu.algorithm.dfs.island; + +import org.junit.jupiter.api.Assertions; + +/** + * 1254. 统计封闭岛屿的数目 + *

+ * 元素不可重复,不可复选 + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 统计封闭岛屿的数目 { + + public static void main(String[] args) { + Solution s = new Solution(); + + int[][] input = new int[][] { + { 1, 1, 1, 1, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 0, 1, 1, 0 }, + { 1, 0, 1, 0, 1, 1, 1, 0 }, + { 1, 0, 0, 0, 0, 1, 0, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 0 } + }; + Assertions.assertEquals(2, s.closedIsland(input)); + + int[][] input2 = new int[][] { + { 1, 1, 1, 1, 1, 1, 1 }, + { 1, 0, 0, 0, 0, 0, 1 }, + { 1, 0, 1, 1, 1, 0, 1 }, + { 1, 0, 1, 0, 1, 0, 1 }, + { 1, 0, 1, 1, 1, 0, 1 }, + { 1, 0, 0, 0, 0, 0, 1 }, + { 1, 1, 1, 1, 1, 1, 1 } + }; + Assertions.assertEquals(2, s.closedIsland(input2)); + } + + static class Solution { + + public int closedIsland(int[][] grid) { + + if (grid == null || grid.length == 0 || grid[0].length == 0) { return 0; } + + int M = grid.length, N = grid[0].length; + + for (int column = 0; column < N; column++) { + dfs(grid, 0, column); + dfs(grid, M - 1, column); + } + + for (int row = 0; row < M; row++) { + dfs(grid, row, 0); + dfs(grid, row, N - 1); + } + + // 遍历 grid + int res = 0; + for (int row = 0; row < M; row++) { + for (int column = 0; column < N; column++) { + if (grid[row][column] == 0) { + // 每发现一个岛屿,岛屿数量加一 + res++; + // 然后使用 dfs 将岛屿淹了 + dfs(grid, row, column); + } + } + } + return res; + } + + public void dfs(int[][] grid, int row, int column) { + + // 坐标超过边界,无效 + int M = grid.length, N = grid[0].length; + if (row < 0 || row >= M || column < 0 || column >= N) { return; } + + // 已经是海水了 + if (grid[row][column] == 1) { return; } + // 将 (row, column) 变成海水 + grid[row][column] = 1; + + // 淹没上下左右的陆地 + dfs(grid, row - 1, column); + dfs(grid, row + 1, column); + dfs(grid, row, column - 1); + dfs(grid, row, column + 1); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\351\243\236\345\234\260\347\232\204\346\225\260\351\207\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\351\243\236\345\234\260\347\232\204\346\225\260\351\207\217.java" new file mode 100644 index 0000000..c24224d --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\351\243\236\345\234\260\347\232\204\346\225\260\351\207\217.java" @@ -0,0 +1,80 @@ +package io.github.dunwu.algorithm.dfs.island; + +import org.junit.jupiter.api.Assertions; + +/** + * 1020. 飞地的数量/a> + *

+ * 元素不可重复,不可复选 + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 飞地的数量 { + + public static void main(String[] args) { + Solution s = new Solution(); + + int[][] input = new int[][] { + { 0, 0, 0, 0 }, + { 1, 0, 1, 0 }, + { 0, 1, 1, 0 }, + { 0, 0, 0, 0 } + }; + Assertions.assertEquals(3, s.numEnclaves(input)); + + int[][] input2 = new int[][] { + { 0, 1, 1, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 0 } + }; + Assertions.assertEquals(0, s.numEnclaves(input2)); + } + + static class Solution { + + public int numEnclaves(int[][] grid) { + + int M = grid.length, N = grid[0].length; + for (int i = 0; i < M; i++) { + dfs(grid, i, 0); + dfs(grid, i, N - 1); + } + for (int i = 0; i < N; i++) { + dfs(grid, 0, i); + dfs(grid, M - 1, i); + } + + int res = 0; + for (int i = 0; i < M; i++) { + for (int j = 0; j < N; j++) { + if (grid[i][j] == 1) { + res++; + } + } + } + return res; + } + + public void dfs(int[][] grid, int row, int column) { + + // 坐标超过边界,无效 + int M = grid.length, N = grid[0].length; + if (row < 0 || row >= M || column < 0 || column >= N) { return; } + + // 已经是海水了 + if (grid[row][column] == 0) { return; } + // 将 (row, column) 变成海水 + grid[row][column] = 0; + + // 淹没上下左右的陆地 + dfs(grid, row - 1, column); + dfs(grid, row + 1, column); + dfs(grid, row, column - 1); + dfs(grid, row, column + 1); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\345\205\250\346\216\222\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\227.java" similarity index 59% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\345\205\250\346\216\222\345\210\227.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\227.java" index 40279c8..9e9a5f0 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/backtrack/\345\205\250\346\216\222\345\210\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\227.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.backtrack; +package io.github.dunwu.algorithm.dfs; import java.util.LinkedList; import java.util.List; @@ -20,37 +20,30 @@ public static void main(String[] args) { static class Solution { - private List> res = null; + private LinkedList track = null; + private LinkedList> res = null; + private boolean[] used = null; public List> permute(int[] nums) { - // 记录「路径」 - LinkedList track = new LinkedList<>(); - // 「路径」中的元素会被标记为 true,避免重复使用 - boolean[] used = new boolean[nums.length]; + track = new LinkedList<>(); res = new LinkedList<>(); - backtrack(nums, track, used); + used = new boolean[nums.length]; + backtrack(nums); return res; } - public void backtrack(int[] nums, LinkedList track, boolean[] used) { + public void backtrack(int[] nums) { if (track.size() == nums.length) { res.add(new LinkedList<>(track)); + // System.out.printf("\t=> %s\n", res); return; } for (int i = 0; i < nums.length; i++) { - if (used[i]) { - continue; - } - - // 选择 + if (used[i]) { continue; } track.addLast(nums[i]); used[i] = true; - - // 进入下一层决策树 - backtrack(nums, track, used); - - // 取消选择 + backtrack(nums); track.removeLast(); used[i] = false; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\2272.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\2272.java" new file mode 100644 index 0000000..3a6ac26 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\2272.java" @@ -0,0 +1,59 @@ +package io.github.dunwu.algorithm.dfs; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 47. 全排列 II + * LCR 084. 全排列 II + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 全排列2 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[] input = new int[] { 1, 2, 3 }; + List> output = s.permuteUnique(input); + System.out.println("output: " + output); + } + + static class Solution { + + private LinkedList track = null; + private LinkedList> res = null; + private boolean[] used = null; + + public List> permuteUnique(int[] nums) { + track = new LinkedList<>(); + res = new LinkedList<>(); + used = new boolean[nums.length]; + Arrays.sort(nums); + backtrack(nums); + return res; + } + + public void backtrack(int[] nums) { + if (track.size() == nums.length) { + res.add(new LinkedList<>(track)); + // System.out.printf("\t=> %s\n", res); + return; + } + + for (int i = 0; i < nums.length; i++) { + if (used[i]) { continue;} + if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) { continue;} + + track.addLast(nums[i]); + used[i] = true; + backtrack(nums); + track.removeLast(); + used[i] = false; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\206.java" new file mode 100644 index 0000000..20f21f2 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\206.java" @@ -0,0 +1,59 @@ +package io.github.dunwu.algorithm.dfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 78. 子集 + *

+ * 元素不可重复,不可复选 + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 子集 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[] input = new int[] { 1, 2, 3 }; + Integer[][] expect = new Integer[][] { {}, { 1 }, { 2 }, { 1, 2 }, { 3 }, { 1, 3 }, { 2, 3 }, { 1, 2, 3 } }; + List> output = s.subsets(input); + Assertions.assertEquals(expect.length, output.size()); + System.out.println("output: " + output); + } + + static class Solution { + + // 记录回溯算法的递归路径 + LinkedList track = null; + List> res = null; + + public List> subsets(int[] nums) { + track = new LinkedList<>(); + res = new LinkedList<>(); + backtrack(nums, 0); + return res; + } + + public void backtrack(int[] nums, int start) { + + // 前序位置,每个节点的值都是一个子集 + res.add(new LinkedList<>(track)); + System.out.printf("\t=> %s\n", res); + + // 回溯算法标准框架 + for (int i = start; i < nums.length; i++) { + // 做选择 + track.addLast(nums[i]); + // 通过 start 参数控制树枝的遍历,避免产生重复的子集 + backtrack(nums, i + 1); + // 撤销选择 + track.removeLast(); + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\2062.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\2062.java" new file mode 100644 index 0000000..038c5ac --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\2062.java" @@ -0,0 +1,76 @@ +package io.github.dunwu.algorithm.dfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 90. 子集 II + *

+ * 元素可重复,不可复选 + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 子集2 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + // int[] input = new int[] { 1, 2, 2 }; + // Integer[][] expect = new Integer[][] { {}, { 1 }, { 1, 2 }, { 1, 2, 2 }, { 2 }, { 2, 2 } }; + // List> output = s.subsetsWithDup(input); + // Assertions.assertEquals(expect.length, output.size()); + // System.out.println("output: " + output); + + int[] input2 = new int[] { 4, 4, 4, 1, 4 }; + Integer[][] expect2 = + new Integer[][] { {}, { 1 }, { 1, 4 }, { 1, 4, 4 }, { 1, 4, 4, 4 }, { 1, 4, 4, 4, 4 }, { 4 }, { 4, 4 }, + { 4, 4, 4 }, { 4, 4, 4, 4 } }; + List> output2 = s.subsetsWithDup(input2); + System.out.println("output: " + output2); + Assertions.assertEquals(expect2.length, output2.size()); + } + + static class Solution { + + // 记录回溯算法的递归路径 + LinkedList track = null; + List> res = null; + + public List> subsetsWithDup(int[] nums) { + track = new LinkedList<>(); + res = new LinkedList<>(); + // 先排序,让相同的元素靠在一起 + Arrays.sort(nums); + backtrack(nums, 0); + return res; + } + + public void backtrack(int[] nums, int start) { + + // 前序位置,每个节点的值都是一个子集 + res.add(new LinkedList<>(track)); + // System.out.printf("\t=> %s\n", res); + + // 回溯算法标准框架 + for (int i = start; i < nums.length; i++) { + + // 剪枝逻辑,值相同的相邻树枝,只遍历第一条 + if (i > start && nums[i] == nums[i - 1]) { continue; } + + // 做选择 + track.addLast(nums[i]); + // 通过 start 参数控制树枝的遍历,避免产生重复的子集 + backtrack(nums, i + 1); + // 撤销选择 + track.removeLast(); + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210.java" new file mode 100644 index 0000000..1583633 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210.java" @@ -0,0 +1,51 @@ +package io.github.dunwu.algorithm.dfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * + * @author Zhang Peng + * @date 2025-11-05 + */ +public class 电话号码的字母组合 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new String[] { "ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf" }, + s.letterCombinations("23").toArray()); + Assertions.assertArrayEquals(new String[] { "a","b","c" }, s.letterCombinations("2").toArray()); + Assertions.assertArrayEquals(new String[] { "t","u","v" }, s.letterCombinations("8").toArray()); + } + + static class Solution { + + List res; + StringBuilder sb; + final String[] table = new String[] { "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" }; + + public List letterCombinations(String digits) { + sb = new StringBuilder(); + res = new LinkedList<>(); + backtrack(digits.toCharArray(), 0); + return res; + } + + public void backtrack(char[] nums, int index) { + if (sb.length() == nums.length) { + res.add(sb.toString()); + return; + } + int num = nums[index] - '0'; + for (int i = 0; i < table[num].length(); i++) { + sb.append(table[num].charAt(i)); + backtrack(nums, index + 1); + sb.deleteCharAt(sb.length() - 1); + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210.java" new file mode 100644 index 0000000..32bb539 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210.java" @@ -0,0 +1,58 @@ +package io.github.dunwu.algorithm.dfs; + +import java.util.LinkedList; +import java.util.List; + +/** + * 77. 组合 + *

+ * 元素不可重复,不可复选 + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 组合 { + + public static void main(String[] args) { + Solution s = new Solution(); + List> output = s.combine(4, 2); + System.out.println("output = " + output); + // Assertions.assertArrayEquals(); + } + + static class Solution { + + // 记录回溯算法的递归路径 + LinkedList track = null; + List> res = null; + + public List> combine(int n, int k) { + track = new LinkedList<>(); + res = new LinkedList<>(); + backtrack(1, n, k); + return res; + } + + public void backtrack(int start, int n, int len) { + + // 前序位置,每个节点的值都是一个子集 + if (track.size() == len) { + res.add(new LinkedList<>(track)); + // System.out.printf("\t=> %s\n", res); + return; + } + + // 回溯算法标准框架 + for (int i = start; i <= n; i++) { + // 做选择 + track.addLast(i); + // 通过 start 参数控制树枝的遍历,避免产生重复的子集 + backtrack(i + 1, n, len); + // 撤销选择 + track.removeLast(); + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\214.java" new file mode 100644 index 0000000..c010c0f --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\214.java" @@ -0,0 +1,66 @@ +package io.github.dunwu.algorithm.dfs; + +import java.util.LinkedList; +import java.util.List; + +/** + * 39. 组合总和 + *

+ * 元素不可重复,不可复选 + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 组合总和 { + + public static void main(String[] args) { + Solution s = new Solution(); + List> output = s.combinationSum(new int[] { 2, 3, 6, 7 }, 7); + System.out.println("output = " + output); + } + + static class Solution { + + // 记录回溯算法的递归路径 + LinkedList track = null; + List> res = null; + // 记录 track 中的元素之和 + int sum = 0; + + public List> combinationSum(int[] candidates, int target) { + track = new LinkedList<>(); + res = new LinkedList<>(); + sum = 0; + backtrack(candidates, 0, target); + return res; + } + + public void backtrack(int[] nums, int start, int taget) { + + // 前序位置,每个节点的值都是一个子集 + if (sum == taget) { + res.add(new LinkedList<>(track)); + System.out.printf("\t=> %s\n", res); + return; + } + + if (sum > taget) { + return; + } + + // 回溯算法标准框架 + for (int i = start; i < nums.length; i++) { + // 做选择 + track.addLast(nums[i]); + sum += nums[i]; + // 通过 start 参数控制树枝的遍历,避免产生重复的子集 + backtrack(nums, i, taget); + // 撤销选择 + track.removeLast(); + sum -= nums[i]; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2142.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2142.java" new file mode 100644 index 0000000..6faf5e4 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2142.java" @@ -0,0 +1,79 @@ +package io.github.dunwu.algorithm.dfs; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 40. 组合总和 II + * LCR 082. 组合总和 II + *

+ * 元素不可重复,不可复选 + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 组合总和2 { + + public static void main(String[] args) { + Solution s = new Solution(); + List> output = s.combinationSum2(new int[] { 10, 1, 2, 7, 6, 1, 5 }, 8); + System.out.println("output = " + output); + // 期望输出: + // [ + // [1,1,6], + // [1,2,5], + // [1,7], + // [2,6] + // ] + } + + static class Solution { + + // 记录回溯算法的递归路径 + LinkedList track = null; + List> res = null; + // 记录 track 中的元素之和 + int sum = 0; + + public List> combinationSum2(int[] candidates, int target) { + track = new LinkedList<>(); + res = new LinkedList<>(); + sum = 0; + Arrays.sort(candidates); + backtrack(candidates, 0, target); + return res; + } + + public void backtrack(int[] nums, int start, int taget) { + + // 前序位置,每个节点的值都是一个子集 + if (sum == taget) { + res.add(new LinkedList<>(track)); + // System.out.printf("\t=> %s\n", res); + return; + } + + if (sum > taget) { + return; + } + + // 回溯算法标准框架 + for (int i = start; i < nums.length; i++) { + + if (i > start && nums[i] == nums[i - 1]) { continue; } + + // 做选择 + track.addLast(nums[i]); + sum += nums[i]; + // 通过 start 参数控制树枝的遍历,避免产生重复的子集 + backtrack(nums, i + 1, taget); + // 撤销选择 + track.removeLast(); + sum -= nums[i]; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2143.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2143.java" new file mode 100644 index 0000000..944c523 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2143.java" @@ -0,0 +1,85 @@ +package io.github.dunwu.algorithm.dfs; + +import java.util.LinkedList; +import java.util.List; + +/** + * 216. 组合总和 III + *

+ * 元素不可重复,不可复选 + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 组合总和3 { + + public static void main(String[] args) { + Solution s = new Solution(); + List> output = s.combinationSum3(3, 7); + System.out.println("output = " + output); + // 期望输出: + // [ + // [1,2,4] + // ] + + List> output2 = s.combinationSum3(3, 9); + System.out.println("output = " + output2); + // 期望输出: + // [[1,2,6], [1,3,5], [2,3,4]] + + List> output3 = s.combinationSum3(4, 1); + System.out.println("output = " + output3); + // 期望输出: + // [] + } + + static class Solution { + + // 记录回溯算法的递归路径 + LinkedList track = null; + List> res = null; + // 记录 track 中的元素之和 + int sum = 0; + + public List> combinationSum3(int k, int n) { + track = new LinkedList<>(); + res = new LinkedList<>(); + int[] nums = new int[9]; + for (int i = 0; i < 9; i++) { + nums[i] = i + 1; + } + backtrack(nums, 0, k, n); + return res; + } + + public void backtrack(int[] nums, int start, int len, int taget) { + + // 前序位置,每个节点的值都是一个子集 + if (sum == taget && track.size() == len) { + res.add(new LinkedList<>(track)); + // System.out.printf("\t=> %s\n", res); + return; + } + + // 剪枝 + if (sum > taget || track.size() > len) { + return; + } + + // 回溯算法标准框架 + for (int i = start; i < nums.length; i++) { + + // 做选择 + track.addLast(nums[i]); + sum += nums[i]; + // 通过 start 参数控制树枝的遍历,避免产生重复的子集 + backtrack(nums, i + 1, len, taget); + // 撤销选择 + track.removeLast(); + sum -= nums[i]; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\247\243\346\225\260\347\213\254.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\247\243\346\225\260\347\213\254.java" new file mode 100644 index 0000000..5e9a7e1 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\247\243\346\225\260\347\213\254.java" @@ -0,0 +1,88 @@ +package io.github.dunwu.algorithm.dfs; + +import org.junit.jupiter.api.Assertions; + +/** + * 37. 解数独 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 解数独 { + + public static void main(String[] args) { + Solution s = new Solution(); + char[][] input = new char[][] { { '5', '3', '.', '.', '7', '.', '.', '.', '.' }, + { '6', '.', '.', '1', '9', '5', '.', '.', '.' }, { '.', '9', '8', '.', '.', '.', '.', '6', '.' }, + { '8', '.', '.', '.', '6', '.', '.', '.', '3' }, { '4', '.', '.', '8', '.', '3', '.', '.', '1' }, + { '7', '.', '.', '.', '2', '.', '.', '.', '6' }, { '.', '6', '.', '.', '.', '.', '2', '8', '.' }, + { '.', '.', '.', '4', '1', '9', '.', '.', '5' }, { '.', '.', '.', '.', '8', '.', '.', '7', '9' } }; + char[][] expect = new char[][] { { '5', '3', '4', '6', '7', '8', '9', '1', '2' }, + { '6', '7', '2', '1', '9', '5', '3', '4', '8' }, { '1', '9', '8', '3', '4', '2', '5', '6', '7' }, + { '8', '5', '9', '7', '6', '1', '4', '2', '3' }, { '4', '2', '6', '8', '5', '3', '7', '9', '1' }, + { '7', '1', '3', '9', '2', '4', '8', '5', '6' }, { '9', '6', '1', '5', '3', '7', '2', '8', '4' }, + { '2', '8', '7', '4', '1', '9', '6', '3', '5' }, { '3', '4', '5', '2', '8', '6', '1', '7', '9' } }; + s.solveSudoku(input); + Assertions.assertArrayEquals(expect, input); + } + + static class Solution { + + boolean found = false; + + public void solveSudoku(char[][] nums) { + found = false; + backtrack(nums, 0); + } + + public void backtrack(char[][] nums, int index) { + + if (found) { return; } + + int m = 9, n = 9; + int i = index / n, j = index % n; + if (index == m * n) { + found = true; + return; + } + + if (nums[i][j] != '.') { + backtrack(nums, index + 1); + return; + } + + for (char ch = '1'; ch <= '9'; ch++) { + // 剪枝:如果遇到不合法的数字,就跳过 + if (!isValid(nums, i, j, ch)) { continue; } + + // 做选择 + nums[i][j] = ch; + + backtrack(nums, index + 1); + if (found) { + // 如果找到一个可行解,立即结束 + // 不要撤销选择,否则 board[i][j] 会被重置为 '.' + return; + } + + // 撤销选择 + nums[i][j] = '.'; + } + } + + // 判断是否可以在 (r, c) 位置放置数字 num + boolean isValid(char[][] board, int row, int column, char num) { + for (int i = 0; i < 9; i++) { + // 判断行是否存在重复 + if (board[row][i] == num) return false; + // 判断列是否存在重复 + if (board[i][column] == num) return false; + // 判断 3 x 3 方框是否存在重复 + if (board[(row / 3) * 3 + i / 3][(column / 3) * 3 + i % 3] == num) { return false; } + } + return true; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\277\236\347\273\255\345\267\256\347\233\270\345\220\214\347\232\204\346\225\260\345\255\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\277\236\347\273\255\345\267\256\347\233\270\345\220\214\347\232\204\346\225\260\345\255\227.java" new file mode 100644 index 0000000..01480a0 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\277\236\347\273\255\345\267\256\347\233\270\345\220\214\347\232\204\346\225\260\345\255\227.java" @@ -0,0 +1,50 @@ +package io.github.dunwu.algorithm.dfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * + * @author Zhang Peng + * @date 2025-11-05 + */ +public class 连续差相同的数字 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new int[] { 181, 292, 707, 818, 929 }, s.numsSameConsecDiff(3, 7)); + } + + static class Solution { + + int track = 0; + int digit = 0; + LinkedList res = null; + + public int[] numsSameConsecDiff(int n, int k) { + res = new LinkedList<>(); + backtrack(n, k); + return res.stream().mapToInt(Integer::intValue).toArray(); + } + + public void backtrack(int n, int k) { + if (digit == n) { + res.addLast(track); + return; + } + + for (int i = 0; i <= 9; i++) { + if (digit == 0 && i == 0) { continue; } + if (digit > 0 && Math.abs(i - track % 10) != k) { continue; } + digit++; + track = track * 10 + i; + backtrack(n, k); + track = track / 10; + digit--; + } + } + + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/package-info.java new file mode 100644 index 0000000..1e7cb09 --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/package-info.java @@ -0,0 +1,7 @@ +/** + * 动态规划 - 斐波那契类型 + * + * @author Zhang Peng + * @date 2025-11-12 + */ +package io.github.dunwu.algorithm.dp.fib; \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\344\275\277\347\224\250\346\234\200\345\260\217\350\212\261\350\264\271\347\210\254\346\245\274\346\242\257.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\344\275\277\347\224\250\346\234\200\345\260\217\350\212\261\350\264\271\347\210\254\346\245\274\346\242\257.java" new file mode 100644 index 0000000..31f6dc3 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\344\275\277\347\224\250\346\234\200\345\260\217\350\212\261\350\264\271\347\210\254\346\245\274\346\242\257.java" @@ -0,0 +1,37 @@ +package io.github.dunwu.algorithm.dp.fib; + +import org.junit.jupiter.api.Assertions; + +/** + * 746. 使用最小花费爬楼梯 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 使用最小花费爬楼梯 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(15, s.minCostClimbingStairs(new int[] { 10, 15, 20 })); + Assertions.assertEquals(6, s.minCostClimbingStairs(new int[] { 1, 100, 1, 1, 1, 100, 1, 1, 100, 1 })); + } + + static class Solution { + + public int minCostClimbingStairs(int[] cost) { + int n = cost.length; + int dp_i_1 = 0, dp_i_2 = 0, dp_i = 0; + for (int i = 2; i <= n; i++) { + dp_i = Math.min( + dp_i_1 + cost[i - 1], + dp_i_2 + cost[i - 2] + ); + dp_i_2 = dp_i_1; + dp_i_1 = dp_i; + } + return dp_i; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" new file mode 100644 index 0000000..43f9bec --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" @@ -0,0 +1,51 @@ +package io.github.dunwu.algorithm.dp.fib; + +import org.junit.jupiter.api.Assertions; + +/** + * 740. 删除并获得点数 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 删除并获得点数 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(6, s.deleteAndEarn(new int[] { 3, 4, 2 })); + // 删除 4 获得 4 个点数,因此 3 也被删除。 + // 之后,删除 2 获得 2 个点数。总共获得 6 个点数。 + Assertions.assertEquals(9, s.deleteAndEarn(new int[] { 2, 2, 3, 3, 3, 4 })); + // 删除 3 获得 3 个点数,接着要删除两个 2 和 4 。 + // 之后,再次删除 3 获得 3 个点数,再次删除 3 获得 3 个点数。 + // 总共获得 9 个点数。 + } + + static class Solution { + + public int deleteAndEarn(int[] nums) { + int max = 0; + for (int val : nums) { + max = Math.max(max, val); + } + int[] sums = new int[max + 1]; + for (int val : nums) { + sums[val] += val; + } + return rob(sums); + } + + public int rob(int[] sums) { + int N = sums.length; + int first = sums[0], second = Math.max(sums[0], sums[1]); + for (int i = 2; i < N; i++) { + int temp = second; + second = Math.max(second, first + sums[i]); + first = temp; + } + return second; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\211\223\345\256\266\345\212\253\350\210\215.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\211\223\345\256\266\345\212\253\350\210\215.java" new file mode 100644 index 0000000..c6ec2e2 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\211\223\345\256\266\345\212\253\350\210\215.java" @@ -0,0 +1,67 @@ +package io.github.dunwu.algorithm.dp.fib; + +import org.junit.jupiter.api.Assertions; + +/** + * 198. 打家劫舍 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 打家劫舍 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(4, s.rob(new int[] { 1, 2, 3, 1 })); + Assertions.assertEquals(12, s.rob(new int[] { 2, 7, 9, 3, 1 })); + Assertions.assertEquals(1, s.rob(new int[] { 1, 1 })); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals(4, s2.rob(new int[] { 1, 2, 3, 1 })); + Assertions.assertEquals(12, s2.rob(new int[] { 2, 7, 9, 3, 1 })); + Assertions.assertEquals(1, s2.rob(new int[] { 1, 1 })); + } + + static class Solution { + + public int rob(int[] nums) { + + int N = nums.length; + if (N <= 1) { return nums[0]; } + + int[] dp = new int[N + 1]; + dp[0] = nums[0]; + dp[1] = Math.max(nums[0], nums[1]); + for (int i = 2; i < N; i++) { + dp[i] = Math.max( + dp[i - 1], + dp[i - 2] + nums[i] + ); + } + + return dp[N - 1]; + } + + } + + /** + * 优化空间复杂度 + */ + static class Solution2 { + + public int rob(int[] nums) { + int N = nums.length; + if (N <= 1) { return nums[0]; } + + int cur = Math.max(nums[0], nums[1]), pre = nums[0]; + for (int i = 2; i < N; i++) { + int tmp = Math.max(cur, pre + nums[i]); + pre = cur; + cur = tmp; + } + return cur; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260.java" new file mode 100644 index 0000000..a2bc7f4 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260.java" @@ -0,0 +1,110 @@ +package io.github.dunwu.algorithm.dp.fib; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 509. 斐波那契数 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 斐波那契数 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(1, s.fib(2)); + Assertions.assertEquals(2, s.fib(3)); + Assertions.assertEquals(3, s.fib(4)); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals(1, s2.fib(2)); + Assertions.assertEquals(2, s2.fib(3)); + Assertions.assertEquals(3, s2.fib(4)); + + Solution2 s3 = new Solution2(); + Assertions.assertEquals(1, s3.fib(2)); + Assertions.assertEquals(2, s3.fib(3)); + Assertions.assertEquals(3, s3.fib(4)); + } + + /** + * 使用备忘录优化动态规划问题 + */ + static class Solution { + + int fib(int n) { + // 备忘录全初始化为 -1 + // 因为斐波那契数肯定是非负整数,所以初始化为特殊值 -1 表示未计算 + + // 因为数组的索引从 0 开始,所以需要 n + 1 个空间 + // 这样才能把 `f(0) ~ f(n)` 都记录到 memo 中 + int[] memo = new int[n + 1]; + Arrays.fill(memo, -1); + + return dp(memo, n); + } + + // 带着备忘录进行递归 + int dp(int[] memo, int n) { + // base case + if (n == 0 || n == 1) { + return n; + } + // 已经计算过,不用再计算了 + if (memo[n] != -1) { + return memo[n]; + } + // 在返回结果之前,存入备忘录 + memo[n] = dp(memo, n - 1) + dp(memo, n - 2); + return memo[n]; + } + + } + + /** + * DP Table 解决动态规划问题 + */ + static class Solution2 { + + int fib(int n) { + if (n == 0 || n == 1) { + return n; + } + + int[] dp = new int[n + 1]; + dp[0] = 0; + dp[1] = 1; + for (int i = 2; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; + } + + } + + /** + * 在 DP Table 基础上优化空间复杂度 + */ + static class Solution3 { + + int fib(int n) { + if (n == 0 || n == 1) { + return n; + } + + // 分别代表 dp[i - 1] 和 dp[i - 2] + int dp_i_1 = 1, dp_i_2 = 0; + for (int i = 2; i <= n; i++) { + // dp[i] = dp[i - 1] + dp[i - 2]; + int dp_i = dp_i_1 + dp_i_2; + dp_i_2 = dp_i_1; + dp_i_1 = dp_i; + } + return dp_i_1; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\210\254\346\245\274\346\242\257.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\210\254\346\245\274\346\242\257.java" new file mode 100644 index 0000000..63c40b8 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\210\254\346\245\274\346\242\257.java" @@ -0,0 +1,71 @@ +package io.github.dunwu.algorithm.dp.fib; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 70. 爬楼梯 + * + * @author Zhang Peng + * @since 2020-07-04 + */ +public class 爬楼梯 { + + public static void main(String[] args) { + + Solution s = new Solution(); + Assertions.assertEquals(1, s.climbStairs(0)); + Assertions.assertEquals(1, s.climbStairs(1)); + Assertions.assertEquals(2, s.climbStairs(2)); + Assertions.assertEquals(3, s.climbStairs(3)); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals(1, s2.climbStairs(0)); + Assertions.assertEquals(1, s2.climbStairs(1)); + Assertions.assertEquals(2, s2.climbStairs(2)); + Assertions.assertEquals(3, s2.climbStairs(3)); + } + + static class Solution { + + int[] memo = null; + + public int climbStairs(int n) { + memo = new int[n + 1]; + Arrays.fill(memo, -1); + return dp(n); + } + + // 爬第n阶楼梯的方法数量,等于 2 部分之和 + // + // 爬上 n−1 阶楼梯的方法数量。因为再爬1阶就能到第n阶 + // 爬上 n−2 阶楼梯的方法数量,因为再爬2阶就能到第n阶 + public int dp(int n) { + if (n == 0) return 1; + if (n == 1) return 1; + if (memo[n] != -1) return memo[n]; + memo[n] = dp(n - 1) + dp(n - 2); + return memo[n]; + } + + } + + static class Solution2 { + + public int climbStairs(int n) { + + if (n == 0 || n == 1) return 1; + + int[] dp = new int[n + 1]; + dp[0] = 1; + dp[1] = 1; + for (int i = 2; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\254\254N\344\270\252\346\263\260\346\263\242\351\202\243\345\245\221\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\254\254N\344\270\252\346\263\260\346\263\242\351\202\243\345\245\221\346\225\260.java" new file mode 100644 index 0000000..87a3c49 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\254\254N\344\270\252\346\263\260\346\263\242\351\202\243\345\245\221\346\225\260.java" @@ -0,0 +1,37 @@ +package io.github.dunwu.algorithm.dp.fib; + +import org.junit.jupiter.api.Assertions; + +/** + * 1137. 第 N 个泰波那契数 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 第N个泰波那契数 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(4, s.tribonacci(4)); + Assertions.assertEquals(1389537, s.tribonacci(25)); + } + + static class Solution { + + public int tribonacci(int n) { + if (n == 0) return 0; + if (n == 1 || n == 2) return 1; + + int[] dp = new int[n + 1]; + dp[0] = 0; + dp[1] = 1; + dp[2] = 1; + for (int i = 3; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]; + } + return dp[n]; + } + + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/package-info.java new file mode 100644 index 0000000..60b8318 --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/package-info.java @@ -0,0 +1,7 @@ +/** + * 动态规划 - 矩阵 + * + * @author Zhang Peng + * @date 2025-11-12 + */ +package io.github.dunwu.algorithm.dp.matrix; \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" new file mode 100644 index 0000000..c11b5b8 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" @@ -0,0 +1,51 @@ +package io.github.dunwu.algorithm.dp.matrix; + +import io.github.dunwu.algorithm.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.List; + +/** + * 120. 三角形最小路径和 + * + * @author Zhang Peng + * @since 2020-07-04 + */ +public class 三角形最小路径和 { + + public static void main(String[] args) { + Solution s = new Solution(); + List> input = ArrayUtil.toListList(new int[][] { { 2 }, { 3, 4 }, { 6, 5, 7 }, { 4, 1, 8, 3 } }); + Assertions.assertEquals(11, s.minimumTotal(input)); + List> input2 = ArrayUtil.toListList(new int[][] { { -10 } }); + Assertions.assertEquals(-10, s.minimumTotal(input2)); + + // 给定一个三角形 triangle ,找出自顶向下的最小路径和。 + + // 每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。 + // 也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。 + } + + static class Solution { + + public int minimumTotal(List> triangle) { + int n = triangle.size(); + int[][] dp = new int[n][n]; + dp[0][0] = triangle.get(0).get(0); + for (int i = 1; i < n; ++i) { + dp[i][0] = dp[i - 1][0] + triangle.get(i).get(0); + for (int j = 1; j < i; ++j) { + dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i - 1][j]) + triangle.get(i).get(j); + } + dp[i][i] = dp[i - 1][i - 1] + triangle.get(i).get(i); + } + int min = dp[n - 1][0]; + for (int i = 1; i < n; ++i) { + min = Math.min(min, dp[n - 1][i]); + } + return min; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" new file mode 100644 index 0000000..cd10af9 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" @@ -0,0 +1,54 @@ +package io.github.dunwu.algorithm.dp.matrix; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 300. 最长递增子序列 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 下降路径最小和 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(13, s.minFallingPathSum(new int[][] { { 2, 1, 3 }, { 6, 5, 4 }, { 7, 8, 9 } })); + } + + static class Solution { + + int N = 0; + int[][] matrix = null; + int[][] memo = null; + + public int minFallingPathSum(int[][] matrix) { + this.matrix = matrix; + this.N = matrix.length; + int res = Integer.MAX_VALUE; + memo = new int[N + 1][N + 1]; + for (int i = 0; i <= N; i++) { + Arrays.fill(memo[i], Integer.MAX_VALUE); + } + for (int y = 0; y < N; y++) { + res = Math.min(res, dp(N - 1, y)); + } + return res; + } + + public int dp(int x, int y) { + if (y < 0 || y >= N) { return Integer.MAX_VALUE; } + if (x == 0) { return matrix[0][y]; } + if (memo[x][y] != Integer.MAX_VALUE) { return memo[x][y]; } + memo[x][y] = matrix[x][y] + min(dp(x - 1, y - 1), dp(x - 1, y), dp(x - 1, y + 1)); + return memo[x][y]; + } + + int min(int a, int b, int c) { + return Math.min(a, Math.min(b, c)); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" new file mode 100644 index 0000000..b897805 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" @@ -0,0 +1,39 @@ +package io.github.dunwu.algorithm.dp.matrix; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 62. 不同路径 + * + * @author Zhang Peng + * @date 2025-11-12 + */ +public class 不同路径 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(28, s.uniquePaths(3, 7)); + Assertions.assertEquals(3, s.uniquePaths(3, 2)); + } + + static class Solution { + + public int uniquePaths(int m, int n) { + int[][] dp = new int[m][n]; + // 沿着边界只有一个前进方向 + for (int i = 0; i < m; i++) { dp[i][0] = 1; } + for (int j = 0; j < n; j++) { dp[0][j] = 1; } + // dp[i][j] 表示到达 (i, j) 的最多路径 + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; + } + } + return dp[m - 1][n - 1]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" new file mode 100644 index 0000000..5adc151 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" @@ -0,0 +1,69 @@ +package io.github.dunwu.algorithm.dp.matrix; + +import org.junit.jupiter.api.Assertions; + +/** + * 62. 不同路径 + * + * @author Zhang Peng + * @date 2025-11-12 + */ +public class 不同路径2 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[][] input1 = new int[][] { { 0, 0, 0 }, { 0, 1, 0 }, { 0, 0, 0 } }; + Assertions.assertEquals(2, s.uniquePathsWithObstacles(input1)); + int[][] input2 = new int[][] { { 0, 1 }, { 0, 0 } }; + Assertions.assertEquals(1, s.uniquePathsWithObstacles(input2)); + int[][] input3 = new int[][] { { 1, 0 } }; + Assertions.assertEquals(0, s.uniquePathsWithObstacles(input3)); + } + + static class Solution { + + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + if (obstacleGrid == null || obstacleGrid.length == 0 || obstacleGrid[0].length == 0) { + return 0; + } + + int m = obstacleGrid.length, n = obstacleGrid[0].length; + + // 如果起点或终点有障碍物,直接返回0 + if (obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1) { + return 0; + } + + // dp[i][j] 表示从起点到 (i,j) 的不同路径数 + int[][] dp = new int[m][n]; + + // 初始化起点 + dp[0][0] = 1; + + // 初始化第一列:只能从上边来 + for (int i = 1; i < m; i++) { + dp[i][0] = (obstacleGrid[i][0] == 1) ? 0 : dp[i - 1][0]; + } + // 初始化第一行:只能从左边来 + for (int j = 1; j < n; j++) { + dp[0][j] = (obstacleGrid[0][j] == 1) ? 0 : dp[0][j - 1]; + } + + // 填充dp表 + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + if (obstacleGrid[i][j] == 1) { + dp[i][j] = 0; // 有障碍物,无法到达 + } else { + // 路径数 = 从上边来的路径数 + 从左边来的路径数 + dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; + } + } + } + + return dp[m - 1][n - 1]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" new file mode 100644 index 0000000..f2c8bd5 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" @@ -0,0 +1,56 @@ +package io.github.dunwu.algorithm.dp.matrix; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 300. 最长递增子序列 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 最大正方形 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(4, s.maximalSquare(new char[][] { + { '1', '0', '1', '0', '0' }, + { '1', '0', '1', '1', '1' }, + { '1', '1', '1', '1', '1' }, + { '1', '0', '0', '1', '0' } + })); + } + + static class Solution { + + public int maximalSquare(char[][] matrix) { + + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { + return 0; + } + + int m = matrix.length, n = matrix[0].length; + int[][] dp = new int[m][n]; + dp[0][0] = matrix[0][0] == '1' ? 1 : 0; + int max = dp[0][0]; + for (int i = 1; i < m; ++i) { + for (int j = 1; j < n; ++j) { + if (matrix[i][j] == '0') { + dp[i][j] = 0; + continue; + } + dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1; + max = Math.max(max, dp[i][j]); + } + } + return max * max; + } + + public int min(int a, int b, int c) { + return Math.min(Math.min(a, b), c); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" new file mode 100644 index 0000000..046d441 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" @@ -0,0 +1,40 @@ +package io.github.dunwu.algorithm.dp.matrix; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 64. 最小路径和 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 最小路径和 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(7, s.minPathSum(new int[][] { { 1, 3, 1 }, { 1, 5, 1 }, { 4, 2, 1 } })); + Assertions.assertEquals(12, s.minPathSum(new int[][] { { 1, 2, 3 }, { 4, 5, 6 } })); + } + + static class Solution { + + public int minPathSum(int[][] grid) { + if (grid == null || grid.length == 0 || grid[0].length == 0) { return 0; } + int m = grid.length, n = grid[0].length; + int[][] dp = new int[m][n]; + dp[0][0] = grid[0][0]; + for (int i = 1; i < m; i++) { dp[i][0] = dp[i - 1][0] + grid[i][0]; } + for (int j = 1; j < n; j++) { dp[0][j] = dp[0][j - 1] + grid[0][j]; } + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + dp[i][j] = Math.min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]; + } + } + return dp[m - 1][n - 1]; + } + + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/package-info.java similarity index 72% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/package-info.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/package-info.java index 567166a..48674a2 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/package-info.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/package-info.java @@ -4,4 +4,4 @@ * @author Zhang Peng * @since 2020-03-06 */ -package io.github.dunwu.algorithm.dynamic; +package io.github.dunwu.algorithm.dp; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" similarity index 97% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" index e8723ba..0ef65ab 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.dynamic; +package io.github.dunwu.algorithm.dp.state; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II.java" index 821d79a..d3d8197 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.dynamic; +package io.github.dunwu.algorithm.dp.state; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272III.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272III.java" similarity index 97% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272III.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272III.java" index e53c7e8..916188a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272III.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272III.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.dynamic; +package io.github.dunwu.algorithm.dp.state; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272IV.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272IV.java" similarity index 97% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272IV.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272IV.java" index 63bab9e..f2bb072 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272IV.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272IV.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.dynamic; +package io.github.dunwu.algorithm.dp.state; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272\345\220\253\346\211\213\347\273\255\350\264\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272\345\220\253\346\211\213\347\273\255\350\264\271.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272\345\220\253\346\211\213\347\273\255\350\264\271.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272\345\220\253\346\211\213\347\273\255\350\264\271.java" index 89d7b43..134b337 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272\345\220\253\346\211\213\347\273\255\350\264\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272\345\220\253\346\211\213\347\273\255\350\264\271.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.dynamic; +package io.github.dunwu.algorithm.dp.state; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.java" index a06adee..9836d29 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.dynamic; +package io.github.dunwu.algorithm.dp.state; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227.java" new file mode 100644 index 0000000..ad63c86 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227.java" @@ -0,0 +1,52 @@ +package io.github.dunwu.algorithm.dp.subseq; + +import org.junit.jupiter.api.Assertions; + +/** + * 392. 判断子序列 + * + * @author Zhang Peng + * @since 2020-07-06 + */ +public class 判断子序列 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.isSubsequence("abc", "ahbgdc")); + Assertions.assertFalse(s.isSubsequence("axc", "ahbgdc")); + Assertions.assertTrue(s.isSubsequence("", "ahbgdc")); + Assertions.assertFalse(s.isSubsequence("aaaaaa", "bbaaaa")); + } + + static class Solution { + + public boolean isSubsequence(String s, String t) { + int m = s.length(), n = t.length(); + + // dp[i][j] 表示 s 的前 i 个字符是否是 t 的前 j 个字符的子序列 + boolean[][] dp = new boolean[m + 1][n + 1]; + + // 初始化:空字符串是任何字符串的子序列 + for (int j = 0; j <= n; j++) { + dp[0][j] = true; + } + + // 动态规划填表 + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= n; j++) { + if (s.charAt(i - 1) == t.charAt(j - 1)) { + // 字符匹配,取决于前一个状态 + dp[i][j] = dp[i - 1][j - 1]; + } else { + // 字符不匹配,只能尝试在 t 中继续寻找 + dp[i][j] = dp[i][j - 1]; + } + } + } + + return dp[m][n]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" similarity index 86% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" index b5cb9e1..22b2183 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" @@ -1,10 +1,11 @@ -package io.github.dunwu.algorithm.dynamic; +package io.github.dunwu.algorithm.dp.subseq; import org.junit.jupiter.api.Assertions; /** + * 53. 最大子序和 + * * @author Zhang Peng - * @see 53. 最大子序和 * @since 2020-07-06 */ public class 最大子序和 { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227.java" similarity index 84% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227.java" index 1aef32a..d7ff0fe 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227.java" @@ -1,10 +1,11 @@ -package io.github.dunwu.algorithm.dynamic; +package io.github.dunwu.algorithm.dp.subseq; import org.junit.jupiter.api.Assertions; /** + * 300. 最长上升子序列 + * * @author Zhang Peng - * @see 300. 最长上升子序列 * @since 2020-07-06 */ public class 最长上升子序列 { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.java" new file mode 100644 index 0000000..97c9a7f --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.java" @@ -0,0 +1,57 @@ +package io.github.dunwu.algorithm.dp.subseq; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 1143. 最长公共子序列 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 最长公共子序列 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(3, s.longestCommonSubsequence("abcde", "ace")); + Assertions.assertEquals(3, s.longestCommonSubsequence("abc", "abc")); + Assertions.assertEquals(0, s.longestCommonSubsequence("abc", "def")); + } + + /** + * 使用备忘录优化动态规划问题 + */ + static class Solution { + + public int longestCommonSubsequence(String text1, String text2) { + int[][] memo = new int[text1.length()][text2.length()]; + for (int i = 0; i < text1.length(); i++) { + Arrays.fill(memo[i], -1); + } + return dp(memo, text1, 0, text2, 0); + } + + public int dp(int[][] memo, String text1, int i, String text2, int j) { + if (i < 0 || j < 0 || i >= text1.length() || j >= text2.length()) { return 0; } + if (memo[i][j] != -1) { return memo[i][j]; } + + if (text1.charAt(i) == text2.charAt(j)) { + memo[i][j] = 1 + dp(memo, text1, i + 1, text2, j + 1); + } else { + memo[i][j] = max( + dp(memo, text1, i + 1, text2, j), + dp(memo, text1, i, text2, j + 1), + dp(memo, text1, i + 1, text2, j + 1) + ); + } + return memo[i][j]; + } + + public int max(int a, int b, int c) { + return Math.max(a, Math.max(b, c)); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227.java" new file mode 100644 index 0000000..5f11659 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227.java" @@ -0,0 +1,46 @@ +package io.github.dunwu.algorithm.dp.subseq; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 300. 最长递增子序列 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 最长递增子序列 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(4, s.lengthOfLIS(new int[] { 10, 9, 2, 5, 3, 7, 101, 18 })); + } + + /** + * 使用备忘录优化动态规划问题 + */ + static class Solution { + + public int lengthOfLIS(int[] nums) { + int[] dp = new int[nums.length]; + Arrays.fill(dp, 1); + + for (int i = 0; i < nums.length; i++) { + for (int j = 0; j < i; j++) { + if (nums[i] > nums[j]) { + dp[i] = Math.max(dp[i], dp[j] + 1); + } + } + } + + int res = 0; + for (int num : dp) { + res = Math.max(res, num); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/template/\345\212\250\346\200\201\350\247\204\345\210\222\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/template/\345\212\250\346\200\201\350\247\204\345\210\222\346\250\241\346\235\277.java" new file mode 100644 index 0000000..654e676 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/template/\345\212\250\346\200\201\350\247\204\345\210\222\346\250\241\346\235\277.java" @@ -0,0 +1,25 @@ +package io.github.dunwu.algorithm.dp.template; + +/** + * 动态规划模板 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 动态规划模板 { + // 自顶向下递归的动态规划 + // def dp(状态1, 状态2, ...): + // for 选择 in 所有可能的选择: + // # 此时的状态已经因为做了选择而改变 + // result = 求最值(result, dp(状态1, 状态2, ...)) + // return result + + // 自底向上迭代的动态规划 + // 初始化 base case + // dp[0][0][...] = base case + // # 进行状态转移 + // for 状态1 in 状态1的所有取值: + // for 状态2 in 状态2的所有取值: + // for ... + // dp[状态1][状态2][...] = 求最值(选择1,选择2...) +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" new file mode 100644 index 0000000..bd82ebf --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" @@ -0,0 +1,57 @@ +package io.github.dunwu.algorithm.dp; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 583. 两个字符串的删除操作 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 两个字符串的删除操作 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(2, s.minDistance("sea", "eat")); + } + + static class Solution { + + public int minDistance(String word1, String word2) { + int lcs = longestCommonSubsequence(word1, word2); + return word1.length() + word2.length() - lcs - lcs; + } + + public int longestCommonSubsequence(String text1, String text2) { + int[][] memo = new int[text1.length()][text2.length()]; + for (int i = 0; i < text1.length(); i++) { + Arrays.fill(memo[i], -1); + } + return dp(memo, text1, 0, text2, 0); + } + + public int dp(int[][] memo, String text1, int i, String text2, int j) { + if (i < 0 || j < 0 || i >= text1.length() || j >= text2.length()) { return 0; } + if (memo[i][j] != -1) { return memo[i][j]; } + + if (text1.charAt(i) == text2.charAt(j)) { + memo[i][j] = 1 + dp(memo, text1, i + 1, text2, j + 1); + } else { + memo[i][j] = max( + dp(memo, text1, i + 1, text2, j), + dp(memo, text1, i, text2, j + 1), + dp(memo, text1, i + 1, text2, j + 1) + ); + } + return memo[i][j]; + } + + public int max(int a, int b, int c) { + return Math.max(a, Math.max(b, c)); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204.java" similarity index 97% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204.java" index 6734c61..3f7dff2 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.dynamic; +package io.github.dunwu.algorithm.dp; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206.java" new file mode 100644 index 0000000..f478807 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206.java" @@ -0,0 +1,55 @@ +package io.github.dunwu.algorithm.dp; + +import org.junit.jupiter.api.Assertions; + +/** + * 416. 分割等和子集 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 分割等和子集 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.canPartition(new int[] { 1, 5, 11, 5 })); + Assertions.assertFalse(s.canPartition(new int[] { 1, 2, 3, 5 })); + } + + static class Solution { + + public boolean canPartition(int[] wights) { + + int sum = 0; + for (int weight : wights) { + sum += weight; + } + + // 和为奇数时,不可能划分成两个和相等的集合 + if (sum % 2 != 0) return false; + + // 初始化为背包问题 + int W = sum / 2; + int N = wights.length; + + // base case + boolean[][] dp = new boolean[N + 1][W + 1]; + for (int i = 0; i <= N; i++) + dp[i][0] = true; + + for (int i = 1; i <= N; i++) { + for (int w = 1; w <= W; w++) { + if (w - wights[i - 1] < 0) { + dp[i][w] = dp[i - 1][w]; + } else { + dp[i][w] = dp[i - 1][w] + || dp[i - 1][w - wights[i - 1]]; + } + } + } + return dp[N][W]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204\345\222\214.java" new file mode 100644 index 0000000..c606944 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204\345\222\214.java" @@ -0,0 +1,41 @@ +package io.github.dunwu.algorithm.dp; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 53. 最大子数组和 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 最大子数组和 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(6, s.maxSubArray(new int[] { -2, 1, -3, 4, -1, 2, 1, -5, 4 })); + } + + static class Solution { + + public int maxSubArray(int[] nums) { + int n = nums.length; + if (n == 0) return 0; + int[] dp = new int[n]; + // base case + // 第一个元素前面没有子数组 + dp[0] = nums[0]; + // 状态转移方程 + int res = Integer.MIN_VALUE; + for (int i = 1; i < n; i++) { + dp[i] = Math.max(nums[i], nums[i] + dp[i - 1]); + res = Math.max(res, dp[i]); + System.out.printf("nums[%d] = %d, dp[%d] = %d\n", i, nums[i], i, dp[i]); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\347\274\226\350\276\221\350\267\235\347\246\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\347\274\226\350\276\221\350\267\235\347\246\273.java" new file mode 100644 index 0000000..85dc76a --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\347\274\226\350\276\221\350\267\235\347\246\273.java" @@ -0,0 +1,63 @@ +package io.github.dunwu.algorithm.dp; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 72. 编辑距离 + * + * @author Zhang Peng + * @since 2020-07-06 + */ +public class 编辑距离 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(3, s.minDistance("horse", "ros")); + Assertions.assertEquals(5, s.minDistance("intention", "execution")); + } + + static class Solution { + + int[][] memo = null; + + public int minDistance(String word1, String word2) { + memo = new int[word1.length() + 1][word2.length() + 1]; + for (int i = 0; i <= word1.length(); i++) { + Arrays.fill(memo[i], -1); + } + return dp(word1, word1.length() - 1, word2, word2.length() - 1); + } + + public int dp(String s1, int i, String s2, int j) { + + // base case + if (i == -1) return j + 1; + if (j == -1) return i + 1; + + if (memo[i][j] != -1) { return memo[i][j]; } + + // 字符相等,啥也不做 + if (s1.charAt(i) == s2.charAt(j)) { + memo[i][j] = dp(s1, i - 1, s2, j - 1); + } else { + memo[i][j] = min( + // 插入 + dp(s1, i, s2, j - 1) + 1, + // 删除 + dp(s1, i - 1, s2, j) + 1, + // 替换 + dp(s1, i - 1, s2, j - 1) + 1 + ); + } + return memo[i][j]; + } + + public int min(int a, int b, int c) { + return Math.min(a, Math.min(b, c)); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\242.java" new file mode 100644 index 0000000..3d27dcc --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\242.java" @@ -0,0 +1,83 @@ +package io.github.dunwu.algorithm.dp; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 322. 零钱兑换 + * + * @author Zhang Peng + * @since 2020-07-06 + */ +public class 零钱兑换 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(3, s.coinChange(new int[] { 1, 2, 5 }, 11)); + Assertions.assertEquals(-1, s.coinChange(new int[] { 2 }, 3)); + Assertions.assertEquals(0, s.coinChange(new int[] { 1 }, 0)); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals(3, s2.coinChange(new int[] { 1, 2, 5 }, 11)); + Assertions.assertEquals(-1, s2.coinChange(new int[] { 2 }, 3)); + Assertions.assertEquals(0, s2.coinChange(new int[] { 1 }, 0)); + } + + static class Solution { + + public int coinChange(int[] coins, int amount) { + int[] memo = new int[amount + 1]; + // 备忘录初始化为一个不会被取到的特殊值,代表还未被计算 + Arrays.fill(memo, -1); + return dp(coins, memo, amount); + } + + public int dp(int[] coins, int[] memo, int amount) { + if (amount == 0) return 0; + if (amount < 0) return -1; + // 查备忘录,防止重复计算 + if (memo[amount] != -1) { + return memo[amount]; + } + + int res = Integer.MAX_VALUE; + for (int coin : coins) { + // 计算子问题的结果 + int subProblem = dp(coins, memo, amount - coin); + // 子问题无解则跳过 + if (subProblem == -1) continue; + // 在子问题中选择最优解,然后加一 + res = Math.min(res, subProblem + 1); + } + // 把计算结果存入备忘录 + memo[amount] = (res == Integer.MAX_VALUE) ? -1 : res; + return memo[amount]; + } + + } + + static class Solution2 { + + public int coinChange(int[] coins, int amount) { + return dp(coins, amount); + } + + public int dp(int[] coins, int amount) { + if (amount <= 0) return amount; + int[] dp = new int[amount + 1]; + Arrays.fill(dp, amount + 1); + + dp[0] = 0; + for (int i = 0; i < dp.length; i++) { + for (int coin : coins) { + if (i - coin < 0) { continue; } + dp[i] = Math.min(dp[i], dp[i - coin] + 1); + } + } + return (dp[amount] == amount + 1) ? -1 : dp[amount]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\2422.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\2422.java" new file mode 100644 index 0000000..079c629 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\2422.java" @@ -0,0 +1,43 @@ +package io.github.dunwu.algorithm.dp; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 518. 零钱兑换 II + * + * @author Zhang Peng + * @date 2025-11-11 + */ +public class 零钱兑换2 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(4, s.change(5, new int[] { 1, 2, 5 })); + Assertions.assertEquals(0, s.change(3, new int[] { 2 })); + Assertions.assertEquals(1, s.change(10, new int[] { 10 })); + } + + static class Solution { + + public int change(int amount, int[] coins) { + int n = coins.length; + int[][] dp = new int[n + 1][amount + 1]; + // base case + for (int i = 0; i <= n; i++) + dp[i][0] = 1; + + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= amount; j++) + if (j - coins[i - 1] >= 0) { + dp[i][j] = dp[i - 1][j] + + dp[i][j - coins[i - 1]]; + } else { dp[i][j] = dp[i - 1][j]; } + } + return dp[n][amount]; + } + + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/MaxSubArray.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/MaxSubArray.java deleted file mode 100644 index 130756a..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/MaxSubArray.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.dunwu.algorithm.dynamic; - -import cn.hutool.core.util.ArrayUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author Zhang Peng - * @since 2020-03-06 - */ -public class MaxSubArray { - - private static final Logger log = LoggerFactory.getLogger(MaxSubArray.class); - - public static int maxSubArray(int[] nums) { - int[] result = new int[nums.length]; - result[0] = nums[0]; - int max = nums[0]; - for (int i = 1; i < nums.length; i++) { - result[i] = Math.max(result[i - 1] + nums[i], nums[i]); - if (max < result[i]) { - max = result[i]; - } - - if (log.isDebugEnabled()) { - log.debug(ArrayUtil.toString(result)); - } - } - return max; - } - - public static void main(String[] args) { - int[] array = new int[] { -2, 1, -3, 4, -1, 2, 1, -5, 4 }; - int max = MaxSubArray.maxSubArray(array); - System.out.println("max = " + max); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" deleted file mode 100644 index e1dd46e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" +++ /dev/null @@ -1,101 +0,0 @@ -package io.github.dunwu.algorithm.dynamic; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * @author Zhang Peng - * @see 120. 三角形最小路径和 - * @since 2020-07-04 - */ -public class 三角形最小路径和 { - - public static void main(String[] args) { - List> triangle = new ArrayList<>(); - triangle.add(Collections.singletonList(2)); - triangle.add(Arrays.asList(3, 4)); - triangle.add(Arrays.asList(6, 5, 7)); - triangle.add(Arrays.asList(4, 1, 8, 3)); - System.out.println("args = " + minimumTotal(triangle)); - Assertions.assertEquals(11, minimumTotal(triangle)); - Assertions.assertEquals(11, minimumTotal2(triangle)); - Assertions.assertEquals(11, minimumTotal3(triangle)); - Assertions.assertEquals(11, minimumTotal4(triangle)); - } - - // 回溯法,自上而下 - // 时间复杂度:O(2^(M*N)) - public static int minimumTotal(List> triangle) { - return backtrack(triangle, triangle.size(), 0, 0); - } - - private static int backtrack(List> triangle, int row, int x, int y) { - if (x == row - 1) return triangle.get(x).get(y); - int left = backtrack(triangle, row, x + 1, y); - int right = backtrack(triangle, row, x + 1, y + 1); - return triangle.get(x).get(y) + Math.min(left, right); - } - - // 回溯法 + 剪枝,自上而下 - // 针对 minimumTotal 加入记忆缓存 memory 存储计算结果,避免递归中的重复计算 - // 时间复杂度:< O(2^(M*N)) - // 空间复杂度:O(M*M) - public static int minimumTotal2(List> triangle) { - int level = triangle.size(); - int[][] memory = new int[level][level]; // 存储每个节点能得到的最优解 - return backtrack2(triangle, memory, triangle.size(), 0, 0); - } - - private static int backtrack2(List> triangle, int[][] memory, int row, int x, int y) { - if (memory[x][y] != 0) { return memory[x][y]; } - if (x == row - 1) return memory[x][y] = triangle.get(x).get(y); - int left = backtrack2(triangle, memory, row, x + 1, y); - int right = backtrack2(triangle, memory, row, x + 1, y + 1); - memory[x][y] = triangle.get(x).get(y) + Math.min(left, right); - return memory[x][y]; - } - - // 动态规划,自下而上 - // 时间复杂度:O(M^2) - // 空间复杂度:O(M^2) - public static int minimumTotal3(List> triangle) { - // 判空 - if (triangle == null || triangle.size() == 0) return 0; - int level = triangle.size(); - // 横竖维度都加1,可以不用考虑最后一行的初始化 - // 由于是三角形二维数组,可视为横竖维度都是行数 - int[][] memory = new int[level + 1][level + 1]; - for (int i = level - 1; i >= 0; i--) { - for (int j = 0; j < triangle.get(i).size(); j++) { - if (memory[i][j] == 0) { - memory[i][j] = Math.min(memory[i + 1][j], memory[i + 1][j + 1]) + triangle.get(i).get(j); - } - } - } - return memory[0][0]; - } - - // 动态规划,自下而上 + 空间优化 - // 时间复杂度:O(M^2) - // 空间复杂度:O(M^2) - public static int minimumTotal4(List> triangle) { - // 判空 - if (triangle == null || triangle.size() == 0) return 0; - int level = triangle.size(); - // 横竖维度都加1,可以不用考虑最后一行的初始化 - // 由于是三角形二维数组,可视为横竖维度都是行数 - int[] memory = new int[level + 1]; - for (int i = level - 1; i >= 0; i--) { - List rows = triangle.get(i); - for (int j = 0; j < rows.size(); j++) { - memory[j] = Math.min(memory[j], memory[j + 1]) + rows.get(j); - } - } - return memory[0]; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227.java" deleted file mode 100644 index 96d0bb2..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227.java" +++ /dev/null @@ -1,39 +0,0 @@ -package io.github.dunwu.algorithm.dynamic; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @see 392. 判断子序列 - * @since 2020-07-06 - */ -public class 判断子序列 { - - public static void main(String[] args) { - Assertions.assertTrue(isSubsequence("abc", "ahbgdc")); - Assertions.assertFalse(isSubsequence("axc", "ahbgdc")); - Assertions.assertTrue(isSubsequence("", "ahbgdc")); - Assertions.assertFalse(isSubsequence("aaaaaa", "bbaaaa")); - } - - public static boolean isSubsequence(String s, String t) { - if (s == null || s.length() == 0) return true; - if (s.length() > t.length()) return false; - char[] source = s.toCharArray(); - char[] target = t.toCharArray(); - int i = 0, j = 0; - while (i < source.length && j < target.length) { - if (target[j] != source[i]) { - j++; - } else { - if (i == source.length - 1) { - return true; - } - i++; - j++; - } - } - return false; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\347\210\254\346\245\274\346\242\257.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\347\210\254\346\245\274\346\242\257.java" deleted file mode 100644 index 4f33ee3..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\347\210\254\346\245\274\346\242\257.java" +++ /dev/null @@ -1,63 +0,0 @@ -package io.github.dunwu.algorithm.dynamic; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @see 79. 单词搜索 - * @since 2020-07-04 - */ -public class 爬楼梯 { - - public static void main(String[] args) { - Assertions.assertEquals(1, climbStairs(0)); - Assertions.assertEquals(1, climbStairs(1)); - Assertions.assertEquals(2, climbStairs(2)); - Assertions.assertEquals(3, climbStairs(3)); - - Assertions.assertEquals(1, climbStairs2(0)); - Assertions.assertEquals(1, climbStairs2(1)); - Assertions.assertEquals(2, climbStairs2(2)); - Assertions.assertEquals(3, climbStairs2(3)); - - Assertions.assertEquals(1, climbStairs3(0)); - Assertions.assertEquals(1, climbStairs3(1)); - Assertions.assertEquals(2, climbStairs3(2)); - Assertions.assertEquals(3, climbStairs3(3)); - } - - // 使用递归(回溯方式) - // 时间复杂度:O(2^N) - public static int climbStairs(int n) { - return (n <= 1) ? 1 : climbStairs(n - 1) + climbStairs(n - 2); - } - - // 使用动态规划 - // 时间复杂度:O(N) - // 空间复杂度:O(N) - public static int climbStairs2(int n) { - if (n <= 1) return 1; - int[] mem = new int[n + 1]; - mem[0] = 1; - mem[1] = 1; - for (int i = 2; i < n + 1; i++) { - mem[i] = mem[i - 1] + mem[i - 2]; - } - return mem[n]; - } - // 优化 climbStairs2 动态规划方案 - // 时间复杂度:O(N) - // 空间复杂度:O(3) - public static int climbStairs3(int n) { - if (n <= 1) return 1; - int res = 0; - int prevStep1 = 1; - int prevStep2 = 1; - for (int i = 2; i < n + 1; i++) { - res = prevStep1 + prevStep2; - prevStep2 = prevStep1; - prevStep1 = res; - } - return res; - } -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\347\274\226\350\276\221\350\267\235\347\246\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\347\274\226\350\276\221\350\267\235\347\246\273.java" deleted file mode 100644 index 868165e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\347\274\226\350\276\221\350\267\235\347\246\273.java" +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.dunwu.algorithm.dynamic; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @see 72. 编辑距离 - * @since 2020-07-06 - */ -public class 编辑距离 { - - public static void main(String[] args) { - Assertions.assertEquals(3, minDistance("horse", "ros")); - Assertions.assertEquals(5, minDistance("intention", "execution")); - } - - public static int minDistance(String word1, String word2) { - int m = word1.length(); - int n = word2.length(); - int[][] dp = new int[m + 1][n + 1]; - for (int i = 0; i < m + 1; i++) dp[i][0] = i; - for (int j = 0; j < n + 1; j++) dp[0][j] = j; - - for (int i = 1; i < m + 1; i++) { - for (int j = 1; j < n + 1; j++) { - if (word1.charAt(i - 1) == word2.charAt(j - 1)) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - int m1 = Math.min(dp[i - 1][j], dp[i][j - 1]); - int m2 = Math.min(m1, dp[i - 1][j - 1]); - dp[i][j] = 1 + m2; - } - } - } - return dp[m][n]; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\351\233\266\351\222\261\345\205\221\346\215\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\351\233\266\351\222\261\345\205\221\346\215\242.java" deleted file mode 100644 index 20c3454..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/\351\233\266\351\222\261\345\205\221\346\215\242.java" +++ /dev/null @@ -1,39 +0,0 @@ -package io.github.dunwu.algorithm.dynamic; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @see 322. 零钱兑换 - * @since 2020-07-06 - */ -public class 零钱兑换 { - - public static void main(String[] args) { - int[] nums = { 1, 2, 5 }; - Assertions.assertEquals(3, coinChange(nums, 11)); - Assertions.assertEquals(-1, coinChange(new int[] { 2 }, 3)); - } - - - public static int coinChange(int[] coins, int amount) { - return coinChange(coins, amount, 0); - } - - public static int coinChange(int[] coins, int amount, int idxCoin) { - if (amount == 0) { return 0; } - if (idxCoin < coins.length && amount > 0) { - int maxVal = amount / coins[idxCoin]; - int minCost = Integer.MAX_VALUE; - for (int x = 0; x <= maxVal; x++) { - if (amount >= x * coins[idxCoin]) { - int res = coinChange(coins, amount - x * coins[idxCoin], idxCoin + 1); - if (res != -1) { minCost = Math.min(minCost, res + x); } - } - } - return (minCost == Integer.MAX_VALUE) ? -1 : minCost; - } - return -1; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Edge.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Edge.java new file mode 100644 index 0000000..c4ee513 --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Edge.java @@ -0,0 +1,16 @@ +package io.github.dunwu.algorithm.graph; + +/** + * 存储相邻节点及边的权重 + */ +public class Edge { + + public int to; + public int weight; + + public Edge(int to, int weight) { + this.to = to; + this.weight = weight; + } + +} \ No newline at end of file diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Graph.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Graph.java new file mode 100644 index 0000000..eaf8c0c --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Graph.java @@ -0,0 +1,25 @@ +package io.github.dunwu.algorithm.graph; + +import java.util.List; + +public interface Graph { + + // 添加一条边(带权重) + void addEdge(int from, int to, int weight); + + // 删除一条边 + void removeEdge(int from, int to); + + // 判断两个节点是否相邻 + boolean hasEdge(int from, int to); + + // 返回一条边的权重 + int weight(int from, int to); + + // 返回某个节点的所有邻居节点和对应权重 + List neighbors(int v); + + // 返回节点总数 + int size(); + +} \ No newline at end of file diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/State.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/State.java new file mode 100644 index 0000000..3b78a8f --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/State.java @@ -0,0 +1,17 @@ +package io.github.dunwu.algorithm.graph; + +// 图结构的 BFS 遍历,从节点 s 开始进行 BFS,且记录遍历步数(从起点 s 到当前节点的边的条数) +// 每个节点自行维护 State 类,记录从 s 走来的遍历步数 +public class State { + + // 当前节点 ID + public int node; + // 从起点 s 到当前节点的遍历步数 + public int step; + + public State(int node, int step) { + this.node = node; + this.step = step; + } + +} \ No newline at end of file diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Vertex.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Vertex.java new file mode 100644 index 0000000..46dec8a --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Vertex.java @@ -0,0 +1,11 @@ +package io.github.dunwu.algorithm.graph; + +/** + * 图节点 + */ +public class Vertex { + + public int id; + public Vertex[] neighbors; + +} \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/BFS\351\201\215\345\216\206\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/BFS\351\201\215\345\216\206\345\233\276.java" new file mode 100644 index 0000000..74141ec --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/BFS\351\201\215\345\216\206\345\233\276.java" @@ -0,0 +1,87 @@ +package io.github.dunwu.algorithm.graph.template; + +import io.github.dunwu.algorithm.graph.Edge; +import io.github.dunwu.algorithm.graph.Graph; +import io.github.dunwu.algorithm.graph.State; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * 图的遍历框架 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class BFS遍历图 { + + // 图结构的 BFS 遍历,从节点 s 开始进行 BFS + void bfs(Graph graph, int s) { + boolean[] visited = new boolean[graph.size()]; + Queue q = new LinkedList<>(); + q.offer(s); + visited[s] = true; + + while (!q.isEmpty()) { + int cur = q.poll(); + System.out.println("visit " + cur); + for (Edge e : graph.neighbors(cur)) { + if (visited[e.to]) { + continue; + } + q.offer(e.to); + visited[e.to] = true; + } + } + } + + // 从 s 开始 BFS 遍历图的所有节点,且记录遍历的步数 + void bfs2(Graph graph, int s) { + boolean[] visited = new boolean[graph.size()]; + Queue q = new LinkedList<>(); + q.offer(s); + visited[s] = true; + // 记录从 s 开始走到当前节点的步数 + int step = 0; + while (!q.isEmpty()) { + int sz = q.size(); + for (int i = 0; i < sz; i++) { + int cur = q.poll(); + System.out.println("visit " + cur + " at step " + step); + for (Edge e : graph.neighbors(cur)) { + if (visited[e.to]) { + continue; + } + q.offer(e.to); + visited[e.to] = true; + } + } + step++; + } + } + + // 图结构的 BFS 遍历,从节点 s 开始进行 BFS,且记录遍历步数(从起点 s 到当前节点的边的条数) + // 每个节点自行维护 State 类,记录从 s 走来的遍历步数 + void bfs3(Graph graph, int s) { + boolean[] visited = new boolean[graph.size()]; + Queue q = new LinkedList<>(); + + q.offer(new State(s, 0)); + visited[s] = true; + + while (!q.isEmpty()) { + State state = q.poll(); + int node = state.node; + int step = state.step; + System.out.println("visit " + node + " with step " + step); + for (Edge e : graph.neighbors(node)) { + if (visited[e.to]) { + continue; + } + q.offer(new State(e.to, step + 1)); + visited[e.to] = true; + } + } + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\233\276\347\232\204DFS\351\201\215\345\216\206\346\241\206\346\236\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\212\202\347\202\271.java" similarity index 52% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\233\276\347\232\204DFS\351\201\215\345\216\206\346\241\206\346\236\266.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\212\202\347\202\271.java" index 7a2e5dd..3d1f714 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\233\276\347\232\204DFS\351\201\215\345\216\206\346\241\206\346\236\266.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\212\202\347\202\271.java" @@ -1,12 +1,35 @@ package io.github.dunwu.algorithm.graph.template; +import io.github.dunwu.algorithm.graph.Edge; +import io.github.dunwu.algorithm.graph.Graph; +import io.github.dunwu.algorithm.graph.Vertex; + /** * 图的遍历框架 * * @author Zhang Peng * @date 2025-11-03 */ -public class 图的DFS遍历框架 { +public class DFS遍历图的所有节点 { + + // 遍历图的所有节点 + void traverse(Graph graph, int s, boolean[] visited) { + // base case + if (s < 0 || s >= graph.size()) { + return; + } + if (visited[s]) { + // 防止死循环 + return; + } + // 前序位置 + visited[s] = true; + System.out.println("visit " + s); + for (Edge e : graph.neighbors(s)) { + traverse(graph, e.to, visited); + } + // 后序位置 + } // 图的遍历框架 // 需要一个 visited 数组记录被遍历过的节点 @@ -29,11 +52,4 @@ void traverse(Vertex s, boolean[] visited) { // 后序位置 } - static class Vertex { - - int id; - Vertex[] neighbors; - - } - } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" new file mode 100644 index 0000000..20e419f --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" @@ -0,0 +1,45 @@ +package io.github.dunwu.algorithm.graph.template; + +import io.github.dunwu.algorithm.tree.Node; +import io.github.dunwu.algorithm.graph.Vertex; + +/** + * DFS遍历图的所有边 + * + * @author Zhang Peng + * @date 2025-11-06 + */ +public class DFS遍历图的所有边 { + + // 遍历多叉树的树枝 + void traverseBranch(Node root) { + // base case + if (root == null) { + return; + } + for (Node child : root.children) { + System.out.println("visit branch: " + root.val + " -> " + child.val); + traverseBranch(child); + } + } + + // 遍历图的边 + // 需要一个二维 visited 数组记录被遍历过的边,visited[u][v] 表示边 u->v 已经被遍历过 + void traverseEdges(Vertex s, boolean[][] visited) { + // base case + if (s == null) { + return; + } + for (Vertex neighbor : s.neighbors) { + // 如果边已经被遍历过,则跳过 + if (visited[s.id][neighbor.id]) { + continue; + } + // 标记并访问边 + visited[s.id][neighbor.id] = true; + System.out.println("visit edge: " + s.id + " -> " + neighbor.id); + traverseEdges(neighbor, visited); + } + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\347\237\251\351\230\265\345\256\236\347\216\260\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\347\237\251\351\230\265\345\256\236\347\216\260\345\233\276.java" new file mode 100644 index 0000000..cdd84bb --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\347\237\251\351\230\265\345\256\236\347\216\260\345\233\276.java" @@ -0,0 +1,138 @@ +package io.github.dunwu.algorithm.graph.template; + +import io.github.dunwu.algorithm.graph.Edge; + +import java.util.ArrayList; +import java.util.List; + +/** + * 邻接矩阵实现图 + * + * @author Zhang Peng + * @date 2025-11-06 + */ +public class 邻接矩阵实现图 { + + public static void main(String[] args) { + WeightedDigraph graph = new WeightedDigraph(3); + graph.addEdge(0, 1, 1); + graph.addEdge(1, 2, 2); + graph.addEdge(2, 0, 3); + graph.addEdge(2, 1, 4); + + System.out.println(graph.hasEdge(0, 1)); // true + System.out.println(graph.hasEdge(1, 0)); // false + + graph.neighbors(2).forEach(edge -> { + System.out.println(2 + " -> " + edge.to + ", wight: " + edge.weight); + }); + // 2 -> 0, wight: 3 + // 2 -> 1, wight: 4 + + graph.removeEdge(0, 1); + System.out.println(graph.hasEdge(0, 1)); // false + } // 存储相邻节点及边的权重 + + // 加权有向图的通用实现(邻接矩阵) + static class WeightedDigraph { + + // 邻接矩阵,matrix[from][to] 存储从节点 from 到节点 to 的边的权重 + // 0 表示没有连接 + private int[][] matrix; + + public WeightedDigraph(int n) { + matrix = new int[n][n]; + } + + // 增,添加一条带权重的有向边,复杂度 O(1) + public void addEdge(int from, int to, int weight) { + matrix[from][to] = weight; + } + + // 删,删除一条有向边,复杂度 O(1) + public void removeEdge(int from, int to) { + matrix[from][to] = 0; + } + + // 查,判断两个节点是否相邻,复杂度 O(1) + public boolean hasEdge(int from, int to) { + return matrix[from][to] != 0; + } + + // 查,返回一条边的权重,复杂度 O(1) + public int weight(int from, int to) { + return matrix[from][to]; + } + + // 查,返回某个节点的所有邻居节点,复杂度 O(V) + public List neighbors(int v) { + List res = new ArrayList<>(); + for (int i = 0; i < matrix[v].length; i++) { + if (matrix[v][i] != 0) { + res.add(new Edge(i, matrix[v][i])); + } + } + return res; + } + + } + + // 无向加权图的通用实现 + static class WeightedUndigraph { + + private WeightedDigraph graph; + + public WeightedUndigraph(int n) { + graph = new WeightedDigraph(n); + } + + // 增,添加一条带权重的无向边 + public void addEdge(int from, int to, int weight) { + graph.addEdge(from, to, weight); + graph.addEdge(to, from, weight); + } + + // 删,删除一条无向边 + public void removeEdge(int from, int to) { + graph.removeEdge(from, to); + graph.removeEdge(to, from); + } + + // 查,判断两个节点是否相邻 + public boolean hasEdge(int from, int to) { + return graph.hasEdge(from, to); + } + + // 查,返回一条边的权重 + public int weight(int from, int to) { + return graph.weight(from, to); + } + + // 查,返回某个节点的所有邻居节点 + public List neighbors(int v) { + return graph.neighbors(v); + } + + public static void main(String[] args) { + WeightedUndigraph graph = new WeightedUndigraph(3); + graph.addEdge(0, 1, 1); + graph.addEdge(2, 0, 3); + graph.addEdge(2, 1, 4); + + System.out.println(graph.hasEdge(0, 1)); // true + System.out.println(graph.hasEdge(1, 0)); // true + + graph.neighbors(2).forEach(edge -> { + System.out.println(2 + " <-> " + edge.to + ", wight: " + edge.weight); + }); + // 2 <-> 0, wight: 3 + // 2 <-> 1, wight: 4 + + graph.removeEdge(0, 1); + System.out.println(graph.hasEdge(0, 1)); // false + System.out.println(graph.hasEdge(1, 0)); // false + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\350\241\250\345\256\236\347\216\260\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\350\241\250\345\256\236\347\216\260\345\233\276.java" new file mode 100644 index 0000000..2372c4c --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\350\241\250\345\256\236\347\216\260\345\233\276.java" @@ -0,0 +1,159 @@ +package io.github.dunwu.algorithm.graph.template; + +import io.github.dunwu.algorithm.graph.Edge; + +import java.util.ArrayList; +import java.util.List; + +/** + * 邻接表实现图 + * + * @author Zhang Peng + * @date 2025-11-06 + */ +public class 邻接表实现图 { + + /** + * 加权有向图的通用实现(邻接表) + */ + static class WeightedDigraph { + + // 邻接表,graph[v] 存储节点 v 的所有邻居节点及对应权重 + private List[] graph; + + public WeightedDigraph(int n) { + // 我们这里简单起见,建图时要传入节点总数,这其实可以优化 + // 比如把 graph 设置为 Map>,就可以动态添加新节点了 + graph = new List[n]; + for (int i = 0; i < n; i++) { + graph[i] = new ArrayList<>(); + } + } + + // 增,添加一条带权重的有向边,复杂度 O(1) + public void addEdge(int from, int to, int weight) { + graph[from].add(new Edge(to, weight)); + } + + // 删,删除一条有向边,复杂度 O(V) + public void removeEdge(int from, int to) { + for (int i = 0; i < graph[from].size(); i++) { + if (graph[from].get(i).to == to) { + graph[from].remove(i); + break; + } + } + } + + // 查,判断两个节点是否相邻,复杂度 O(V) + public boolean hasEdge(int from, int to) { + for (Edge e : graph[from]) { + if (e.to == to) { + return true; + } + } + return false; + } + + // 查,返回一条边的权重,复杂度 O(V) + public int weight(int from, int to) { + for (Edge e : graph[from]) { + if (e.to == to) { + return e.weight; + } + } + throw new IllegalArgumentException("No such edge"); + } + + // 上面的 hasEdge、removeEdge、weight 方法遍历 List 的行为是可以优化的 + // 比如用 Map> 存储邻接表 + // 这样就可以避免遍历 List,复杂度就能降到 O(1) + + // 查,返回某个节点的所有邻居节点,复杂度 O(1) + public List neighbors(int v) { + return graph[v]; + } + + public static void main(String[] args) { + WeightedDigraph graph = new WeightedDigraph(3); + graph.addEdge(0, 1, 1); + graph.addEdge(1, 2, 2); + graph.addEdge(2, 0, 3); + graph.addEdge(2, 1, 4); + + System.out.println(graph.hasEdge(0, 1)); // true + System.out.println(graph.hasEdge(1, 0)); // false + + graph.neighbors(2).forEach(edge -> { + System.out.println(2 + " -> " + edge.to + ", wight: " + edge.weight); + }); + // 2 -> 0, wight: 3 + // 2 -> 1, wight: 4 + + graph.removeEdge(0, 1); + System.out.println(graph.hasEdge(0, 1)); // false + } + + } + + /** + * 无向加权图的通用实现 + */ + static class WeightedUndigraph { + + private WeightedDigraph graph; + + public WeightedUndigraph(int n) { + graph = new WeightedDigraph(n); + } + + // 增,添加一条带权重的无向边 + public void addEdge(int from, int to, int weight) { + graph.addEdge(from, to, weight); + graph.addEdge(to, from, weight); + } + + // 删,删除一条无向边 + public void removeEdge(int from, int to) { + graph.removeEdge(from, to); + graph.removeEdge(to, from); + } + + // 查,判断两个节点是否相邻 + public boolean hasEdge(int from, int to) { + return graph.hasEdge(from, to); + } + + // 查,返回一条边的权重 + public int weight(int from, int to) { + return graph.weight(from, to); + } + + // 查,返回某个节点的所有邻居节点 + public List neighbors(int v) { + return graph.neighbors(v); + } + + public static void main(String[] args) { + WeightedUndigraph graph = new WeightedUndigraph(3); + graph.addEdge(0, 1, 1); + graph.addEdge(2, 0, 3); + graph.addEdge(2, 1, 4); + + System.out.println(graph.hasEdge(0, 1)); // true + System.out.println(graph.hasEdge(1, 0)); // true + + graph.neighbors(2).forEach(edge -> { + System.out.println(2 + " <-> " + edge.to + ", wight: " + edge.weight); + }); + // 2 <-> 0, wight: 3 + // 2 <-> 1, wight: 4 + + graph.removeEdge(0, 1); + System.out.println(graph.hasEdge(0, 1)); // false + System.out.println(graph.hasEdge(1, 0)); // false + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" index 3fbd0c5..5619547 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" @@ -42,23 +42,20 @@ public List> allPathsSourceTarget(int[][] graph) { void traverse(int[][] graph, int s) { - // 添加节点 s 到路径 + // 前序 path.addLast(s); - int n = graph.length; - if (s == n - 1) { - // 到达终点 + if (s == graph.length - 1) { res.add(new LinkedList<>(path)); path.removeLast(); return; } - // 递归每个相邻节点 for (int v : graph[s]) { traverse(graph, v); } - // 从路径移出节点 s + // 后序 path.removeLast(); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\350\267\263\350\267\203\346\270\270\346\210\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\350\267\263\350\267\203\346\270\270\346\210\217.java" new file mode 100644 index 0000000..bae6a44 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\350\267\263\350\267\203\346\270\270\346\210\217.java" @@ -0,0 +1,57 @@ +package io.github.dunwu.algorithm.greedy; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 55. 跳跃游戏 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 跳跃游戏 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(2, s.jump(new int[] { 2, 3, 1, 1, 4 })); + } + + static class Solution { + + int[] memo; + + public int jump(int[] nums) { + if (nums.length <= 1) { + return 0; + } + int n = nums.length; + // 备忘录都初始化为 n,相当于 INT_MAX + // 因为从 0 跳到 n - 1 最多 n - 1 步 + memo = new int[n]; + Arrays.fill(memo, n); + + return dp(nums, 0); + } + + int dp(int[] nums, int p) { + int n = nums.length; + if (p >= n - 1) { + return 0; + } + + int steps = nums[p]; + // 你可以选择跳 1 步,2 步... + for (int i = 1; i <= steps; i++) { + // 穷举每一个选择 + // 计算每一个子问题的结果 + int sub = dp(nums, p + i); + // 取其中最小的作为最终结果 + memo[p] = Math.min(memo[p], sub + 1); + } + return memo[p]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\350\267\263\350\267\203\346\270\270\346\210\2172.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\350\267\263\350\267\203\346\270\270\346\210\2172.java" new file mode 100644 index 0000000..d1413bb --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\350\267\263\350\267\203\346\270\270\346\210\2172.java" @@ -0,0 +1,31 @@ +package io.github.dunwu.algorithm.greedy; + +import org.junit.jupiter.api.Assertions; + +/** + * 53. 最大子数组和 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 跳跃游戏2 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.canJump(new int[] { 2, 3, 1, 1, 4 })); + } + + static class Solution { + + public boolean canJump(int[] nums) { + int farthest = 0; + for (int i = 0; i < nums.length; i++) { + farthest = Math.max(farthest, i + nums[i]); + if (farthest <= i) return false; + } + return farthest >= nums.length - 1; + } + + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/Node.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/Node.java new file mode 100644 index 0000000..c131411 --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/Node.java @@ -0,0 +1,11 @@ +package io.github.dunwu.algorithm.tree; + +import java.util.List; + +// 多叉树节点 +public class Node { + + public int val; + public List children; + +} \ No newline at end of file diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/State.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/State.java new file mode 100644 index 0000000..9f19b02 --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/State.java @@ -0,0 +1,15 @@ +package io.github.dunwu.algorithm.tree; + +// 多叉树的层序遍历 +// 每个节点自行维护 State 类,记录深度等信息 +public class State { + + public Node node; + public int depth; + + public State(Node node, int depth) { + this.node = node; + this.depth = depth; + } + +} \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\345\244\232\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\345\244\232\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" index 8835333..a8154e0 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\345\244\232\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\345\244\232\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" @@ -1,6 +1,10 @@ package io.github.dunwu.algorithm.tree.template; -import java.util.List; +import io.github.dunwu.algorithm.tree.Node; +import io.github.dunwu.algorithm.tree.State; + +import java.util.LinkedList; +import java.util.Queue; /** * 多叉树遍历框架 @@ -11,7 +15,7 @@ public class 多叉树遍历框架 { // 多叉树的遍历框架 - void traverse(Node root) { + void dfs(Node root) { // base case if (root == null) { return; @@ -19,17 +23,75 @@ void traverse(Node root) { // 前序位置 System.out.println("visit " + root.val); for (Node child : root.children) { - traverse(child); + dfs(child); } // 后序位置 } - // 多叉树节点 - static class Node { + void bfs(Node root) { + // base case + if (root == null) { + return; + } + Queue q = new LinkedList<>(); + q.offer(root); + while (!q.isEmpty()) { + Node node = q.poll(); + // 访问 cur 节点 + System.out.println(node.val); - int val; - List children; + // 把 cur 的所有子节点加入队列 + for (Node child : node.children) { + q.offer(child); + } + } + } + + // 记录遍历步数的写法 + void bfs2(Node root) { + if (root == null) { + return; + } + Queue q = new LinkedList<>(); + q.offer(root); + // 记录当前遍历到的层数(根节点视为第 1 层) + int depth = 1; + while (!q.isEmpty()) { + int size = q.size(); + for (int i = 0; i < size; i++) { + Node node = q.poll(); + // 访问 cur 节点,同时知道它所在的层数 + System.out.println("depth = " + depth + ", val = " + node.val); + + for (Node child : node.children) { + q.offer(child); + } + } + depth++; + } + } + + // 每个节点自行维护 State 类,记录深度等信息 + void bfs3(Node root) { + if (root == null) { + return; + } + Queue q = new LinkedList<>(); + // 记录当前遍历到的层数(根节点视为第 1 层) + q.offer(new State(root, 1)); + + while (!q.isEmpty()) { + State state = q.poll(); + Node node = state.node; + int depth = state.depth; + // 访问 cur 节点,同时知道它所在的层数 + System.out.println("depth = " + depth + ", val = " + node.val); + + for (Node child : node.children) { + q.offer(new State(child, depth + 1)); + } + } } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java index f6ff852..53b5d8a 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java @@ -1,21 +1,47 @@ package io.github.dunwu.algorithm.util; +import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.List; import java.util.Random; /** * @author Zhang Peng */ +@Slf4j public class ArrayUtil { - private static final Logger logger = LoggerFactory.getLogger(ArrayUtil.class); + public static List> toListList(int[][] arr) { + if (arr == null || arr.length == 0) { return new ArrayList<>(); } + List> listlist = new ArrayList<>(); + for (int i = 0; i < arr.length; i++) { + List list = new ArrayList<>(); + listlist.add(list); + for (int j = 0; j < arr[i].length; j++) { + list.add(arr[i][j]); + } + } + return listlist; + } + + public static int[][] toMatrixArray(List> listlist) { + if (listlist == null || listlist.size() == 0) { return new int[0][0]; } + int[][] arr = new int[listlist.size()][listlist.get(0).size()]; + for (int i = 0; i < listlist.size(); i++) { + for (int j = 0; j < listlist.get(i).size(); j++) { + arr[i][j] = listlist.get(i).get(j); + } + } + return arr; + } public static void debugLogArray(T[] list, int begin, int end, String tip) { String content = tip + getArrayString(list, begin, end); - if (logger.isDebugEnabled()) { - logger.debug(content); + if (log.isDebugEnabled()) { + log.debug(content); } } From 4e5bd23cc7689cd8f3504980058a8b43549293c9 Mon Sep 17 00:00:00 2001 From: dunwu Date: Sun, 16 Nov 2025 11:10:31 +0800 Subject: [PATCH 12/21] =?UTF-8?q?feat:=20leetcode=20=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 62 ++++++++++++------ ...\347\210\254\346\245\274\346\242\257.java" | 40 +++++++++--- ...\345\276\227\347\202\271\346\225\260.java" | 29 +++++---- ...\345\256\266\345\212\253\350\210\215.java" | 44 ++----------- ...\347\210\254\346\245\274\346\242\257.java" | 16 ++--- ...\350\267\257\345\276\204\345\222\214.java" | 47 +++++++++++--- ...\346\234\200\345\260\217\345\222\214.java" | 50 ++++++++------- ...\345\220\214\350\267\257\345\276\204.java" | 2 - ...345\220\214\350\267\257\345\276\2042.java" | 35 ++++------ ...\346\255\243\346\226\271\345\275\242.java" | 56 +++++++++++----- ...\344\275\263\346\227\266\346\234\272.java" | 40 +++++------- ...344\275\263\346\227\266\346\234\2722.java" | 5 +- ...\344\272\244\347\232\204\347\272\277.java" | 53 +++++++++++++++ ...\351\231\244\346\223\215\344\275\234.java" | 2 +- ...\345\255\220\345\272\217\345\210\227.java" | 25 ++++---- ...\345\255\220\345\272\217\345\210\227.java" | 64 +++++++++++++++++++ ...\346\225\260\345\257\271\351\223\276.java" | 44 +++++++++++++ ...\345\267\256\346\225\260\345\210\227.java" | 52 +++++++++++++++ ...\345\255\220\345\272\217\345\210\227.java" | 33 +++++----- ...\347\232\204\344\270\252\346\225\260.java" | 49 ++++++++++++++ 20 files changed, 531 insertions(+), 217 deletions(-) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\2722.java" (84%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\215\347\233\270\344\272\244\347\232\204\347\272\277.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" (97%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\256\232\345\267\256\345\255\220\345\272\217\345\210\227.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\346\225\260\345\257\271\351\223\276.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\347\255\211\345\267\256\346\225\260\345\210\227.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227\347\232\204\344\270\252\346\225\260.java" diff --git a/README.md b/README.md index 0ae606e..a4d1a01 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ build - + code style @@ -404,32 +404,59 @@ | --------------------------------------------------------------------------------- | :--: | :----: | | [509. 斐波那契数](https://leetcode.cn/problems/fibonacci-number/) | 💚 | ✔️ | | [1137. 第 N 个泰波那契数](https://leetcode.cn/problems/n-th-tribonacci-number/) | 💚 | ✔️ | -| [70. 爬楼梯](https://leetcode.cn/problems/climbing-stairs/) | 💚 | ❗ | -| [746. 使用最小花费爬楼梯](https://leetcode.cn/problems/min-cost-climbing-stairs/) | 💚 | ❗ | -| [198. 打家劫舍](https://leetcode.cn/problems/house-robber/) | 💛 | ❌ | -| [740. 删除并获得点数](https://leetcode.cn/problems/delete-and-earn/) | 💛 | ❌ | +| [70. 爬楼梯](https://leetcode.cn/problems/climbing-stairs/) | 💚 | ✔️ | +| [746. 使用最小花费爬楼梯](https://leetcode.cn/problems/min-cost-climbing-stairs/) | 💚 | ✔️ | +| [198. 打家劫舍](https://leetcode.cn/problems/house-robber/) | 💛 | ❗ | +| [740. 删除并获得点数](https://leetcode.cn/problems/delete-and-earn/) | 💛 | ❗ | + +#### 一维 + +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------------------------------------------------ | :--: | :----: | +| [2140. 解决智力问题](https://leetcode.cn/problems/solving-questions-with-brainpower/) | 💛 | | +| [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | 💛 | | +| [2466. 统计构造好字符串的方案数](https://leetcode.cn/problems/count-ways-to-build-good-strings/) | 💛 | | +| [91. 解码方法](https://leetcode.cn/problems/decode-ways/) | 💛 | | +| [983. 最低票价](https://leetcode.cn/problems/minimum-cost-for-tickets/) | 💛 | | +| [790. 多米诺和托米诺平铺](https://leetcode.cn/problems/domino-and-tromino-tiling/) | 💛 | | #### 矩阵 | 题目 | 难度 | 掌握度 | | ----------------------------------------------------------------------------- | :--: | :----: | -| [62. 不同路径](https://leetcode.cn/problems/unique-paths/) | 💛 | ❌ | -| [63. 不同路径 II](https://leetcode.cn/problems/unique-paths-ii/) | 💛 | ❌ | +| [62. 不同路径](https://leetcode.cn/problems/unique-paths/) | 💛 | ❗ | +| [63. 不同路径 II](https://leetcode.cn/problems/unique-paths-ii/) | 💛 | ❗ | | [64. 最小路径和](https://leetcode.cn/problems/minimum-path-sum/) | 💛 | ✔️ | -| [120. 三角形最小路径和](https://leetcode.cn/problems/triangle/) | 💛 | ❌ | -| [931. 下降路径最小和](https://leetcode.cn/problems/minimum-falling-path-sum/) | 💛 | ❌ | -| [221. 最大正方形](https://leetcode.cn/problems/maximal-square/) | 💛 | ❌ | +| [120. 三角形最小路径和](https://leetcode.cn/problems/triangle/) | 💛 | ❗ | +| [931. 下降路径最小和](https://leetcode.cn/problems/minimum-falling-path-sum/) | 💛 | ❗ | +| [221. 最大正方形](https://leetcode.cn/problems/maximal-square/) | 💛 | ❌ | #### 字符串 +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------------------------------ | :--: | :----: | +| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | | | +| | | | +| | | | +| | | | +| | | | +| | | | + +#### 最长递增/公共子序列 + | 题目 | 难度 | 掌握度 | | ------------------------------------------------------------ | :--: | :----: | -| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | | | -| | | | -| | | | -| | | | -| | | | -| | | | +| [300. 最长递增子序列](https://leetcode.cn/problems/longest-increasing-subsequence/) | 💛 | ❌ | +| [673. 最长递增子序列的个数](https://leetcode.cn/problems/number-of-longest-increasing-subsequence/) | 💛 | ❌ | +| [646. 最长数对链](https://leetcode.cn/problems/maximum-length-of-pair-chain/) | 💛 | ✔️ | +| [1218. 最长定差子序列](https://leetcode.cn/problems/longest-arithmetic-subsequence-of-given-difference/) | 💛 | ❌ | +| [1027. 最长等差数列](https://leetcode.cn/problems/longest-arithmetic-subsequence/) | 💛 | ❌ | +| [1143. 最长公共子序列](https://leetcode.cn/problems/longest-common-subsequence/) | 💛 | ❗ | +| [1035. 不相交的线](https://leetcode.cn/problems/uncrossed-lines/) | 💛 | ❌ | +| [583. 两个字符串的删除操作](https://leetcode.cn/problems/delete-operation-for-two-strings/) | 💛 | ❌ | +| [712. 两个字符串的最小ASCII删除和](https://leetcode.cn/problems/minimum-ascii-delete-sum-for-two-strings/) | 💛 | ❌ | + +#### 买卖股票的最佳时间/状态机 #### 其他 @@ -440,9 +467,6 @@ | [354. 俄罗斯套娃信封问题](https://leetcode.cn/problems/russian-doll-envelopes/) | ❤️ | | | [72. 编辑距离](https://leetcode.cn/problems/edit-distance/) | 💛 | ❌ | | [53. 最大子数组和](https://leetcode.cn/problems/maximum-subarray/) | 💛 | ❌ | -| [712. 两个字符串的最小ASCII删除和](https://leetcode.cn/problems/minimum-ascii-delete-sum-for-two-strings/) | 💛 | ❌ | -| [583. 两个字符串的删除操作](https://leetcode.cn/problems/delete-operation-for-two-strings/) | 💛 | ❌ | -| [1143. 最长公共子序列](https://leetcode.cn/problems/longest-common-subsequence/) | 💛 | ❌ | | [416. 分割等和子集](https://leetcode.cn/problems/partition-equal-subset-sum/) | | | | [518. 零钱兑换 II](https://leetcode.cn/problems/coin-change-ii/) | | | diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\344\275\277\347\224\250\346\234\200\345\260\217\350\212\261\350\264\271\347\210\254\346\245\274\346\242\257.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\344\275\277\347\224\250\346\234\200\345\260\217\350\212\261\350\264\271\347\210\254\346\245\274\346\242\257.java" index 31f6dc3..e0d3ca1 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\344\275\277\347\224\250\346\234\200\345\260\217\350\212\261\350\264\271\347\210\254\346\245\274\346\242\257.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\344\275\277\347\224\250\346\234\200\345\260\217\350\212\261\350\264\271\347\210\254\346\245\274\346\242\257.java" @@ -14,22 +14,44 @@ public static void main(String[] args) { Solution s = new Solution(); Assertions.assertEquals(15, s.minCostClimbingStairs(new int[] { 10, 15, 20 })); Assertions.assertEquals(6, s.minCostClimbingStairs(new int[] { 1, 100, 1, 1, 1, 100, 1, 1, 100, 1 })); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals(15, s2.minCostClimbingStairs(new int[] { 10, 15, 20 })); + Assertions.assertEquals(6, s2.minCostClimbingStairs(new int[] { 1, 100, 1, 1, 1, 100, 1, 1, 100, 1 })); } static class Solution { public int minCostClimbingStairs(int[] cost) { - int n = cost.length; - int dp_i_1 = 0, dp_i_2 = 0, dp_i = 0; - for (int i = 2; i <= n; i++) { - dp_i = Math.min( - dp_i_1 + cost[i - 1], - dp_i_2 + cost[i - 2] + if (cost == null || cost.length == 0) { return 0; } + int N = cost.length; + int[] dp = new int[N + 1]; + dp[0] = dp[1] = 0; + for (int i = 2; i <= N; i++) { + dp[i] = Math.min( + dp[i - 1] + cost[i - 1], + dp[i - 2] + cost[i - 2] + ); + } + return dp[N]; + } + + } + + static class Solution2 { + + public int minCostClimbingStairs(int[] cost) { + if (cost == null || cost.length == 0) { return 0; } + int pre1 = 0, pre2 = 0; + for (int i = 2; i <= cost.length; i++) { + int tmp = Math.min( + pre1 + cost[i - 1], + pre2 + cost[i - 2] ); - dp_i_2 = dp_i_1; - dp_i_1 = dp_i; + pre2 = pre1; + pre1 = tmp; } - return dp_i; + return pre1; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" index 43f9bec..c7e952c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" @@ -2,6 +2,8 @@ import org.junit.jupiter.api.Assertions; +import java.util.Arrays; + /** * 740. 删除并获得点数 * @@ -24,26 +26,25 @@ public static void main(String[] args) { static class Solution { public int deleteAndEarn(int[] nums) { - int max = 0; - for (int val : nums) { - max = Math.max(max, val); - } - int[] sums = new int[max + 1]; - for (int val : nums) { - sums[val] += val; + int[] sums = new int[10001]; + for (int num : nums) { + sums[num] += num; } return rob(sums); } public int rob(int[] sums) { - int N = sums.length; - int first = sums[0], second = Math.max(sums[0], sums[1]); - for (int i = 2; i < N; i++) { - int temp = second; - second = Math.max(second, first + sums[i]); - first = temp; + if (sums == null || sums.length == 0) { return 0; } + if (sums.length == 1) { return sums[0]; } + int pre1 = Math.max(sums[0], sums[1]), pre2 = sums[0]; + int max = 0; + for (int i = 2; i < sums.length; i++) { + int tmp = Math.max(pre1, pre2 + sums[i]); + max = Math.max(max, tmp); + pre2 = pre1; + pre1 = tmp; } - return second; + return max; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\211\223\345\256\266\345\212\253\350\210\215.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\211\223\345\256\266\345\212\253\350\210\215.java" index c6ec2e2..9acda1e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\211\223\345\256\266\345\212\253\350\210\215.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\211\223\345\256\266\345\212\253\350\210\215.java" @@ -15,51 +15,21 @@ public static void main(String[] args) { Assertions.assertEquals(4, s.rob(new int[] { 1, 2, 3, 1 })); Assertions.assertEquals(12, s.rob(new int[] { 2, 7, 9, 3, 1 })); Assertions.assertEquals(1, s.rob(new int[] { 1, 1 })); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(4, s2.rob(new int[] { 1, 2, 3, 1 })); - Assertions.assertEquals(12, s2.rob(new int[] { 2, 7, 9, 3, 1 })); - Assertions.assertEquals(1, s2.rob(new int[] { 1, 1 })); } static class Solution { public int rob(int[] nums) { - - int N = nums.length; - if (N <= 1) { return nums[0]; } - - int[] dp = new int[N + 1]; - dp[0] = nums[0]; - dp[1] = Math.max(nums[0], nums[1]); - for (int i = 2; i < N; i++) { - dp[i] = Math.max( - dp[i - 1], - dp[i - 2] + nums[i] - ); - } - - return dp[N - 1]; - } - - } - - /** - * 优化空间复杂度 - */ - static class Solution2 { - - public int rob(int[] nums) { + if (nums == null || nums.length == 0) { return 0; } + if (nums.length == 1) { return nums[0]; } int N = nums.length; - if (N <= 1) { return nums[0]; } - - int cur = Math.max(nums[0], nums[1]), pre = nums[0]; + int first = nums[0], second = Math.max(nums[0], nums[1]); for (int i = 2; i < N; i++) { - int tmp = Math.max(cur, pre + nums[i]); - pre = cur; - cur = tmp; + int tmp = Math.max(second, first + nums[i]); + first = second; + second = tmp; } - return cur; + return second; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\210\254\346\245\274\346\242\257.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\210\254\346\245\274\346\242\257.java" index 63c40b8..2b7f0bf 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\210\254\346\245\274\346\242\257.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\210\254\346\245\274\346\242\257.java" @@ -42,8 +42,7 @@ public int climbStairs(int n) { // 爬上 n−1 阶楼梯的方法数量。因为再爬1阶就能到第n阶 // 爬上 n−2 阶楼梯的方法数量,因为再爬2阶就能到第n阶 public int dp(int n) { - if (n == 0) return 1; - if (n == 1) return 1; + if (n == 0 || n == 1) return 1; if (memo[n] != -1) return memo[n]; memo[n] = dp(n - 1) + dp(n - 2); return memo[n]; @@ -51,19 +50,18 @@ public int dp(int n) { } + // 空间复杂度 o(1) static class Solution2 { public int climbStairs(int n) { - if (n == 0 || n == 1) return 1; - - int[] dp = new int[n + 1]; - dp[0] = 1; - dp[1] = 1; + int pre1 = 1, pre2 = 1; for (int i = 2; i <= n; i++) { - dp[i] = dp[i - 1] + dp[i - 2]; + int tmp = pre1 + pre2; + pre2 = pre1; + pre1 = tmp; } - return dp[n]; + return pre1; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" index c11b5b8..3f21250 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" @@ -24,24 +24,53 @@ public static void main(String[] args) { // 每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。 // 也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。 + + // 示例 1: + // + // 输入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]] + // 输出:11 + // 解释:如下面简图所示: + // 2 + // 3 4 + // 6 5 7 + // 4 1 8 3 + // 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 + // 示例 2: + // + // 输入:triangle = [[-10]] + // 输出:-10 } static class Solution { public int minimumTotal(List> triangle) { + + // base case + if (triangle == null || triangle.size() == 0) { return 0; } + if (triangle.size() == 1) { return triangle.get(0).get(0); } + + // 状态定义 int n = triangle.size(); int[][] dp = new int[n][n]; + + // 初始化 dp[0][0] = triangle.get(0).get(0); - for (int i = 1; i < n; ++i) { - dp[i][0] = dp[i - 1][0] + triangle.get(i).get(0); - for (int j = 1; j < i; ++j) { - dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i - 1][j]) + triangle.get(i).get(j); + + // 状态转移 + int min = Integer.MAX_VALUE; + for (int i = 1; i < n; i++) { + for (int j = 0; j <= i; j++) { + if (j == 0) { + dp[i][j] = dp[i - 1][0] + triangle.get(i).get(0); + } else if (j == i) { + dp[i][j] = dp[i - 1][j - 1] + triangle.get(i).get(j); + } else { + dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i - 1][j]) + triangle.get(i).get(j); + } + if (i == n - 1) { + min = Math.min(min, dp[i][j]); + } } - dp[i][i] = dp[i - 1][i - 1] + triangle.get(i).get(i); - } - int min = dp[n - 1][0]; - for (int i = 1; i < n; ++i) { - min = Math.min(min, dp[n - 1][i]); } return min; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" index cd10af9..ac07d40 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" @@ -2,8 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.Arrays; - /** * 300. 最长递增子序列 * @@ -15,37 +13,43 @@ public class 下降路径最小和 { public static void main(String[] args) { Solution s = new Solution(); Assertions.assertEquals(13, s.minFallingPathSum(new int[][] { { 2, 1, 3 }, { 6, 5, 4 }, { 7, 8, 9 } })); + Assertions.assertEquals(-59, s.minFallingPathSum(new int[][] { { -19, 57 }, { -40, -5 } })); } static class Solution { - int N = 0; - int[][] matrix = null; - int[][] memo = null; - public int minFallingPathSum(int[][] matrix) { - this.matrix = matrix; - this.N = matrix.length; - int res = Integer.MAX_VALUE; - memo = new int[N + 1][N + 1]; - for (int i = 0; i <= N; i++) { - Arrays.fill(memo[i], Integer.MAX_VALUE); + + // base case + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { return 0; } + if (matrix.length == 1) { return matrix[0][0]; } + + // 状态定义 + int n = matrix.length; + int[][] dp = new int[n][n]; + + // 初始化、边界状态 + for (int j = 0; j < n; j++) { + dp[0][j] = matrix[0][j]; } - for (int y = 0; y < N; y++) { - res = Math.min(res, dp(N - 1, y)); + + // 状态转移 + for (int i = 1; i < n; i++) { + dp[i][0] = Math.min(dp[i - 1][0], dp[i - 1][1]) + matrix[i][0]; + for (int j = 1; j < n - 1; j++) { + dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i - 1][j + 1]) + matrix[i][j]; + } + dp[i][n - 1] = Math.min(dp[i - 1][n - 1], dp[i - 1][n - 2]) + matrix[i][n - 1]; } - return res; - } - public int dp(int x, int y) { - if (y < 0 || y >= N) { return Integer.MAX_VALUE; } - if (x == 0) { return matrix[0][y]; } - if (memo[x][y] != Integer.MAX_VALUE) { return memo[x][y]; } - memo[x][y] = matrix[x][y] + min(dp(x - 1, y - 1), dp(x - 1, y), dp(x - 1, y + 1)); - return memo[x][y]; + int min = Integer.MAX_VALUE; + for (int j = 0; j < n; j++) { + min = Math.min(min, dp[n - 1][j]); + } + return min; } - int min(int a, int b, int c) { + public int min(int a, int b, int c) { return Math.min(a, Math.min(b, c)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" index b897805..8931a3e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" @@ -22,10 +22,8 @@ static class Solution { public int uniquePaths(int m, int n) { int[][] dp = new int[m][n]; - // 沿着边界只有一个前进方向 for (int i = 0; i < m; i++) { dp[i][0] = 1; } for (int j = 0; j < n; j++) { dp[0][j] = 1; } - // dp[i][j] 表示到达 (i, j) 的最多路径 for (int i = 1; i < m; i++) { for (int j = 1; j < n; j++) { dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" index 5adc151..3040c6c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" @@ -18,49 +18,38 @@ public static void main(String[] args) { Assertions.assertEquals(1, s.uniquePathsWithObstacles(input2)); int[][] input3 = new int[][] { { 1, 0 } }; Assertions.assertEquals(0, s.uniquePathsWithObstacles(input3)); + int[][] input4 = new int[][] { { 0, 1, 0, 0 } }; + Assertions.assertEquals(0, s.uniquePathsWithObstacles(input4)); } static class Solution { public int uniquePathsWithObstacles(int[][] obstacleGrid) { - if (obstacleGrid == null || obstacleGrid.length == 0 || obstacleGrid[0].length == 0) { - return 0; - } + // 基本校验 + if (obstacleGrid == null || obstacleGrid.length == 0 || obstacleGrid[0].length == 0) { return 0; } int m = obstacleGrid.length, n = obstacleGrid[0].length; + // 起点、终点有障碍,注定无法到达 + if (obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1) { return 0; } - // 如果起点或终点有障碍物,直接返回0 - if (obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1) { - return 0; - } - - // dp[i][j] 表示从起点到 (i,j) 的不同路径数 + // 状态定义 int[][] dp = new int[m][n]; - // 初始化起点 + // 初始化、边界状态 dp[0][0] = 1; + for (int i = 1; i < m; i++) { dp[i][0] = obstacleGrid[i][0] == 1 ? 0 : dp[i - 1][0]; } + for (int j = 1; j < n; j++) { dp[0][j] = obstacleGrid[0][j] == 1 ? 0 : dp[0][j - 1]; } - // 初始化第一列:只能从上边来 - for (int i = 1; i < m; i++) { - dp[i][0] = (obstacleGrid[i][0] == 1) ? 0 : dp[i - 1][0]; - } - // 初始化第一行:只能从左边来 - for (int j = 1; j < n; j++) { - dp[0][j] = (obstacleGrid[0][j] == 1) ? 0 : dp[0][j - 1]; - } - - // 填充dp表 + // 状态转移 for (int i = 1; i < m; i++) { for (int j = 1; j < n; j++) { if (obstacleGrid[i][j] == 1) { - dp[i][j] = 0; // 有障碍物,无法到达 + dp[i][j] = 0; } else { - // 路径数 = 从上边来的路径数 + 从左边来的路径数 dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; } } } - return dp[m - 1][n - 1]; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" index f2c8bd5..876a815 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" @@ -13,34 +13,60 @@ public class 最大正方形 { public static void main(String[] args) { + Solution s = new Solution(); - Assertions.assertEquals(4, s.maximalSquare(new char[][] { - { '1', '0', '1', '0', '0' }, - { '1', '0', '1', '1', '1' }, - { '1', '1', '1', '1', '1' }, - { '1', '0', '0', '1', '0' } - })); + + // char[][] input1 = new char[][] { + // { '1', '0', '1', '0', '0' }, + // { '1', '0', '1', '1', '1' }, + // { '1', '1', '1', '1', '1' }, + // { '1', '0', '0', '1', '0' } + // }; + // Assertions.assertEquals(4, s.maximalSquare(input1)); + // + // char[][] input2 = new char[][] { { '0', '1' }, { '1', '0' } }; + // Assertions.assertEquals(1, s.maximalSquare(input2)); + // + // char[][] input3 = new char[][] { { '0' } }; + // Assertions.assertEquals(0, s.maximalSquare(input3)); + + char[][] input4 = new char[][] { + { '1', '0', '1', '1', '0', '1' }, + { '1', '1', '1', '1', '1', '1' }, + { '0', '1', '1', '0', '1', '1' }, + { '1', '1', '1', '0', '1', '0' }, + { '0', '1', '1', '1', '1', '1' }, + { '1', '1', '0', '1', '1', '1' } + }; + Assertions.assertEquals(4, s.maximalSquare(input4)); } static class Solution { public int maximalSquare(char[][] matrix) { - if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { - return 0; - } + // base case + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { return 0; } + if (matrix.length == 1 && matrix[0][0] == '1') { return 1; } + // 状态定义 int m = matrix.length, n = matrix[0].length; int[][] dp = new int[m][n]; + + // 初始化、边界状态 dp[0][0] = matrix[0][0] == '1' ? 1 : 0; int max = dp[0][0]; - for (int i = 1; i < m; ++i) { - for (int j = 1; j < n; ++j) { - if (matrix[i][j] == '0') { - dp[i][j] = 0; - continue; + + // 状态转移 + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (matrix[i][j] == '1') { + if (i == 0 || j == 0) { + dp[i][j] = 1; + } else { + dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1; + } } - dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1; max = Math.max(max, dp[i][j]); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" index 0ef65ab..af5cc5f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" @@ -3,42 +3,34 @@ import org.junit.jupiter.api.Assertions; /** + * 121. 买卖股票的最佳时机 + * * @author Zhang Peng - * @see 121. 买卖股票的最佳时机 * @since 2020-07-05 */ public class 买卖股票的最佳时机 { public static void main(String[] args) { - int[] prices = { 7, 1, 5, 3, 6, 4 }; - int[] prices2 = { 7, 6, 4, 3, 1 }; - Assertions.assertEquals(5, maxProfit(prices)); - Assertions.assertEquals(0, maxProfit(prices2)); + Solution s = new Solution(); + Assertions.assertEquals(5, s.maxProfit(new int[] { 7, 1, 5, 3, 6, 4 })); + Assertions.assertEquals(0, s.maxProfit(new int[] { 7, 6, 4, 3, 1 })); } - public static int maxProfit(int[] prices) { - if (prices == null || prices.length == 0) return 0; - int n = prices.length; - int max = 0; + static class Solution { - // 定义二维数组 - // 一维表示第 i 天 - // 二维表示交易状态:0 表示没有买卖;1 表示买入;2 表示卖出 - int[][] mp = new int[n][3]; - mp[0][0] = 0; // 无 - mp[0][1] = -prices[0]; // 买 - mp[0][2] = 0; // 当天买进卖出,净赚0 - for (int i = 1; i < n; i++) { - mp[i][0] = mp[i - 1][0]; // 一直不买 - mp[i][1] = Math.max(mp[i - 1][1], mp[i - 1][0] - prices[i]); // 昨天买或今天买 - mp[i][2] = mp[i - 1][1] + prices[i]; // 昨天还有股,今天卖出 - for (int j = 0; j <= 2; j++) { - if (max < mp[i][j]) { - max = mp[i][j]; + public int maxProfit(int[] prices) { + int min = prices[0]; + int max = 0; + for (int i = 1; i < prices.length; i++) { + if (prices[i] <= min) { + min = prices[i]; + } else { + max = Math.max(max, prices[i] - min); } } + return max; } - return max; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\2722.java" similarity index 84% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\2722.java" index d3d8197..98b90e7 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\2722.java" @@ -3,11 +3,12 @@ import org.junit.jupiter.api.Assertions; /** + * 122. 买卖股票的最佳时机 II + * * @author Zhang Peng - * @see 122. 买卖股票的最佳时机 II * @since 2020-07-05 */ -public class 买卖股票的最佳时机II { +public class 买卖股票的最佳时机2 { public static void main(String[] args) { int[] prices = { 7, 1, 5, 3, 6, 4 }; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\215\347\233\270\344\272\244\347\232\204\347\272\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\215\347\233\270\344\272\244\347\232\204\347\272\277.java" new file mode 100644 index 0000000..290ae9d --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\215\347\233\270\344\272\244\347\232\204\347\272\277.java" @@ -0,0 +1,53 @@ +package io.github.dunwu.algorithm.dp.subseq; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 300. 最长递增子序列 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 不相交的线 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(2, s.maxUncrossedLines(new int[] { 1, 4, 2 }, new int[] { 1, 2, 4 })); + } + + static class Solution { + + int[][] memo; + + public int maxUncrossedLines(int[] nums1, int[] nums2) { + memo = new int[nums1.length + 1][nums2.length + 1]; + for (int i = 0; i <= nums1.length; i++) { + Arrays.fill(memo[i], -1); + } + return dp(nums1, 0, nums2, 0); + } + + public int dp(int[] nums1, int i, int[] nums2, int j) { + if (i < 0 || i >= nums1.length || j < 0 || j >= nums2.length) { return 0; } + if (memo[i][j] != -1) { return memo[i][j]; } + if (nums1[i] == nums2[j]) { + memo[i][j] = dp(nums1, i + 1, nums2, j + 1) + 1; + } else { + memo[i][j] = max( + dp(nums1, i, nums2, j + 1), + dp(nums1, i + 1, nums2, j), + dp(nums1, i + 1, nums2, j + 1) + ); + } + return memo[i][j]; + } + + public int max(int a, int b, int c) { + return Math.max(a, Math.max(b, c)); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" similarity index 97% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" index bd82ebf..8559c20 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.dp; +package io.github.dunwu.algorithm.dp.subseq; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.java" index 97c9a7f..cf7c08e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.java" @@ -19,30 +19,29 @@ public static void main(String[] args) { Assertions.assertEquals(0, s.longestCommonSubsequence("abc", "def")); } - /** - * 使用备忘录优化动态规划问题 - */ static class Solution { + private int[][] memo; + public int longestCommonSubsequence(String text1, String text2) { - int[][] memo = new int[text1.length()][text2.length()]; - for (int i = 0; i < text1.length(); i++) { + int m = text1.length(), n = text2.length(); + memo = new int[m + 1][n + 1]; + for (int i = 0; i <= m; i++) { Arrays.fill(memo[i], -1); } - return dp(memo, text1, 0, text2, 0); + return dp(text1, 0, text2, 0); } - public int dp(int[][] memo, String text1, int i, String text2, int j) { - if (i < 0 || j < 0 || i >= text1.length() || j >= text2.length()) { return 0; } + public int dp(String text1, int i, String text2, int j) { + if (i < 0 || i >= text1.length() || j < 0 || j >= text2.length()) { return 0; } if (memo[i][j] != -1) { return memo[i][j]; } - if (text1.charAt(i) == text2.charAt(j)) { - memo[i][j] = 1 + dp(memo, text1, i + 1, text2, j + 1); + memo[i][j] = dp(text1, i + 1, text2, j + 1) + 1; } else { memo[i][j] = max( - dp(memo, text1, i + 1, text2, j), - dp(memo, text1, i, text2, j + 1), - dp(memo, text1, i + 1, text2, j + 1) + dp(text1, i + 1, text2, j), + dp(text1, i, text2, j + 1), + dp(text1, i + 1, text2, j + 1) ); } return memo[i][j]; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\256\232\345\267\256\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\256\232\345\267\256\345\255\220\345\272\217\345\210\227.java" new file mode 100644 index 0000000..d7ae1d4 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\256\232\345\267\256\345\255\220\345\272\217\345\210\227.java" @@ -0,0 +1,64 @@ +package io.github.dunwu.algorithm.dp.subseq; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; +import java.util.Map; + +/** + * 1218. 最长定差子序列 + * + * @author Zhang Peng + * @date 2025-11-14 + */ +public class 最长定差子序列 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(4, s.longestSubsequence(new int[] { 1, 2, 3, 4 }, 1)); + Assertions.assertEquals(1, s.longestSubsequence(new int[] { 1, 3, 5, 7 }, 1)); + Assertions.assertEquals(4, s.longestSubsequence(new int[] { 1, 5, 7, 8, 5, 3, 4, 2, 1 }, -2)); + Assertions.assertEquals(2, s.longestSubsequence(new int[] { 3, 4, -3, -2, -4 }, -5)); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals(4, s2.longestSubsequence(new int[] { 1, 2, 3, 4 }, 1)); + Assertions.assertEquals(1, s2.longestSubsequence(new int[] { 1, 3, 5, 7 }, 1)); + Assertions.assertEquals(4, s2.longestSubsequence(new int[] { 1, 5, 7, 8, 5, 3, 4, 2, 1 }, -2)); + Assertions.assertEquals(2, s2.longestSubsequence(new int[] { 3, 4, -3, -2, -4 }, -5)); + } + + static class Solution { + + public int longestSubsequence(int[] arr, int diff) { + int n = arr.length; + Map map = new HashMap<>(); + int[][] dp = new int[n][2]; + dp[0][1] = 1; + map.put(arr[0], 0); + for (int i = 1; i < n; i++) { + dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]); + dp[i][1] = 1; + int prev = arr[i] - diff; + if (map.containsKey(prev)) dp[i][1] = Math.max(dp[i][1], dp[map.get(prev)][1] + 1); + map.put(arr[i], i); + } + return Math.max(dp[n - 1][0], dp[n - 1][1]); + } + + } + + static class Solution2 { + + public int longestSubsequence(int[] arr, int diff) { + int res = 1; + Map map = new HashMap<>(); + for (int val : arr) { + map.put(val, map.getOrDefault(val - diff, 0) + 1); + res = Math.max(res, map.get(val)); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\346\225\260\345\257\271\351\223\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\346\225\260\345\257\271\351\223\276.java" new file mode 100644 index 0000000..ae2ef0d --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\346\225\260\345\257\271\351\223\276.java" @@ -0,0 +1,44 @@ +package io.github.dunwu.algorithm.dp.subseq; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.Comparator; + +/** + * 646. 最长数对链 + * + * @author Zhang Peng + * @date 2025-11-14 + */ +public class 最长数对链 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[][] input1 = new int[][] { { 1, 2 }, { 2, 3 }, { 3, 4 } }; + Assertions.assertEquals(2, s.findLongestChain(input1)); + + int[][] input2 = new int[][] { { 1, 2 }, { 7, 8 }, { 4, 5 } }; + Assertions.assertEquals(3, s.findLongestChain(input2)); + } + + static class Solution { + + public int findLongestChain(int[][] pairs) { + Arrays.sort(pairs, Comparator.comparingInt(pair -> pair[0])); + int n = pairs.length; + int[] dp = new int[n]; + for (int i = 0; i < n; i++) { + dp[i] = 1; + for (int j = 0; j < i; j++) { + if (pairs[i][0] > pairs[j][1]) { + dp[i] = Math.max(dp[i], dp[j] + 1); + } + } + } + return dp[n - 1]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\347\255\211\345\267\256\346\225\260\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\347\255\211\345\267\256\346\225\260\345\210\227.java" new file mode 100644 index 0000000..e0b1b49 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\347\255\211\345\267\256\346\225\260\345\210\227.java" @@ -0,0 +1,52 @@ +package io.github.dunwu.algorithm.dp.subseq; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; +import java.util.Map; + +/** + * 1027. 最长等差数列 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 最长等差数列 { + + public static void main(String[] args) { + Solution s = new Solution(); + // Assertions.assertEquals(4, s.longestArithSeqLength(new int[] { 3, 6, 9, 12 })); + // Assertions.assertEquals(3, s.longestArithSeqLength(new int[] { 9, 4, 7, 2, 10 })); + Assertions.assertEquals(4, s.longestArithSeqLength(new int[] { 20, 1, 15, 3, 10, 5, 8 })); + } + + static class Solution { + + public int longestArithSeqLength(int[] nums) { + int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE; + for (int num : nums) { + min = Math.min(min, num); + max = Math.max(max, num); + } + + int res = 1; + int maxDiff = max - min; + for (int diff = -maxDiff; diff <= maxDiff; diff++) { + res = Math.max(longestSubsequence(nums, diff), res); + } + return res; + } + + public int longestSubsequence(int[] arr, int diff) { + int res = 1; + Map map = new HashMap<>(); + for (int val : arr) { + map.put(val, map.getOrDefault(val - diff, 0) + 1); + res = Math.max(res, map.get(val)); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227.java" index 5f11659..ad8cb65 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227.java" @@ -2,8 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.Arrays; - /** * 300. 最长递增子序列 * @@ -15,30 +13,31 @@ public class 最长递增子序列 { public static void main(String[] args) { Solution s = new Solution(); Assertions.assertEquals(4, s.lengthOfLIS(new int[] { 10, 9, 2, 5, 3, 7, 101, 18 })); + Assertions.assertEquals(4, s.lengthOfLIS(new int[] { 0, 1, 0, 3, 2, 3 })); + Assertions.assertEquals(1, s.lengthOfLIS(new int[] { 7, 7, 7, 7, 7, 7, 7 })); } - /** - * 使用备忘录优化动态规划问题 - */ static class Solution { public int lengthOfLIS(int[] nums) { - int[] dp = new int[nums.length]; - Arrays.fill(dp, 1); - - for (int i = 0; i < nums.length; i++) { + int n = nums.length; + int[] dp = new int[n]; + int max = 1; + for (int i = 0; i < n; i++) { + dp[i] = 1; for (int j = 0; j < i; j++) { - if (nums[i] > nums[j]) { - dp[i] = Math.max(dp[i], dp[j] + 1); + // 枚举区间 [0,i) 的所有数 nums[j],如果满足 nums[j]300. 最长递增子序列 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 最长递增子序列的个数 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(2, s.findNumberOfLIS(new int[] { 1, 3, 5, 4, 7 })); + Assertions.assertEquals(5, s.findNumberOfLIS(new int[] { 2, 2, 2, 2, 2 })); + } + + static class Solution { + + public int findNumberOfLIS(int[] nums) { + int n = nums.length; + int[] dp = new int[n]; + int[] cnt = new int[n]; + int max = 1; + for (int i = 0; i < n; i++) { + dp[i] = cnt[i] = 1; + for (int j = 0; j < i; j++) { + if (nums[j] < nums[i]) { + if (dp[i] < dp[j] + 1) { + dp[i] = dp[j] + 1; + cnt[i] = cnt[j]; + } else if (dp[i] == dp[j] + 1) { + cnt[i] += cnt[j]; + } + } + } + max = Math.max(max, dp[i]); + } + int res = 0; + for (int i = 0; i < n; i++) { + if (dp[i] == max) res += cnt[i]; + } + return res; + } + + } + +} From a7f801ce9b427a560e1d145c83713deb56db1c62 Mon Sep 17 00:00:00 2001 From: dunwu Date: Mon, 17 Nov 2025 08:29:01 +0800 Subject: [PATCH 13/21] =?UTF-8?q?feat:=20leetcode=20=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 ++--- ...\345\276\227\347\202\271\346\225\260.java" | 34 +++++++----- ...\350\267\257\345\276\204\345\222\214.java" | 43 ++++----------- ...\346\234\200\345\260\217\345\222\214.java" | 4 +- ...\345\220\214\350\267\257\345\276\204.java" | 8 ++- ...345\220\214\350\267\257\345\276\2042.java" | 14 ++--- ...\346\255\243\346\226\271\345\275\242.java" | 54 +++++++++---------- 7 files changed, 78 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index a4d1a01..a7939bf 100644 --- a/README.md +++ b/README.md @@ -406,8 +406,8 @@ | [1137. 第 N 个泰波那契数](https://leetcode.cn/problems/n-th-tribonacci-number/) | 💚 | ✔️ | | [70. 爬楼梯](https://leetcode.cn/problems/climbing-stairs/) | 💚 | ✔️ | | [746. 使用最小花费爬楼梯](https://leetcode.cn/problems/min-cost-climbing-stairs/) | 💚 | ✔️ | -| [198. 打家劫舍](https://leetcode.cn/problems/house-robber/) | 💛 | ❗ | -| [740. 删除并获得点数](https://leetcode.cn/problems/delete-and-earn/) | 💛 | ❗ | +| [198. 打家劫舍](https://leetcode.cn/problems/house-robber/) | 💛 | ✔️ | +| [740. 删除并获得点数](https://leetcode.cn/problems/delete-and-earn/) | 💛 | ✔️ | #### 一维 @@ -424,12 +424,12 @@ | 题目 | 难度 | 掌握度 | | ----------------------------------------------------------------------------- | :--: | :----: | -| [62. 不同路径](https://leetcode.cn/problems/unique-paths/) | 💛 | ❗ | -| [63. 不同路径 II](https://leetcode.cn/problems/unique-paths-ii/) | 💛 | ❗ | +| [62. 不同路径](https://leetcode.cn/problems/unique-paths/) | 💛 | ✔️ | +| [63. 不同路径 II](https://leetcode.cn/problems/unique-paths-ii/) | 💛 | ✔️ | | [64. 最小路径和](https://leetcode.cn/problems/minimum-path-sum/) | 💛 | ✔️ | -| [120. 三角形最小路径和](https://leetcode.cn/problems/triangle/) | 💛 | ❗ | -| [931. 下降路径最小和](https://leetcode.cn/problems/minimum-falling-path-sum/) | 💛 | ❗ | -| [221. 最大正方形](https://leetcode.cn/problems/maximal-square/) | 💛 | ❌ | +| [120. 三角形最小路径和](https://leetcode.cn/problems/triangle/) | 💛 | ✔️ | +| [931. 下降路径最小和](https://leetcode.cn/problems/minimum-falling-path-sum/) | 💛 | ✔️ | +| [221. 最大正方形](https://leetcode.cn/problems/maximal-square/) | 💛 | ❗ | #### 字符串 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" index c7e952c..2442b5b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" @@ -2,8 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.Arrays; - /** * 740. 删除并获得点数 * @@ -26,25 +24,33 @@ public static void main(String[] args) { static class Solution { public int deleteAndEarn(int[] nums) { - int[] sums = new int[10001]; + + if (nums == null || nums.length == 0) { return 0; } + + int n = nums.length; + int max = Integer.MIN_VALUE; + for (int i = 1; i < n; i++) { + max = Math.max(max, nums[i]); + } + + int[] sums = new int[max + 1]; for (int num : nums) { sums[num] += num; } return rob(sums); } - public int rob(int[] sums) { - if (sums == null || sums.length == 0) { return 0; } - if (sums.length == 1) { return sums[0]; } - int pre1 = Math.max(sums[0], sums[1]), pre2 = sums[0]; - int max = 0; - for (int i = 2; i < sums.length; i++) { - int tmp = Math.max(pre1, pre2 + sums[i]); - max = Math.max(max, tmp); - pre2 = pre1; - pre1 = tmp; + public int rob(int[] nums) { + if (nums == null || nums.length == 0) { return 0; } + if (nums.length == 1) { return nums[0]; } + int N = nums.length; + int first = nums[0], second = Math.max(nums[0], nums[1]); + for (int i = 2; i < N; i++) { + int tmp = Math.max(second, first + nums[i]); + first = second; + second = tmp; } - return max; + return second; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" index 3f21250..0fbde05 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" @@ -19,26 +19,6 @@ public static void main(String[] args) { Assertions.assertEquals(11, s.minimumTotal(input)); List> input2 = ArrayUtil.toListList(new int[][] { { -10 } }); Assertions.assertEquals(-10, s.minimumTotal(input2)); - - // 给定一个三角形 triangle ,找出自顶向下的最小路径和。 - - // 每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。 - // 也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。 - - // 示例 1: - // - // 输入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]] - // 输出:11 - // 解释:如下面简图所示: - // 2 - // 3 4 - // 6 5 7 - // 4 1 8 3 - // 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 - // 示例 2: - // - // 输入:triangle = [[-10]] - // 输出:-10 } static class Solution { @@ -53,24 +33,21 @@ public int minimumTotal(List> triangle) { int n = triangle.size(); int[][] dp = new int[n][n]; - // 初始化 + // 初始状态 dp[0][0] = triangle.get(0).get(0); - // 状态转移 + // 状态转移方程 int min = Integer.MAX_VALUE; for (int i = 1; i < n; i++) { - for (int j = 0; j <= i; j++) { - if (j == 0) { - dp[i][j] = dp[i - 1][0] + triangle.get(i).get(0); - } else if (j == i) { - dp[i][j] = dp[i - 1][j - 1] + triangle.get(i).get(j); - } else { - dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i - 1][j]) + triangle.get(i).get(j); - } - if (i == n - 1) { - min = Math.min(min, dp[i][j]); - } + dp[i][0] = triangle.get(i).get(0) + dp[i - 1][0]; + for (int j = 1; j < i; j++) { + dp[i][j] = Math.min(dp[i - 1][j], dp[i - 1][j - 1]) + triangle.get(i).get(j); } + dp[i][i] = dp[i - 1][i - 1] + triangle.get(i).get(i); + } + + for (int j = 0; j < n; j++) { + min = Math.min(min, dp[n - 1][j]); } return min; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" index ac07d40..b1965bc 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Assertions; /** - * 300. 最长递增子序列 + * 931. 下降路径最小和 * * @author Zhang Peng * @date 2025-11-10 @@ -28,7 +28,7 @@ public int minFallingPathSum(int[][] matrix) { int n = matrix.length; int[][] dp = new int[n][n]; - // 初始化、边界状态 + // 初始状态、边界状态 for (int j = 0; j < n; j++) { dp[0][j] = matrix[0][j]; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" index 8931a3e..aa700cf 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" @@ -2,8 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.Arrays; - /** * 62. 不同路径 * @@ -21,9 +19,15 @@ public static void main(String[] args) { static class Solution { public int uniquePaths(int m, int n) { + + // 状态定义 int[][] dp = new int[m][n]; + + // 初始状态、边界状态 for (int i = 0; i < m; i++) { dp[i][0] = 1; } for (int j = 0; j < n; j++) { dp[0][j] = 1; } + + // 状态转移方程 for (int i = 1; i < m; i++) { for (int j = 1; j < n; j++) { dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" index 3040c6c..50295cf 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Assertions; /** - * 62. 不同路径 + * 63. 不同路径 II * * @author Zhang Peng * @date 2025-11-12 @@ -26,8 +26,8 @@ static class Solution { public int uniquePathsWithObstacles(int[][] obstacleGrid) { - // 基本校验 - if (obstacleGrid == null || obstacleGrid.length == 0 || obstacleGrid[0].length == 0) { return 0; } + // base case + if (obstacleGrid == null || obstacleGrid.length == 0) { return 0; } int m = obstacleGrid.length, n = obstacleGrid[0].length; // 起点、终点有障碍,注定无法到达 if (obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1) { return 0; } @@ -35,12 +35,12 @@ public int uniquePathsWithObstacles(int[][] obstacleGrid) { // 状态定义 int[][] dp = new int[m][n]; - // 初始化、边界状态 + // 初始状态、边界状态 dp[0][0] = 1; - for (int i = 1; i < m; i++) { dp[i][0] = obstacleGrid[i][0] == 1 ? 0 : dp[i - 1][0]; } - for (int j = 1; j < n; j++) { dp[0][j] = obstacleGrid[0][j] == 1 ? 0 : dp[0][j - 1]; } + for (int i = 1; i < m; i++) { dp[i][0] = (obstacleGrid[i][0] == 1) ? 0 : dp[i - 1][0]; } + for (int j = 1; j < n; j++) { dp[0][j] = (obstacleGrid[0][j] == 1) ? 0 : dp[0][j - 1]; } - // 状态转移 + // 状态转移方程 for (int i = 1; i < m; i++) { for (int j = 1; j < n; j++) { if (obstacleGrid[i][j] == 1) { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" index 876a815..e72d379 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" @@ -2,8 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.Arrays; - /** * 300. 最长递增子序列 * @@ -16,19 +14,19 @@ public static void main(String[] args) { Solution s = new Solution(); - // char[][] input1 = new char[][] { - // { '1', '0', '1', '0', '0' }, - // { '1', '0', '1', '1', '1' }, - // { '1', '1', '1', '1', '1' }, - // { '1', '0', '0', '1', '0' } - // }; - // Assertions.assertEquals(4, s.maximalSquare(input1)); - // - // char[][] input2 = new char[][] { { '0', '1' }, { '1', '0' } }; - // Assertions.assertEquals(1, s.maximalSquare(input2)); - // - // char[][] input3 = new char[][] { { '0' } }; - // Assertions.assertEquals(0, s.maximalSquare(input3)); + char[][] input1 = new char[][] { + { '1', '0', '1', '0', '0' }, + { '1', '0', '1', '1', '1' }, + { '1', '1', '1', '1', '1' }, + { '1', '0', '0', '1', '0' } + }; + Assertions.assertEquals(4, s.maximalSquare(input1)); + + char[][] input2 = new char[][] { { '0', '1' }, { '1', '0' } }; + Assertions.assertEquals(1, s.maximalSquare(input2)); + + char[][] input3 = new char[][] { { '0' } }; + Assertions.assertEquals(0, s.maximalSquare(input3)); char[][] input4 = new char[][] { { '1', '0', '1', '1', '0', '1' }, @@ -46,28 +44,28 @@ static class Solution { public int maximalSquare(char[][] matrix) { // base case - if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { return 0; } - if (matrix.length == 1 && matrix[0][0] == '1') { return 1; } + if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) { return 0; } // 状态定义 int m = matrix.length, n = matrix[0].length; int[][] dp = new int[m][n]; - // 初始化、边界状态 - dp[0][0] = matrix[0][0] == '1' ? 1 : 0; - int max = dp[0][0]; - - // 状态转移 + // 状态转移方程 + int max = 0; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { - if (matrix[i][j] == '1') { - if (i == 0 || j == 0) { - dp[i][j] = 1; - } else { - dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1; + if (i == 0 || j == 0) { + dp[i][j] = matrix[i][j] == '1' ? 1 : 0; + } else { + if (matrix[i][j] == '1') { + dp[i][j] = min( + dp[i - 1][j], + dp[i][j - 1], + dp[i - 1][j - 1] + ) + 1; } } - max = Math.max(max, dp[i][j]); + max = Math.max(dp[i][j], max); } } return max * max; From c104f2bb7e61b89f04d4a186cfac52d006e4544d Mon Sep 17 00:00:00 2001 From: dunwu Date: Wed, 19 Nov 2025 07:43:43 +0800 Subject: [PATCH 14/21] =?UTF-8?q?feat:=20leetcode=20=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 123 +++++++++-------- ...\347\232\204\345\205\203\347\264\240.java" | 2 +- ...\345\257\271\346\225\260\345\255\227.java" | 52 +++++++ ...\345\257\271\346\225\260\345\255\227.java" | 61 --------- ...\346\226\271\346\241\210\346\225\260.java" | 46 +++++++ ...\345\212\233\351\227\256\351\242\230.java" | 46 +++++++ ...\351\222\261\345\205\221\346\215\242.java" | 41 ++++++ ...\346\255\243\346\226\271\345\275\242.java" | 2 +- ...\351\231\244\346\223\215\344\275\234.java" | 2 +- ...\345\210\240\351\231\244\345\222\214.java" | 46 +++++++ ...\350\257\215\346\213\206\345\210\206.java" | 44 ++++++ ...\346\226\207\345\255\220\344\270\262.java" | 53 ++++++++ ...\345\255\220\345\272\217\345\210\227.java" | 39 ++++++ ...\350\276\221\350\267\235\347\246\273.java" | 57 ++++++++ ...\347\232\204\344\270\252\346\225\260.java" | 2 + ...\350\276\221\350\267\235\347\246\273.java" | 63 --------- ...\351\222\261\345\205\221\346\215\242.java" | 83 ------------ .../DoublyLinkedList.java | 2 +- .../LRUBaseLinkedList.java | 2 +- .../{list => linkedlist}/LRUBasedArray.java | 2 +- .../dunwu/algorithm/linkedlist/ListNode.java | 114 ++++++++++++++++ .../{list => linkedlist}/MyLinkedList.java | 2 +- .../SinglyLinkedList.java | 2 +- ...\346\226\207\351\223\276\350\241\250.java" | 11 +- ...\350\275\254\351\223\276\350\241\250.java" | 62 +++++++++ ...\350\275\254\351\223\276\350\241\250.java" | 44 ++++++ ...350\275\254\351\223\276\350\241\2502.java" | 60 +++++++++ ...\346\225\260\347\233\270\345\212\240.java" | 65 +++++++++ ...346\225\260\347\233\270\345\212\2402.java" | 79 +++++++++++ ...\351\232\224\351\223\276\350\241\250.java" | 101 ++++++++++++++ ...\345\244\215\345\205\203\347\264\240.java" | 15 ++- ...345\244\215\345\205\203\347\264\2402.java" | 62 +++++++++ ...\344\270\252\347\273\223\347\202\271.java" | 59 ++++++++ ...\345\272\217\351\223\276\350\241\250.java" | 67 +++++++++ ...\345\272\217\351\223\276\350\241\250.java" | 51 +++++++ ...\345\275\242\351\223\276\350\241\250.java" | 50 +++++++ ...345\275\242\351\223\276\350\241\2502.java" | 60 +++++++++ ...\344\272\244\351\223\276\350\241\250.java" | 60 +++++++++ ...\344\270\252\350\212\202\347\202\271.java" | 37 +++++ ...\351\227\264\347\273\223\347\202\271.java" | 35 +++++ ...\350\275\254\346\225\264\346\225\260.java" | 14 +- ...\345\244\215\345\205\203\347\264\240.java" | 20 +-- ...\350\241\250\347\244\272\344\276\213.java" | 2 +- ...\350\241\250\347\244\272\344\276\213.java" | 2 +- ...\345\201\266\351\223\276\350\241\250.java" | 7 +- ...\345\272\217\351\223\276\350\241\250.java" | 14 +- ...\345\244\215\350\212\202\347\202\271.java" | 6 +- ...\350\241\250\345\205\203\347\264\240.java" | 24 ++-- ...\350\256\241\351\223\276\350\241\250.java" | 2 +- ...\350\275\254\351\223\276\350\241\250.java" | 127 ------------------ .../github/dunwu/algorithm/list/ListNode.java | 57 -------- .../github/dunwu/algorithm/list/ListUtil.java | 63 --------- ...\346\225\260\347\233\270\345\212\240.java" | 64 --------- ...46\225\260\347\233\270\345\212\240II.java" | 79 ----------- ...\351\232\224\351\223\276\350\241\250.java" | 52 ------- ...45\244\215\345\205\203\347\264\240II.java" | 91 ------------- ...\344\270\252\347\273\223\347\202\271.java" | 54 -------- ...\350\275\254\351\223\276\350\241\250.java" | 88 ------------ ...50\275\254\351\223\276\350\241\250II.java" | 60 --------- ...\345\272\217\351\223\276\350\241\250.java" | 112 --------------- ...\345\272\217\351\223\276\350\241\250.java" | 42 ------ ...\345\275\242\351\223\276\350\241\250.java" | 43 ------ ...45\275\242\351\223\276\350\241\250II.java" | 48 ------- ...\344\272\244\351\223\276\350\241\250.java" | 54 -------- ...\344\270\252\350\212\202\347\202\271.java" | 40 ------ ...\351\227\264\347\273\223\347\202\271.java" | 41 ------ ...\346\216\222\351\223\276\350\241\250.java" | 11 +- .../algorithm/list/DoubleLinkListTests.java | 1 + .../algorithm/list/SingleLinkListTests.java | 1 + 69 files changed, 1564 insertions(+), 1459 deletions(-) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" (96%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\347\273\237\350\256\241\346\236\204\351\200\240\345\245\275\345\255\227\347\254\246\344\270\262\347\232\204\346\226\271\346\241\210\346\225\260.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\247\243\345\206\263\346\231\272\345\212\233\351\227\256\351\242\230.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\351\233\266\351\222\261\345\205\221\346\215\242.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" (97%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\346\234\200\345\260\217ASCII\345\210\240\351\231\244\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\345\215\225\350\257\215\346\213\206\345\210\206.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\345\272\217\345\210\227.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\347\274\226\350\276\221\350\267\235\347\246\273.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\347\274\226\350\276\221\350\267\235\347\246\273.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\242.java" rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{list => linkedlist}/DoublyLinkedList.java (99%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{list => linkedlist}/LRUBaseLinkedList.java (98%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{list => linkedlist}/LRUBasedArray.java (98%) create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/ListNode.java rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{list => linkedlist}/MyLinkedList.java (99%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{list => linkedlist}/SinglyLinkedList.java (99%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" (83%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\2502.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\344\270\244\346\225\260\347\233\270\345\212\240.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\344\270\244\346\225\260\347\233\270\345\212\2402.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\206\351\232\224\351\223\276\350\241\250.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" (71%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\2402.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\216\257\345\275\242\351\223\276\350\241\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\216\257\345\275\242\351\223\276\350\241\2502.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\233\270\344\272\244\351\223\276\350\241\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" (85%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" (82%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" (98%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" (98%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\245\207\345\201\266\351\223\276\350\241\250.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\245\207\345\201\266\351\223\276\350\241\250.java" (78%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\346\216\222\345\272\217\351\223\276\350\241\250.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\346\216\222\345\272\217\351\223\276\350\241\250.java" (88%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" (90%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" (77%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\256\276\350\256\241\351\223\276\350\241\250.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\350\256\276\350\256\241\351\223\276\350\241\250.java" (98%) delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" delete mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListNode.java delete mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListUtil.java delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\206\351\232\224\351\223\276\350\241\250.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" diff --git a/README.md b/README.md index a7939bf..0943177 100644 --- a/README.md +++ b/README.md @@ -60,46 +60,43 @@ ### 链表 -#### 双指针技巧秒杀七道链表题目 - -| 题目 | 掌握度 | -| ------------------------------------------------------------------------------------------------------------------ | ------ | -| [141. 环形链表](https://leetcode.cn/problems/linked-list-cycle/) | ✔️ | -| [142. 环形链表 II](https://leetcode.cn/problems/linked-list-cycle-ii/) | ✔️ | -| [160. 相交链表](https://leetcode.cn/problems/intersection-of-two-linked-lists/) | ✔️ | -| [19. 删除链表的倒数第 N 个结点](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/) | ✔️ | -| [21. 合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/) | ✔️ | -| [23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/) | ✔️ | -| [86. 分隔链表](https://leetcode.cn/problems/partition-list/) | ✔️ | -| [876. 链表的中间结点](https://leetcode.cn/problems/middle-of-the-linked-list/) | ✔️ | -| [剑指 Offer 22. 链表中倒数第 k 个节点](https://leetcode.cn/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/) | ✔️ | - -#### 【练习】链表双指针经典习题 +#### 双指针技巧 + +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------------------------------------------------------ | ---- | ------ | +| [141. 环形链表](https://leetcode.cn/problems/linked-list-cycle/) | 💚 | ✔️ | +| [142. 环形链表 II](https://leetcode.cn/problems/linked-list-cycle-ii/) | 💛 | ❗ | +| [160. 相交链表](https://leetcode.cn/problems/intersection-of-two-linked-lists/) | 💚 | ✔️ | +| [19. 删除链表的倒数第 N 个结点](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/) | 💛 | ✔️ | +| [21. 合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/) | 💚 | ✔️ | +| [23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/) | ❤️ | ✔️ | +| [86. 分隔链表](https://leetcode.cn/problems/partition-list/) | 💛 | ✔️ | +| [876. 链表的中间结点](https://leetcode.cn/problems/middle-of-the-linked-list/) | 💚 | ✔️ | +| [面试题 02. 返回倒数第 k 个节点](https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/) | 💚 | ✔️ | +| [82. 删除排序链表中的重复元素 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/) | 💛 | ❗ | +| [2. 两数相加](https://leetcode.cn/problems/add-two-numbers/) | 💛 | ✔️ | +| [445. 两数相加 II](https://leetcode.cn/problems/add-two-numbers-ii/) | 💛 | ✔️ | + +#### 单链表反转 -| 题目 | 掌握度 | -| ------------------------------------------------------------------------------------------------------ | ------ | -| [82. 删除排序链表中的重复元素 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/) | ✔️ | -| [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | ❌ | -| [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | ❌ | -| [2. 两数相加](https://leetcode.cn/problems/add-two-numbers/) | ✔️ | -| [445. 两数相加 II](https://leetcode.cn/problems/add-two-numbers-ii/) | ✔️ | - -#### 如何判断回文链表 +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------------------------------ | ---- | ------ | +| [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/) | 💚 | ✔️ | +| [92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/) | 💛 | ❗ | +| [25. K 个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group/) | ❤️ | ❗ | -#### 单链表的花式反转方法汇总 +#### 回文链表 -| 题目 | 掌握度 | -| ------------------------------------------------------------------------------ | ------ | -| [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/) | ❌ | -| [92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/) | ❗ | -| [25. K 个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group/) | ❗ | +| 题目 | 难度 | 掌握度 | +| --------------------------------------------------------------------- | ---- | ------ | +| [234. 回文链表](https://leetcode.cn/problems/palindrome-linked-list/) | 💚 | ❌ | ### 数组 -#### 双指针技巧秒杀七道数组题目 +#### 双指针技巧 | 题目 | 掌握度 | -| ------------------------------------------------------------------------------------------------------ | ------ | +| ------------------------------------------------------------------------------------------------------ | ------ | --- | | [26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/) | ✔️ | | [27. 移除元素](https://leetcode.cn/problems/remove-element/) | ✔️ | | [283. 移动零](https://leetcode.cn/problems/move-zeroes/) | ✔️ | @@ -110,6 +107,8 @@ | [LCR 006. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/kLl5u1/) | ✔️ | | [344. 反转字符串](https://leetcode.cn/problems/reverse-string/) | ✔️ | | [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | ❌ | +| [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | 💛 | ❌ | +| [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | 💛 | ❌ | #### 数组双指针经典习题 @@ -413,8 +412,8 @@ | 题目 | 难度 | 掌握度 | | ------------------------------------------------------------------------------------------------ | :--: | :----: | -| [2140. 解决智力问题](https://leetcode.cn/problems/solving-questions-with-brainpower/) | 💛 | | -| [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | 💛 | | +| [2140. 解决智力问题](https://leetcode.cn/problems/solving-questions-with-brainpower/) | 💛 | ❌ | +| [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | 💛 | ❌ | | [2466. 统计构造好字符串的方案数](https://leetcode.cn/problems/count-ways-to-build-good-strings/) | 💛 | | | [91. 解码方法](https://leetcode.cn/problems/decode-ways/) | 💛 | | | [983. 最低票价](https://leetcode.cn/problems/minimum-cost-for-tickets/) | 💛 | | @@ -429,46 +428,44 @@ | [64. 最小路径和](https://leetcode.cn/problems/minimum-path-sum/) | 💛 | ✔️ | | [120. 三角形最小路径和](https://leetcode.cn/problems/triangle/) | 💛 | ✔️ | | [931. 下降路径最小和](https://leetcode.cn/problems/minimum-falling-path-sum/) | 💛 | ✔️ | -| [221. 最大正方形](https://leetcode.cn/problems/maximal-square/) | 💛 | ❗ | +| [221. 最大正方形](https://leetcode.cn/problems/maximal-square/) | 💛 | ✔️ | #### 字符串 -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------------------------ | :--: | :----: | -| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | | | -| | | | -| | | | -| | | | -| | | | -| | | | +| 题目 | 难度 | 掌握度 | +| ---------------------------------------------------------------------------------------------------------- | :--: | :----: | +| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 💛 | ❌ | +| [139. 单词拆分](https://leetcode.cn/problems/word-break/) | 💛 | ❌ | +| [516. 最长回文子序列](https://leetcode.cn/problems/longest-palindromic-subsequence/) | 💛 | ❌ | +| [72. 编辑距离](https://leetcode.cn/problems/edit-distance/) | 💛 | ❗ | +| [583. 两个字符串的删除操作](https://leetcode.cn/problems/delete-operation-for-two-strings/) | 💛 | | +| [712. 两个字符串的最小ASCII删除和](https://leetcode.cn/problems/minimum-ascii-delete-sum-for-two-strings/) | 💛 | ❌ | +| [115. 不同的子序列](https://leetcode.cn/problems/distinct-subsequences/) | ❤️ | ❌ | #### 最长递增/公共子序列 -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------ | :--: | :----: | -| [300. 最长递增子序列](https://leetcode.cn/problems/longest-increasing-subsequence/) | 💛 | ❌ | -| [673. 最长递增子序列的个数](https://leetcode.cn/problems/number-of-longest-increasing-subsequence/) | 💛 | ❌ | -| [646. 最长数对链](https://leetcode.cn/problems/maximum-length-of-pair-chain/) | 💛 | ✔️ | -| [1218. 最长定差子序列](https://leetcode.cn/problems/longest-arithmetic-subsequence-of-given-difference/) | 💛 | ❌ | -| [1027. 最长等差数列](https://leetcode.cn/problems/longest-arithmetic-subsequence/) | 💛 | ❌ | -| [1143. 最长公共子序列](https://leetcode.cn/problems/longest-common-subsequence/) | 💛 | ❗ | -| [1035. 不相交的线](https://leetcode.cn/problems/uncrossed-lines/) | 💛 | ❌ | -| [583. 两个字符串的删除操作](https://leetcode.cn/problems/delete-operation-for-two-strings/) | 💛 | ❌ | -| [712. 两个字符串的最小ASCII删除和](https://leetcode.cn/problems/minimum-ascii-delete-sum-for-two-strings/) | 💛 | ❌ | +| 题目 | 难度 | 掌握度 | +| --------------------------------------------------------------------------------------------------------------------------- | :--: | :----: | +| [300. 最长递增子序列](https://leetcode.cn/problems/longest-increasing-subsequence/) | 💛 | ❌ | +| [673. 最长递增子序列的个数](https://leetcode.cn/problems/number-of-longest-increasing-subsequence/) | 💛 | ❌ | +| [646. 最长数对链](https://leetcode.cn/problems/maximum-length-of-pair-chain/) | 💛 | ✔️ | +| [1218. 最长定差子序列](https://leetcode.cn/problems/longest-arithmetic-subsequence-of-given-difference/) | 💛 | ❌ | +| [1027. 最长等差数列](https://leetcode.cn/problems/longest-arithmetic-subsequence/) | 💛 | ❌ | +| [1143. 最长公共子序列](https://leetcode.cn/problems/longest-common-subsequence/) | 💛 | ❗ | +| [1035. 不相交的线](https://leetcode.cn/problems/uncrossed-lines/) | 💛 | ❌ | +| [1312. 让字符串成为回文串的最少插入次数](https://leetcode.cn/problems/minimum-insertion-steps-to-make-a-string-palindrome/) | ❤️ | ❌ | #### 买卖股票的最佳时间/状态机 #### 其他 -| 题目 | 难度 | 掌握度 | -| ---------------------------------------------------------------------------------------------------------- | ---- | ------ | -| [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | 💛 | ❌ | -| [300. 最长递增子序列](https://leetcode.cn/problems/longest-increasing-subsequence/) | 💛 | ❌ | -| [354. 俄罗斯套娃信封问题](https://leetcode.cn/problems/russian-doll-envelopes/) | ❤️ | | -| [72. 编辑距离](https://leetcode.cn/problems/edit-distance/) | 💛 | ❌ | -| [53. 最大子数组和](https://leetcode.cn/problems/maximum-subarray/) | 💛 | ❌ | -| [416. 分割等和子集](https://leetcode.cn/problems/partition-equal-subset-sum/) | | | -| [518. 零钱兑换 II](https://leetcode.cn/problems/coin-change-ii/) | | | +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------------------------------- | ---- | ------ | +| [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | 💛 | ❌ | +| [354. 俄罗斯套娃信封问题](https://leetcode.cn/problems/russian-doll-envelopes/) | ❤️ | | +| [53. 最大子数组和](https://leetcode.cn/problems/maximum-subarray/) | 💛 | ❌ | +| [416. 分割等和子集](https://leetcode.cn/problems/partition-equal-subset-sum/) | | | +| [518. 零钱兑换 II](https://leetcode.cn/problems/coin-change-ii/) | | | ### 贪心算法 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" index 05de84d..a50a3d0 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.array; +package io.github.dunwu.algorithm.array.two_pointer; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" new file mode 100644 index 0000000..89cfd6a --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" @@ -0,0 +1,52 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import cn.hutool.json.JSONUtil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.PriorityQueue; + +/** + * 373. 查找和最小的 K 对数字 + * + * @author Zhang Peng + * @date 2025-01-21 + */ +public class 查找和最小的K对数字 { + + public static void main(String[] args) { + Solution s = new Solution(); + List> expectList1 = new ArrayList<>(); + expectList1.add(Arrays.asList(1, 2)); + expectList1.add(Arrays.asList(1, 4)); + expectList1.add(Arrays.asList(1, 6)); + List> list1 = s.kSmallestPairs(new int[] { 1, 7, 11 }, new int[] { 2, 4, 6 }, 3); + System.out.println(JSONUtil.toJsonStr(list1)); + + List> list2 = s.kSmallestPairs(new int[] { 1, 1, 2 }, new int[] { 1, 2, 3 }, 2); + System.out.println(JSONUtil.toJsonStr(list2)); + } + + static class Solution { + + public List> kSmallestPairs(int[] nums1, int[] nums2, int k) { + PriorityQueue queue = new PriorityQueue<>(Comparator.comparingInt(a -> (a[0] + a[1]))); + for (int i = 0; i < nums1.length; i++) { + for (int j = 0; j < nums2.length; j++) { + queue.offer(new int[] { nums1[i], nums2[j] }); + } + } + + List> res = new ArrayList<>(); + for (int i = 0; i < k; i++) { + int[] element = queue.poll(); + res.add(Arrays.asList(element[0], element[1])); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" deleted file mode 100644 index f0ad557..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" +++ /dev/null @@ -1,61 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import cn.hutool.json.JSONUtil; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.PriorityQueue; - -/** - * 373. 查找和最小的 K 对数字 - * - * @author Zhang Peng - * @date 2025-01-21 - */ -public class 查找和最小的K对数字 { - - public static void main(String[] args) { - List> expectList1 = new ArrayList<>(); - expectList1.add(Arrays.asList(1, 2)); - expectList1.add(Arrays.asList(1, 4)); - expectList1.add(Arrays.asList(1, 6)); - List> list1 = kSmallestPairs(new int[] { 1, 7, 11 }, new int[] { 2, 4, 6 }, 3); - System.out.println(JSONUtil.toJsonStr(list1)); - - List> list2 = kSmallestPairs(new int[] { 1, 1, 2 }, new int[] { 1, 2, 3 }, 2); - System.out.println(JSONUtil.toJsonStr(list2)); - } - - public static List> kSmallestPairs(int[] nums1, int[] nums2, int k) { - - // 存储三元组 (num1[i], nums2[i], i) - // i 记录 nums2 元素的索引位置,用于生成下一个节点 - PriorityQueue pq = new PriorityQueue<>((a, b) -> { - // 按照数对的元素和升序排序 - return (a[0] + a[1]) - (b[0] + b[1]); - }); - for (int i = 0; i < nums1.length; i++) { - pq.offer(new int[] { nums1[i], nums2[0], 0 }); - } - - List> list = new ArrayList<>(); - // 执行合并多个有序链表的逻辑 - while (!pq.isEmpty() && k > 0) { - int[] cur = pq.poll(); - k--; - // 链表中的下一个节点加入优先级队列 - int next = cur[2] + 1; - if (next < nums2.length) { - pq.add(new int[] { cur[0], nums2[next], next }); - } - - List pair = new ArrayList<>(); - pair.add(cur[0]); - pair.add(cur[1]); - list.add(pair); - } - return list; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\347\273\237\350\256\241\346\236\204\351\200\240\345\245\275\345\255\227\347\254\246\344\270\262\347\232\204\346\226\271\346\241\210\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\347\273\237\350\256\241\346\236\204\351\200\240\345\245\275\345\255\227\347\254\246\344\270\262\347\232\204\346\226\271\346\241\210\346\225\260.java" new file mode 100644 index 0000000..d81d25f --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\347\273\237\350\256\241\346\236\204\351\200\240\345\245\275\345\255\227\347\254\246\344\270\262\347\232\204\346\226\271\346\241\210\346\225\260.java" @@ -0,0 +1,46 @@ +package io.github.dunwu.algorithm.dp.array; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 2466. 统计构造好字符串的方案数 + * + * @author Zhang Peng + * @since 2025-11-17 + */ +public class 统计构造好字符串的方案数 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(8, s.countGoodStrings(3, 3, 1, 1)); + Assertions.assertEquals(5, s.countGoodStrings(2, 3, 1, 2)); + } + + static class Solution { + + int[] memo = null; + private static final int MOD = 1_000_000_007; + + public int countGoodStrings(int low, int high, int zero, int one) { + memo = new int[high + 1]; + Arrays.fill(memo, -1); + int res = 0; + for (int i = low; i <= high; i++) { + res = (res + dp(i, zero, one)) % MOD; + } + return res; + } + + public int dp(int i, int zero, int one) { + if (i < 0) { return 0; } + if (i == 0) { return 1; } + if (memo[i] != -1) { return memo[i]; } + memo[i] = (dp(i - zero, zero, one) + dp(i - one, zero, one)) % MOD; + return memo[i]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\247\243\345\206\263\346\231\272\345\212\233\351\227\256\351\242\230.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\247\243\345\206\263\346\231\272\345\212\233\351\227\256\351\242\230.java" new file mode 100644 index 0000000..5126e91 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\247\243\345\206\263\346\231\272\345\212\233\351\227\256\351\242\230.java" @@ -0,0 +1,46 @@ +package io.github.dunwu.algorithm.dp.array; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 2140. 解决智力问题 + * + * @author Zhang Peng + * @date 2025-11-17 + */ +public class 解决智力问题 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(5, s.mostPoints(new int[][] { { 3, 2 }, { 4, 3 }, { 4, 4 }, { 2, 5 } })); + Assertions.assertEquals(7, s.mostPoints(new int[][] { { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 } })); + } + + static class Solution { + + long[] memo; + + public long mostPoints(int[][] questions) { + if (questions == null || questions.length == 0) { return 0; } + memo = new long[questions.length + 1]; + Arrays.fill(memo, -1); + return dp(questions, 0); + } + + public long dp(int[][] questions, int i) { + if (i < 0 || i >= questions.length) { return 0L; } + if (memo[i] != -1) { return memo[i]; } + int score = questions[i][0]; + int skip = questions[i][1]; + memo[i] = Math.max( + dp(questions, i + 1), + dp(questions, i + skip + 1) + score + ); + return memo[i]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\351\233\266\351\222\261\345\205\221\346\215\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\351\233\266\351\222\261\345\205\221\346\215\242.java" new file mode 100644 index 0000000..b568e1e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\351\233\266\351\222\261\345\205\221\346\215\242.java" @@ -0,0 +1,41 @@ +package io.github.dunwu.algorithm.dp.array; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 322. 零钱兑换 + * + * @author Zhang Peng + * @since 2025-11-17 + */ +public class 零钱兑换 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(3, s.coinChange(new int[] { 1, 2, 5 }, 11)); + Assertions.assertEquals(-1, s.coinChange(new int[] { 2 }, 3)); + Assertions.assertEquals(0, s.coinChange(new int[] { 1 }, 0)); + } + + static class Solution { + + public int coinChange(int[] coins, int amount) { + if (coins == null || coins.length == 0) { return 0; } + int[] dp = new int[amount + 1]; + Arrays.fill(dp, amount + 1); + dp[0] = 0; + for (int i = 1; i <= amount; i++) { + for (int coin : coins) { + if (i - coin >= 0) { + dp[i] = Math.min(dp[i], dp[i - coin] + 1); + } + } + } + return (dp[amount] > amount) ? -1 : dp[amount]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" index e72d379..2d4926a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Assertions; /** - * 300. 最长递增子序列 + * 221. 最大正方形 * * @author Zhang Peng * @date 2025-11-10 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" similarity index 97% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" index 8559c20..a3df26e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.dp.subseq; +package io.github.dunwu.algorithm.dp.str; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\346\234\200\345\260\217ASCII\345\210\240\351\231\244\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\346\234\200\345\260\217ASCII\345\210\240\351\231\244\345\222\214.java" new file mode 100644 index 0000000..18a5317 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\346\234\200\345\260\217ASCII\345\210\240\351\231\244\345\222\214.java" @@ -0,0 +1,46 @@ +package io.github.dunwu.algorithm.dp.str; + +import org.junit.jupiter.api.Assertions; + +/** + * 712. 两个字符串的最小ASCII删除和 + * + * @author Zhang Peng + * @since 2020-07-06 + */ +public class 两个字符串的最小ASCII删除和 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(231, s.minimumDeleteSum("sea", "eat")); + Assertions.assertEquals(403, s.minimumDeleteSum("delete", "leet")); + } + + static class Solution { + + public int minimumDeleteSum(String s1, String s2) { + int m = s1.length(), n = s2.length(); + int[][] dp = new int[m + 1][n + 1]; + for (int i = 1; i <= m; i++) { + dp[i][0] = dp[i - 1][0] + s1.codePointAt(i - 1); + } + for (int j = 1; j <= n; j++) { + dp[0][j] = dp[0][j - 1] + s2.codePointAt(j - 1); + } + for (int i = 1; i <= m; i++) { + int code1 = s1.codePointAt(i - 1); + for (int j = 1; j <= n; j++) { + int code2 = s2.codePointAt(j - 1); + if (code1 == code2) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = Math.min(dp[i - 1][j] + code1, dp[i][j - 1] + code2); + } + } + } + return dp[m][n]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\345\215\225\350\257\215\346\213\206\345\210\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\345\215\225\350\257\215\346\213\206\345\210\206.java" new file mode 100644 index 0000000..582260b --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\345\215\225\350\257\215\346\213\206\345\210\206.java" @@ -0,0 +1,44 @@ +package io.github.dunwu.algorithm.dp.str; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * 139. 单词拆分 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 单词拆分 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.wordBreak("leetcode", Arrays.asList("leet", "code"))); + Assertions.assertTrue(s.wordBreak("applepenapple", Arrays.asList("apple", "pen"))); + Assertions.assertFalse(s.wordBreak("catsandog", Arrays.asList("cats", "dog", "sand", "and", "cat"))); + } + + static class Solution { + + public boolean wordBreak(String s, List wordDict) { + Set set = new HashSet<>(wordDict); + boolean[] dp = new boolean[s.length() + 1]; + dp[0] = true; + for (int i = 1; i <= s.length(); i++) { + for (int j = 0; j < i; j++) { + if (dp[j] && set.contains(s.substring(j, i))) { + dp[i] = true; + break; + } + } + } + return dp[s.length()]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" new file mode 100644 index 0000000..3734a30 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" @@ -0,0 +1,53 @@ +package io.github.dunwu.algorithm.dp.str; + +import org.junit.jupiter.api.Assertions; + +/** + * 5. 最长回文子串 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 最长回文子串 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals("bab", s.longestPalindrome("babad")); + Assertions.assertEquals("bb", s.longestPalindrome("cbbd")); + Assertions.assertEquals("a", s.longestPalindrome("a")); + } + + static class Solution { + + public String longestPalindrome(String s) { + String max = ""; + for (int i = 0; i < s.length(); i++) { + for (int j = i; j < s.length(); j++) { + if (isPalindrome(s, i, j)) { + // System.out.println("s = " + s.substring(i, j + 1)); + if (max.length() < (j - i + 1)) { + max = s.substring(i, j + 1); + } + } + } + } + return max; + } + + public boolean isPalindrome(String s, int left, int right) { + if (s == null || s.length() == 0) { return false; } + if (left == right) { return true; } + if (left > right) { return false; } + while (left <= right) { + if (s.charAt(left) != s.charAt(right)) { + return false; + } + left++; + right--; + } + return true; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\345\272\217\345\210\227.java" new file mode 100644 index 0000000..4104ba8 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\345\272\217\345\210\227.java" @@ -0,0 +1,39 @@ +package io.github.dunwu.algorithm.dp.str; + +import org.junit.jupiter.api.Assertions; + +/** + * 516. 最长回文子序列 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 最长回文子序列 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(4, s.longestPalindromeSubseq("bbbab")); + Assertions.assertEquals(2, s.longestPalindromeSubseq("v")); + } + + static class Solution { + + public int longestPalindromeSubseq(String s) { + int n = s.length(); + int[][] dp = new int[n][n]; + for (int i = n - 1; i >= 0; i--) { + dp[i][i] = 1; + for (int j = i + 1; j < n; j++) { + if (s.charAt(i) == s.charAt(j)) { + dp[i][j] = dp[i + 1][j - 1] + 2; + } else { + dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]); + } + } + } + return dp[0][n - 1]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\347\274\226\350\276\221\350\267\235\347\246\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\347\274\226\350\276\221\350\267\235\347\246\273.java" new file mode 100644 index 0000000..2dc83a4 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\347\274\226\350\276\221\350\267\235\347\246\273.java" @@ -0,0 +1,57 @@ +package io.github.dunwu.algorithm.dp.str; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 72. 编辑距离 + * + * @author Zhang Peng + * @since 2020-07-06 + */ +public class 编辑距离 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(3, s.minDistance("horse", "ros")); + Assertions.assertEquals(5, s.minDistance("intention", "execution")); + } + + static class Solution { + + int[][] memo; + + public int minDistance(String word1, String word2) { + memo = new int[word1.length()][word2.length()]; + for (int i = 0; i < word1.length(); i++) { + Arrays.fill(memo[i], Integer.MAX_VALUE); + } + return dp(word1, 0, word2, 0); + } + + public int dp(String word1, int i, String word2, int j) { + if (i >= word1.length()) { return word2.length() - j; } + if (j >= word2.length()) { return word1.length() - i; } + if (memo[i][j] != Integer.MAX_VALUE) { + return memo[i][j]; + } + if (word1.charAt(i) == word2.charAt(j)) { + memo[i][j] = dp(word1, i + 1, word2, j + 1); + } else { + memo[i][j] = min( + dp(word1, i + 1, word2, j), + dp(word1, i, word2, j + 1), + dp(word1, i + 1, word2, j + 1) + ) + 1; + } + return memo[i][j]; + } + + public int min(int a, int b, int c) { + return Math.min(a, Math.min(b, c)); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227\347\232\204\344\270\252\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227\347\232\204\344\270\252\346\225\260.java" index ef681fe..3c687b1 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227\347\232\204\344\270\252\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227\347\232\204\344\270\252\346\225\260.java" @@ -14,11 +14,13 @@ public static void main(String[] args) { Solution s = new Solution(); Assertions.assertEquals(2, s.findNumberOfLIS(new int[] { 1, 3, 5, 4, 7 })); Assertions.assertEquals(5, s.findNumberOfLIS(new int[] { 2, 2, 2, 2, 2 })); + Assertions.assertEquals(3, s.findNumberOfLIS(new int[] { 1, 2, 4, 3, 5, 4, 7, 2 })); } static class Solution { public int findNumberOfLIS(int[] nums) { + int n = nums.length; int[] dp = new int[n]; int[] cnt = new int[n]; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\347\274\226\350\276\221\350\267\235\347\246\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\347\274\226\350\276\221\350\267\235\347\246\273.java" deleted file mode 100644 index 85dc76a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\347\274\226\350\276\221\350\267\235\347\246\273.java" +++ /dev/null @@ -1,63 +0,0 @@ -package io.github.dunwu.algorithm.dp; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * 72. 编辑距离 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 编辑距离 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(3, s.minDistance("horse", "ros")); - Assertions.assertEquals(5, s.minDistance("intention", "execution")); - } - - static class Solution { - - int[][] memo = null; - - public int minDistance(String word1, String word2) { - memo = new int[word1.length() + 1][word2.length() + 1]; - for (int i = 0; i <= word1.length(); i++) { - Arrays.fill(memo[i], -1); - } - return dp(word1, word1.length() - 1, word2, word2.length() - 1); - } - - public int dp(String s1, int i, String s2, int j) { - - // base case - if (i == -1) return j + 1; - if (j == -1) return i + 1; - - if (memo[i][j] != -1) { return memo[i][j]; } - - // 字符相等,啥也不做 - if (s1.charAt(i) == s2.charAt(j)) { - memo[i][j] = dp(s1, i - 1, s2, j - 1); - } else { - memo[i][j] = min( - // 插入 - dp(s1, i, s2, j - 1) + 1, - // 删除 - dp(s1, i - 1, s2, j) + 1, - // 替换 - dp(s1, i - 1, s2, j - 1) + 1 - ); - } - return memo[i][j]; - } - - public int min(int a, int b, int c) { - return Math.min(a, Math.min(b, c)); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\242.java" deleted file mode 100644 index 3d27dcc..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\242.java" +++ /dev/null @@ -1,83 +0,0 @@ -package io.github.dunwu.algorithm.dp; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * 322. 零钱兑换 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 零钱兑换 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(3, s.coinChange(new int[] { 1, 2, 5 }, 11)); - Assertions.assertEquals(-1, s.coinChange(new int[] { 2 }, 3)); - Assertions.assertEquals(0, s.coinChange(new int[] { 1 }, 0)); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(3, s2.coinChange(new int[] { 1, 2, 5 }, 11)); - Assertions.assertEquals(-1, s2.coinChange(new int[] { 2 }, 3)); - Assertions.assertEquals(0, s2.coinChange(new int[] { 1 }, 0)); - } - - static class Solution { - - public int coinChange(int[] coins, int amount) { - int[] memo = new int[amount + 1]; - // 备忘录初始化为一个不会被取到的特殊值,代表还未被计算 - Arrays.fill(memo, -1); - return dp(coins, memo, amount); - } - - public int dp(int[] coins, int[] memo, int amount) { - if (amount == 0) return 0; - if (amount < 0) return -1; - // 查备忘录,防止重复计算 - if (memo[amount] != -1) { - return memo[amount]; - } - - int res = Integer.MAX_VALUE; - for (int coin : coins) { - // 计算子问题的结果 - int subProblem = dp(coins, memo, amount - coin); - // 子问题无解则跳过 - if (subProblem == -1) continue; - // 在子问题中选择最优解,然后加一 - res = Math.min(res, subProblem + 1); - } - // 把计算结果存入备忘录 - memo[amount] = (res == Integer.MAX_VALUE) ? -1 : res; - return memo[amount]; - } - - } - - static class Solution2 { - - public int coinChange(int[] coins, int amount) { - return dp(coins, amount); - } - - public int dp(int[] coins, int amount) { - if (amount <= 0) return amount; - int[] dp = new int[amount + 1]; - Arrays.fill(dp, amount + 1); - - dp[0] = 0; - for (int i = 0; i < dp.length; i++) { - for (int coin : coins) { - if (i - coin < 0) { continue; } - dp[i] = Math.min(dp[i], dp[i - coin] + 1); - } - } - return (dp[amount] == amount + 1) ? -1 : dp[amount]; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/DoublyLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/DoublyLinkedList.java similarity index 99% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/DoublyLinkedList.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/DoublyLinkedList.java index a5e05f8..fda6b80 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/DoublyLinkedList.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/DoublyLinkedList.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist; import lombok.Getter; import lombok.Setter; diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/LRUBaseLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/LRUBaseLinkedList.java similarity index 98% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/LRUBaseLinkedList.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/LRUBaseLinkedList.java index 126fe30..b64ac35 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/LRUBaseLinkedList.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/LRUBaseLinkedList.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist; import java.util.Scanner; diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/LRUBasedArray.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/LRUBasedArray.java similarity index 98% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/LRUBasedArray.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/LRUBasedArray.java index e7aa484..255489a 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/LRUBasedArray.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/LRUBasedArray.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist; import java.util.HashMap; import java.util.Map; diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/ListNode.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/ListNode.java new file mode 100644 index 0000000..f8868a7 --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/ListNode.java @@ -0,0 +1,114 @@ +package io.github.dunwu.algorithm.linkedlist; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public final class ListNode { + + public int val; + public ListNode next; + + public ListNode(int val) { this.val = val; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ListNode)) return false; + ListNode listNode = (ListNode) o; + return val == listNode.val && + Objects.equals(next, listNode.next); + } + + @Override + public int hashCode() { + return Objects.hash(val, next); + } + + public List toList() { + return ListNode.toList(this); + } + + public static ListNode createLinkedList(int[] arr) { + if (arr == null || arr.length == 0) { + return null; + } + ListNode head = new ListNode(arr[0]); + ListNode cur = head; + for (int i = 1; i < arr.length; i++) { + cur.next = new ListNode(arr[i]); + cur = cur.next; + } + return head; + } + + public static void addLast() { + + } + + public static ListNode buildList(int... list) { + ListNode head = new ListNode(-1); + ListNode node = head; + for (int val : list) { + node.next = new ListNode(val); + node = node.next; + } + return head.next; + } + + public static ListNode buildCycleList(int cyclePoint, int[] list) { + ListNode head = new ListNode(-1); + ListNode node = head; + ListNode cycleBeginNode = null; + for (int val : list) { + ListNode item = new ListNode(val); + if (cyclePoint == 0 && cycleBeginNode == null) { + cycleBeginNode = item; + } else { + cyclePoint--; + } + node.next = item; + node = node.next; + } + if (cycleBeginNode != null) { + node.next = cycleBeginNode; + } + return head.next; + } + + public static List toList(ListNode listNode) { + List list = new ArrayList<>(); + while (listNode != null) { + list.add(listNode.val); + listNode = listNode.next; + } + return list; + } + + public static void buildMetPot(ListNode listA, ListNode listB, int skipA, int skipB) { + ListNode pA = listA; + for (int i = 0; i < skipA; i++) { + pA = pA.next; + } + ListNode pB = listB; + for (int i = 0; i < skipB - 1; i++) { + pB = pB.next; + } + pB.next = pA; + } + + public static void main(String[] args) { + int[] arr = { 1, 2, 3, 4, 5 }; + ListNode head = createLinkedList(arr); + ListNode p = head; + while (p.next != null) { + p = p.next; + } + p.next = new ListNode(6); + while (head != null) { + System.out.println(head.val); + head = head.next; + } + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/MyLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/MyLinkedList.java similarity index 99% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/MyLinkedList.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/MyLinkedList.java index 6601d2e..694b2d4 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/MyLinkedList.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/MyLinkedList.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist; import java.util.NoSuchElementException; diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/SinglyLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/SinglyLinkedList.java similarity index 99% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/SinglyLinkedList.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/SinglyLinkedList.java index e661110..e89238d 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/SinglyLinkedList.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/SinglyLinkedList.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist; import lombok.Getter; import lombok.Setter; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" similarity index 83% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" index 0792257..7c45670 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\233\236\346\226\207\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" @@ -1,11 +1,8 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist.palindrome; +import io.github.dunwu.algorithm.linkedlist.ListNode; import org.junit.jupiter.api.Assertions; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - /** * 234. 回文链表 * 面试题 02.06. 回文链表 @@ -16,10 +13,10 @@ public class 回文链表 { public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 2, 2, 1); + ListNode head = ListNode.buildList(1, 2, 2, 1); Assertions.assertTrue(isPalindrome(head)); - head = ListUtil.buildList(1, 2); + head = ListNode.buildList(1, 2); Assertions.assertFalse(isPalindrome(head)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" new file mode 100644 index 0000000..2156a24 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" @@ -0,0 +1,62 @@ +package io.github.dunwu.algorithm.linkedlist.reverse; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 23. 合并 K 个升序链表 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class K个一组翻转链表 { + + public static void main(String[] args) { + Solution s = new Solution(); + ListNode output = s.reverseKGroup(ListNode.buildList(1, 2, 3, 4, 5), 2); + Assertions.assertEquals(ListNode.buildList(2, 1, 4, 3, 5), output); + ListNode output2 = s.reverseKGroup(ListNode.buildList(1, 2, 3, 4, 5), 3); + Assertions.assertEquals(ListNode.buildList(3, 2, 1, 4, 5), output2); + } + + static class Solution { + + public ListNode reverseKGroup(ListNode head, int k) { + if (head == null) return null; + // 区间 [a, b) 包含 k 个待反转元素 + ListNode a, b; + a = b = head; + for (int i = 0; i < k; i++) { + // 不足 k 个,不需要反转了 + if (b == null) return head; + b = b.next; + } + // 反转前 k 个元素 + ListNode newHead = reverseN(a, k); + // 此时 b 指向下一组待反转的头结点 + // 递归反转后续链表并连接起来 + a.next = reverseKGroup(b, k); + + return newHead; + } + + private ListNode reverseN(ListNode head, int len) { + if (head == null || head.next == null) { return head; } + ListNode pre = null, cur = head, next = cur.next; + while (len-- > 0) { + cur.next = pre; + pre = cur; + cur = next; + if (next != null) { + next = next.next; + } + } + // 此时的 cur 是第 n + 1 个节点,head 是反转后的尾结点 + head.next = cur; + // 此时的 pre 是反转后的头结点 + return pre; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\250.java" new file mode 100644 index 0000000..ac54c4c --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\250.java" @@ -0,0 +1,44 @@ +package io.github.dunwu.algorithm.linkedlist.reverse; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 206. 反转链表 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 反转链表 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + ListNode result = s.reverseList(ListNode.buildList(1, 2, 3, 4)); + Assertions.assertEquals(ListNode.buildList(4, 3, 2, 1), result); + + ListNode result2 = s.reverseList(ListNode.buildList(1, 2)); + Assertions.assertEquals(ListNode.buildList(2, 1), result2); + + ListNode result3 = s.reverseList(ListNode.buildList()); + Assertions.assertEquals(ListNode.buildList(), result3); + } + + static class Solution { + + public ListNode reverseList(ListNode head) { + if (head == null || head.next == null) { return head; } + ListNode pre = null, cur = head; + while (cur != null) { + ListNode next = cur.next; + cur.next = pre; + pre = cur; + cur = next; + } + return pre; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\2502.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\2502.java" new file mode 100644 index 0000000..286c941 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\2502.java" @@ -0,0 +1,60 @@ +package io.github.dunwu.algorithm.linkedlist.reverse; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 92. 反转链表 II + * + * @author Zhang Peng + * @date 2025-01-20 + */ +public class 反转链表2 { + + public static void main(String[] args) { + Solution s = new Solution(); + ListNode result = s.reverseBetween(ListNode.buildList(1, 2, 3, 4, 5), 2, 4); + Assertions.assertEquals(ListNode.buildList(1, 4, 3, 2, 5), result); + ListNode result2 = s.reverseBetween(ListNode.buildList(3, 5), 1, 2); + Assertions.assertEquals(ListNode.buildList(5, 3), result2); + } + + static class Solution { + + public ListNode reverseBetween(ListNode head, int left, int right) { + if (left == 1) { + return reverseN(head, right); + } + + // 找到第 left 个节点的前驱 + ListNode pre = head; + for (int i = 1; i < left - 1; i++) { + pre = pre.next; + } + + // 从第 left 个节点开始反转 + int len = right - left + 1; + pre.next = reverseN(pre.next, len); + return pre; + } + + private ListNode reverseN(ListNode head, int len) { + if (head == null || head.next == null) { return head; } + ListNode pre = null, cur = head, next = cur.next; + while (len-- > 0) { + cur.next = pre; + pre = cur; + cur = next; + if (next != null) { + next = next.next; + } + } + // 此时的 cur 是第 n + 1 个节点,head 是反转后的尾结点 + head.next = cur; + // 此时的 pre 是反转后的头结点 + return pre; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\344\270\244\346\225\260\347\233\270\345\212\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\344\270\244\346\225\260\347\233\270\345\212\240.java" new file mode 100644 index 0000000..69de0e0 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\344\270\244\346\225\260\347\233\270\345\212\240.java" @@ -0,0 +1,65 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 2. 两数相加 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 两数相加 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + ListNode output1 = s.addTwoNumbers(ListNode.buildList(2, 4, 3), ListNode.buildList(5, 6, 4)); + Assertions.assertEquals(ListNode.buildList(7, 0, 8), output1); + + ListNode output2 = s.addTwoNumbers(ListNode.buildList(0), ListNode.buildList(0)); + Assertions.assertEquals(ListNode.buildList(0), output2); + + ListNode output3 = s.addTwoNumbers(ListNode.buildList(9, 9, 9, 9, 9, 9, 9), ListNode.buildList(9, 9, 9, 9)); + Assertions.assertEquals(ListNode.buildList(8, 9, 9, 9, 0, 0, 0, 1), output3); + } + + static class Solution { + + public ListNode addTwoNumbers(ListNode l1, ListNode l2) { + // 在两条链表上的指针 + ListNode p1 = l1, p2 = l2; + // 虚拟头结点(构建新链表时的常用技巧) + ListNode dummy = new ListNode(-1); + // 指针 p 负责构建新链表 + ListNode p = dummy; + // 记录进位 + int carry = 0; + // 开始执行加法,两条链表走完且没有进位时才能结束循环 + while (p1 != null || p2 != null || carry > 0) { + + int val = 0; + if (p1 != null) { + val += p1.val; + p1 = p1.next; + } + if (p2 != null) { + val += p2.val; + p2 = p2.next; + } + if (carry > 0) { + val += carry; + } + + carry = val / 10; + val = val % 10; + p.next = new ListNode(val); + p = p.next; + } + return dummy.next; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\344\270\244\346\225\260\347\233\270\345\212\2402.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\344\270\244\346\225\260\347\233\270\345\212\2402.java" new file mode 100644 index 0000000..445b9d7 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\344\270\244\346\225\260\347\233\270\345\212\2402.java" @@ -0,0 +1,79 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 445. 两数相加 II + * + * @author Zhang Peng + * @date 2025-01-21 + */ +public class 两数相加2 { + + public static void main(String[] args) { + Solution s = new Solution(); + ListNode result = s.addTwoNumbers(ListNode.buildList(7, 2, 4, 3), ListNode.buildList(5, 6, 4)); + Assertions.assertEquals(ListNode.buildList(7, 8, 0, 7), result); + ListNode result2 = s.addTwoNumbers(ListNode.buildList(2, 4, 3), ListNode.buildList(5, 6, 4)); + Assertions.assertEquals(ListNode.buildList(8, 0, 7), result2); + ListNode result3 = s.addTwoNumbers(ListNode.buildList(0), ListNode.buildList(0)); + Assertions.assertEquals(ListNode.buildList(0), result3); + } + + public static class Solution { + + public ListNode addTwoNumbers(ListNode l1, ListNode l2) { + ListNode r1 = reverse(l1); + ListNode r2 = reverse(l2); + ListNode res = doAddTwoNumbers(r1, r2); + return reverse(res); + } + + public ListNode reverse(ListNode head) { + ListNode pre = null, cur = head; + while (cur != null) { + ListNode next = cur.next; + cur.next = pre; + pre = cur; + cur = next; + } + return pre; + } + + public ListNode doAddTwoNumbers(ListNode l1, ListNode l2) { + // 在两条链表上的指针 + ListNode p1 = l1, p2 = l2; + // 虚拟头结点(构建新链表时的常用技巧) + ListNode dummy = new ListNode(-1); + // 指针 p 负责构建新链表 + ListNode p = dummy; + // 记录进位 + int carry = 0; + // 开始执行加法,两条链表走完且没有进位时才能结束循环 + while (p1 != null || p2 != null || carry > 0) { + + int val = 0; + if (p1 != null) { + val += p1.val; + p1 = p1.next; + } + if (p2 != null) { + val += p2.val; + p2 = p2.next; + } + if (carry > 0) { + val += carry; + } + + carry = val / 10; + val = val % 10; + p.next = new ListNode(val); + p = p.next; + } + return dummy.next; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\206\351\232\224\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\206\351\232\224\351\223\276\350\241\250.java" new file mode 100644 index 0000000..2ab09c3 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\206\351\232\224\351\223\276\350\241\250.java" @@ -0,0 +1,101 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 86. 分隔链表 + * + * @author Zhang Peng + * @since 2020-07-06 + */ +public class 分隔链表 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + Assertions.assertEquals(ListNode.buildList(1, 2, 2, 4, 3, 5), + s.partition(ListNode.buildList(1, 4, 3, 2, 5, 2), 3)); + Assertions.assertEquals(ListNode.buildList(1, 2), s.partition(ListNode.buildList(2, 1), 2)); + Assertions.assertEquals(ListNode.buildList(1, 2, 3), s.partition(ListNode.buildList(3, 1, 2), 3)); + Assertions.assertEquals(ListNode.buildList(1, 0, 4, 3, 5, 2), + s.partition(ListNode.buildList(1, 4, 3, 0, 5, 2), 2)); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals(ListNode.buildList(1, 2, 2, 4, 3, 5), + s2.partition(ListNode.buildList(1, 4, 3, 2, 5, 2), 3)); + Assertions.assertEquals(ListNode.buildList(1, 2), s2.partition(ListNode.buildList(2, 1), 2)); + Assertions.assertEquals(ListNode.buildList(1, 2, 3), s2.partition(ListNode.buildList(3, 1, 2), 3)); + Assertions.assertEquals(ListNode.buildList(1, 0, 4, 3, 5, 2), + s2.partition(ListNode.buildList(1, 4, 3, 0, 5, 2), 2)); + } + + static class Solution { + + public ListNode partition(ListNode head, int x) { + + if (head == null) { return null; } + + ListNode dummy = new ListNode(-1); + dummy.next = head; + + // 找到大于等于 x 的节点的前一个节点 + ListNode l = dummy, r = dummy.next; + while (r != null) { + + while (l.next != null && l.next.val < x) { + l = l.next; + } + if (l.next == null) { + break; + } + + r = l.next; + while (r.next != null && r.next.val >= x) { + r = r.next; + } + if (r.next == null) { + break; + } + + // 替换节点 + ListNode tmp = r.next; + r.next = tmp.next; + tmp.next = l.next; + l.next = tmp; + + l = l.next; + r = r.next; + } + + return dummy.next; + } + + } + + static class Solution2 { + + public ListNode partition(ListNode head, int x) { + ListNode dummy1 = new ListNode(-1); + ListNode dummy2 = new ListNode(-1); + + ListNode d1 = dummy1, d2 = dummy2, p = head; + while (p != null) { + if (p.val < x) { + d1.next = p; + d1 = d1.next; + } else { + d2.next = p; + d2 = d2.next; + } + p = p.next; + } + d2.next = null; + d1.next = dummy2.next; + return dummy1.next; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" similarity index 71% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" index adeaab3..aaf561d 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" @@ -1,5 +1,6 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist.two_pointer; +import io.github.dunwu.algorithm.linkedlist.ListNode; import org.junit.jupiter.api.Assertions; import java.util.List; @@ -13,17 +14,17 @@ public class 删除排序链表中的重复元素 { public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 1, 2); - System.out.println(ListUtil.toList(head)); + ListNode head = ListNode.buildList(1, 1, 2); + System.out.println(ListNode.toList(head)); ListNode result = deleteDuplicates(head); - List list = ListUtil.toList(result); + List list = ListNode.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 1, 2 }, list.toArray(new Integer[0])); - ListNode head2 = ListUtil.buildList(1, 1, 2, 3, 3); - System.out.println(ListUtil.toList(head2)); + ListNode head2 = ListNode.buildList(1, 1, 2, 3, 3); + System.out.println(ListNode.toList(head2)); ListNode result2 = deleteDuplicates(head2); - List list2 = ListUtil.toList(result2); + List list2 = ListNode.toList(result2); System.out.println(list2); Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, list2.toArray(new Integer[0])); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\2402.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\2402.java" new file mode 100644 index 0000000..94cc3af --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\2402.java" @@ -0,0 +1,62 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 82. 删除排序链表中的重复元素 II + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 删除排序链表中的重复元素2 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + ListNode input = ListNode.buildList(1, 2, 3, 3, 4, 4, 5); + Assertions.assertEquals(ListNode.buildList(1, 2, 5), s.deleteDuplicates(input)); + + ListNode input2 = ListNode.buildList(1, 1, 1, 2, 3); + Assertions.assertEquals(ListNode.buildList(2, 3), s.deleteDuplicates(input2)); + + ListNode input3 = ListNode.buildList(1, 2, 2); + Assertions.assertEquals(ListNode.buildList(1), s.deleteDuplicates(input3)); + } + + public static class Solution { + + public ListNode deleteDuplicates(ListNode head) { + // 将原链表分解为两条链表 + // 一条链表存放不重复的节点,另一条链表存放重复的节点 + // 运用虚拟头结点技巧,题目说了 node.val <= 100,所以用 101 作为虚拟头结点 + ListNode dummyUniq = new ListNode(101); + ListNode dummyDup = new ListNode(101); + + ListNode pUniq = dummyUniq, pDup = dummyDup; + ListNode p = head; + + while (p != null) { + if ((p.next != null && p.val == p.next.val) || p.val == pDup.val) { + // 发现重复节点,接到重复链表后面 + pDup.next = p; + pDup = pDup.next; + } else { + // 不是重复节点,接到不重复链表后面 + pUniq.next = p; + pUniq = pUniq.next; + } + + p = p.next; + // 将原链表和新链表断开 + pUniq.next = null; + pDup.next = null; + } + + return dummyUniq.next; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" new file mode 100644 index 0000000..d3e6e42 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" @@ -0,0 +1,59 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 19. 删除链表的倒数第 N 个结点 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 删除链表的倒数第N个结点 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + ListNode input1 = ListNode.buildList(1, 2, 3, 4, 5); + ListNode output1 = s.removeNthFromEnd(input1, 2); + Assertions.assertEquals(ListNode.buildList(1, 2, 3, 5), output1); + + ListNode input2 = ListNode.buildList(1); + ListNode output2 = s.removeNthFromEnd(input2, 1); + Assertions.assertEquals(ListNode.buildList(), output2); + + ListNode input3 = ListNode.buildList(1, 2); + ListNode output3 = s.removeNthFromEnd(input3, 1); + Assertions.assertEquals(ListNode.buildList(1), output3); + } + + static class Solution { + + public ListNode removeNthFromEnd(ListNode head, int n) { + ListNode dummy = new ListNode(-1); + dummy.next = head; + ListNode node = findFromEnd(dummy, n + 1); + node.next = node.next.next; + return dummy.next; + } + + public ListNode findFromEnd(ListNode head, int k) { + ListNode p1 = head; + // p1 先走 k 步 + for (int i = 0; i < k; i++) { + p1 = p1.next; + } + ListNode p2 = head; + // p1 和 p2 同时走 n - k 步 + while (p1 != null) { + p2 = p2.next; + p1 = p1.next; + } + // p2 现在指向第 n - k + 1 个节点,即倒数第 k 个节点 + return p2; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" new file mode 100644 index 0000000..419f5e2 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" @@ -0,0 +1,67 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 23. 合并 K 个升序链表 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 合并K个升序链表 { + + public static void main(String[] args) { + + Solution s = new Solution(); + ListNode head1 = ListNode.buildList(1, 4, 5); + ListNode head2 = ListNode.buildList(1, 3, 4); + ListNode head3 = ListNode.buildList(2, 6); + ListNode result = s.mergeKLists(new ListNode[] { head1, head2, head3 }); + Assertions.assertEquals(ListNode.buildList(1, 1, 2, 3, 4, 4, 5, 6), result); + + ListNode[] array2 = new ListNode[] {}; + ListNode result2 = s.mergeKLists(array2); + Assertions.assertEquals(ListNode.buildList(), result2); + } + + static class Solution { + + public ListNode mergeKLists(ListNode[] lists) { + if (lists == null || lists.length == 0) return null; + ListNode l1 = lists[0]; + for (int i = 1; i < lists.length; i++) { + ListNode l2 = lists[i]; + l1 = mergeTwoLists(l1, l2); + } + return l1; + } + + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + // 虚拟头结点 + ListNode dummy = new ListNode(-1), p = dummy; + ListNode p1 = l1, p2 = l2; + + while (p1 != null && p2 != null) { + // 比较 p1 和 p2 两个指针 + // 将值较小的的节点接到 p 指针 + if (p1.val > p2.val) { + p.next = p2; + p2 = p2.next; + } else { + p.next = p1; + p1 = p1.next; + } + // p 指针不断前进 + p = p.next; + } + + if (p1 != null) { p.next = p1; } + if (p2 != null) { p.next = p2; } + + return dummy.next; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" new file mode 100644 index 0000000..8da3bd1 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" @@ -0,0 +1,51 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 21. 合并两个有序链表 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 合并两个有序链表 { + + public static void main(String[] args) { + Solution s = new Solution(); + ListNode h1 = ListNode.buildList(1, 2, 4); + ListNode h2 = ListNode.buildList(1, 3, 4); + ListNode result = s.mergeTwoLists(h1, h2); + Assertions.assertEquals(ListNode.buildList(1, 1, 2, 3, 4, 4), result); + } + + static class Solution { + + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + // 虚拟头结点 + ListNode dummy = new ListNode(-1), p = dummy; + ListNode p1 = l1, p2 = l2; + + while (p1 != null && p2 != null) { + // 比较 p1 和 p2 两个指针 + // 将值较小的的节点接到 p 指针 + if (p1.val > p2.val) { + p.next = p2; + p2 = p2.next; + } else { + p.next = p1; + p1 = p1.next; + } + // p 指针不断前进 + p = p.next; + } + + if (p1 != null) { p.next = p1; } + if (p2 != null) { p.next = p2; } + + return dummy.next; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\216\257\345\275\242\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\216\257\345\275\242\351\223\276\350\241\250.java" new file mode 100644 index 0000000..f73021e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\216\257\345\275\242\351\223\276\350\241\250.java" @@ -0,0 +1,50 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 141. 环形链表 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 环形链表 { + + public static void main(String[] args) { + + Solution s = new Solution(); + ListNode head = ListNode.buildList(3, 2, 0, -4); + Assertions.assertFalse(s.hasCycle(head)); + + ListNode head2 = ListNode.buildCycleList(1, new int[] { 3, 2, 0, -4 }); + Assertions.assertTrue(s.hasCycle(head2)); + + ListNode head3 = ListNode.buildCycleList(0, new int[] { 1, 2 }); + Assertions.assertTrue(s.hasCycle(head3)); + + ListNode head4 = ListNode.buildCycleList(1, new int[] { 1 }); + Assertions.assertFalse(s.hasCycle(head4)); + } + + static class Solution { + + public boolean hasCycle(ListNode head) { + // 快慢指针初始化指向 head + ListNode slow = head, fast = head; + // 快指针走到末尾时停止 + while (fast != null && fast.next != null) { + // 慢指针走一步,快指针走两步 + slow = slow.next; + fast = fast.next.next; + // 快慢指针相遇,说明含有环 + if (slow == fast) { + return true; + } + } + return false; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\216\257\345\275\242\351\223\276\350\241\2502.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\216\257\345\275\242\351\223\276\350\241\2502.java" new file mode 100644 index 0000000..1c6abd9 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\216\257\345\275\242\351\223\276\350\241\2502.java" @@ -0,0 +1,60 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 142. 环形链表 II + * + * @author Zhang Peng + * @since 2020-07-08 + */ +public class 环形链表2 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + ListNode input = ListNode.buildList(3, 2, 0, -4); + Assertions.assertNull(s.detectCycle(input)); + + ListNode input2 = ListNode.buildList(1); + Assertions.assertNull(s.detectCycle(input2)); + + ListNode input3 = ListNode.buildCycleList(1, new int[] { 3, 2, 0, -4 }); + Assertions.assertEquals(2, s.detectCycle(input3).val); + + ListNode input4 = ListNode.buildCycleList(0, new int[] { 1, 2 }); + Assertions.assertEquals(1, s.detectCycle(input4).val); + } + + static class Solution { + + public ListNode detectCycle(ListNode head) { + ListNode fast, slow; + fast = slow = head; + while (fast != null && fast.next != null) { + fast = fast.next.next; + slow = slow.next; + if (fast == slow) break; + } + + // fast 遇到空指针说明没有环 + if (fast == null || fast.next == null) { + return null; + } + + // 重新指向头结点 + slow = head; + + // 快慢指针同步前进,相交点就是环起点 + while (slow != fast) { + fast = fast.next; + slow = slow.next; + } + return slow; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\233\270\344\272\244\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\233\270\344\272\244\351\223\276\350\241\250.java" new file mode 100644 index 0000000..e222dfe --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\233\270\344\272\244\351\223\276\350\241\250.java" @@ -0,0 +1,60 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 相交链表 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 相交链表 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + ListNode listA = ListNode.buildList(4, 1, 8, 4, 5); + ListNode listB = ListNode.buildList(5, 6, 1, 8, 4, 5); + ListNode.buildMetPot(listA, listB, 2, 3); + ListNode result = s.getIntersectionNode(listA, listB); + Assertions.assertEquals(8, result.val); + + ListNode listA2 = ListNode.buildList(1, 9, 1, 2, 4); + ListNode listB2 = ListNode.buildList(3, 2, 4); + ListNode.buildMetPot(listA2, listB2, 3, 1); + ListNode result2 = s.getIntersectionNode(listA2, listB2); + Assertions.assertEquals(2, result2.val); + + ListNode listA3 = ListNode.buildList(2, 6, 4); + ListNode listB3 = ListNode.buildList(1, 5); + ListNode result3 = s.getIntersectionNode(listA3, listB3); + Assertions.assertNull(result3); + } + + static class Solution { + + public ListNode getIntersectionNode(ListNode headA, ListNode headB) { + // pA 指向 A 链表头结点,pB 指向 B 链表头结点 + ListNode pA = headA, pB = headB; + while (pA != pB) { + // pA 走一步,如果走到 A 链表末尾,转到 B 链表 + if (pA == null) { + pA = headB; + } else { + pA = pA.next; + } + // pB 走一步,如果走到 B 链表末尾,转到 A 链表 + if (pB == null) { + pB = headA; + } else { + pB = pB.next; + } + } + return pA; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" new file mode 100644 index 0000000..808ba2b --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" @@ -0,0 +1,37 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 面试题 02. 返回倒数第 k 个节点 + * LCR 140. 训练计划 II + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 返回倒数第k个节点 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(4, s.kthToLast(ListNode.buildList(1, 2, 3, 4, 5), 2)); + Assertions.assertEquals(1, s.kthToLast(ListNode.buildList(1), 1)); + } + + static class Solution { + + public int kthToLast(ListNode head, int k) { + ListNode slow = head, fast = head; + for (int i = 0; i < k && fast != null; i++) { + fast = fast.next; + } + while (fast != null) { + fast = fast.next; + slow = slow.next; + } + return slow == null ? -1 : slow.val; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" new file mode 100644 index 0000000..f93a67c --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" @@ -0,0 +1,35 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 876. 链表的中间结点 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 链表的中间结点 { + + public static void main(String[] args) { + Solution s = new Solution(); + ListNode input = ListNode.buildList(1, 2, 3, 4, 5); + Assertions.assertEquals(ListNode.buildList(3, 4, 5), s.middleNode(input)); + ListNode input2 = ListNode.buildList(1, 2, 3, 4, 5, 6); + Assertions.assertEquals(ListNode.buildList(4, 5, 6), s.middleNode(input2)); + } + + static class Solution { + + public ListNode middleNode(ListNode head) { + ListNode slow = head, fast = head; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + } + return slow; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" similarity index 85% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" index 4348aad..33c195f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist; import org.junit.jupiter.api.Assertions; @@ -9,23 +9,23 @@ public class 二进制链表转整数 { public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 0, 1); - System.out.println(ListUtil.toList(head)); + ListNode head = ListNode.buildList(1, 0, 1); + System.out.println(ListNode.toList(head)); int result = getDecimalValue(head); Assertions.assertEquals(5, result); head = new ListNode(0); - System.out.println(ListUtil.toList(head)); + System.out.println(ListNode.toList(head)); result = getDecimalValue(head); Assertions.assertEquals(0, result); head = new ListNode(1); - System.out.println(ListUtil.toList(head)); + System.out.println(ListNode.toList(head)); result = getDecimalValue(head); Assertions.assertEquals(1, result); - head = ListUtil.buildList(1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0); - System.out.println(ListUtil.toList(head)); + head = ListNode.buildList(1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0); + System.out.println(ListNode.toList(head)); result = getDecimalValue(head); Assertions.assertEquals(18880, result); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" similarity index 82% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" index d4a69af..69e3aae 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist; import org.junit.jupiter.api.Assertions; @@ -15,24 +15,24 @@ public class 从未排序的链表中移除重复元素 { public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 2, 3, 2); - System.out.println(ListUtil.toList(head)); + ListNode head = ListNode.buildList(1, 2, 3, 2); + System.out.println(ListNode.toList(head)); ListNode result = deleteDuplicates2(head); - List list = ListUtil.toList(result); + List list = ListNode.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 1, 3 }, list.toArray(new Integer[0])); - ListNode head2 = ListUtil.buildList(2, 1, 1, 2); - System.out.println(ListUtil.toList(head2)); + ListNode head2 = ListNode.buildList(2, 1, 1, 2); + System.out.println(ListNode.toList(head2)); ListNode result2 = deleteDuplicates2(head2); - List list2 = ListUtil.toList(result2); + List list2 = ListNode.toList(result2); System.out.println(list2); Assertions.assertArrayEquals(new Integer[] {}, list2.toArray(new Integer[0])); - ListNode head3 = ListUtil.buildList(3, 2, 2, 1, 3, 2, 4); - System.out.println(ListUtil.toList(head3)); + ListNode head3 = ListNode.buildList(3, 2, 2, 1, 3, 2, 4); + System.out.println(ListNode.toList(head3)); ListNode result3 = deleteDuplicates2(head3); - List list3 = ListUtil.toList(result3); + List list3 = ListNode.toList(result3); System.out.println(list3); Assertions.assertArrayEquals(new Integer[] { 1, 4 }, list3.toArray(new Integer[0])); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" similarity index 98% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" index 3719b6c..d09a8ee 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist; import java.util.ArrayList; import java.util.List; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" similarity index 98% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" index 02ede0a..8658232 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist; /** * @author Zhang Peng diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\245\207\345\201\266\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\245\207\345\201\266\351\223\276\350\241\250.java" similarity index 78% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\245\207\345\201\266\351\223\276\350\241\250.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\245\207\345\201\266\351\223\276\350\241\250.java" index 3ab1ae7..a3ce6b0 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\245\207\345\201\266\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\245\207\345\201\266\351\223\276\350\241\250.java" @@ -1,6 +1,5 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist; -import java.util.Arrays; import java.util.List; /** @@ -10,8 +9,8 @@ public class 奇偶链表 { public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 2, 3, 4, 5); - List list = ListUtil.toList(oddEvenList(head)); + ListNode head = ListNode.buildList(1, 2, 3, 4, 5); + List list = ListNode.toList(oddEvenList(head)); System.out.println(list); // Assertions.assertFalse(); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\346\216\222\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\346\216\222\345\272\217\351\223\276\350\241\250.java" similarity index 88% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\346\216\222\345\272\217\351\223\276\350\241\250.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\346\216\222\345\272\217\351\223\276\350\241\250.java" index fa65a28..197c377 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\346\216\222\345\272\217\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\346\216\222\345\272\217\351\223\276\350\241\250.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist; import org.junit.jupiter.api.Assertions; @@ -12,17 +12,17 @@ public class 排序链表 { public static void main(String[] args) { - ListNode head = ListUtil.buildList(4, 2, 1, 3); - System.out.println(ListUtil.toList(head)); + ListNode head = ListNode.buildList(4, 2, 1, 3); + System.out.println(ListNode.toList(head)); ListNode result = sortList(head); - List list = ListUtil.toList(result); + List list = ListNode.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 1, 2, 3, 4 }, list.toArray(new Integer[0])); - head = ListUtil.buildList(-1, 5, 3, 4, 0); - System.out.println(ListUtil.toList(head)); + head = ListNode.buildList(-1, 5, 3, 4, 0); + System.out.println(ListNode.toList(head)); result = sortList(head); - list = ListUtil.toList(result); + list = ListNode.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { -1, 0, 3, 4, 5 }, list.toArray(new Integer[0])); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" similarity index 90% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" index cd353d7..502bdb1 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist; import org.junit.jupiter.api.Assertions; @@ -11,9 +11,9 @@ public class 移除重复节点 { public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 2, 3, 3, 2, 1); + ListNode head = ListNode.buildList(1, 2, 3, 3, 2, 1); ListNode listNode = removeDuplicateNodes(head); - List result = ListUtil.getValues(listNode); + List result = ListNode.toList(listNode); System.out.println(result); Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, result.toArray()); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" similarity index 77% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" index deccb7f..4612cdc 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist; import org.junit.jupiter.api.Assertions; @@ -12,31 +12,31 @@ public class 移除链表元素 { public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 2); - System.out.println(ListUtil.toList(head)); + ListNode head = ListNode.buildList(1, 2); + System.out.println(ListNode.toList(head)); ListNode result = removeElementByValue(head, 1); - List list = ListUtil.toList(result); + List list = ListNode.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 2 }, list.toArray(new Integer[0])); head = new ListNode(1); - System.out.println(ListUtil.toList(head)); + System.out.println(ListNode.toList(head)); result = removeElementByValue(head, 1); - list = ListUtil.toList(result); + list = ListNode.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] {}, list.toArray(new Integer[0])); - head = ListUtil.buildList(1, 1); - System.out.println(ListUtil.toList(head)); + head = ListNode.buildList(1, 1); + System.out.println(ListNode.toList(head)); result = removeElementByValue(head, 1); - list = ListUtil.toList(result); + list = ListNode.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] {}, list.toArray(new Integer[0])); - head = ListUtil.buildList(1, 2, 6, 3, 4, 5, 6); - System.out.println(ListUtil.toList(head)); + head = ListNode.buildList(1, 2, 6, 3, 4, 5, 6); + System.out.println(ListNode.toList(head)); result = removeElementByValue(head, 6); - list = ListUtil.toList(result); + list = ListNode.toList(result); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 1, 2, 3, 4, 5 }, list.toArray(new Integer[0])); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\256\276\350\256\241\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\350\256\276\350\256\241\351\223\276\350\241\250.java" similarity index 98% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\256\276\350\256\241\351\223\276\350\241\250.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\350\256\276\350\256\241\351\223\276\350\241\250.java" index 11e02a1..fd01e53 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\256\276\350\256\241\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\350\256\276\350\256\241\351\223\276\350\241\250.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.list; +package io.github.dunwu.algorithm.linkedlist; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" deleted file mode 100644 index 671bbc2..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" +++ /dev/null @@ -1,127 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -import java.util.List; -import java.util.PriorityQueue; - -/** - * 23. 合并 K 个升序链表 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class K个一组翻转链表 { - - public static void main(String[] args) { - - ListNode result1 = reverseKGroup(ListUtil.buildList(1, 2, 3, 4, 5), 2); - List list = ListUtil.toList(result1); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 2, 1, 4, 3, 5 }, list.toArray(new Integer[0])); - - ListNode result2 = reverseKGroup(ListUtil.buildList(1, 2, 3, 4, 5), 3); - List list2 = ListUtil.toList(result2); - System.out.println(list2); - Assertions.assertArrayEquals(new Integer[] { 3, 2, 1, 4, 5 }, list2.toArray(new Integer[0])); - } - - public static ListNode reverseKGroup(ListNode head, int k) { - if (head == null) return null; - ListNode left = head, right = head; - for (int i = 0; i < k; i++) { - if (right == null) { - return head; - } - right = right.next; - } - - ListNode newHead = reverseN(left, k); - left.next = reverseKGroup(right, k); - return newHead; - } - - public static ListNode reverseN(ListNode head, int n) { - if (head == null || head.next == null) { - return head; - } - ListNode prev = null, curr = head, next = head.next; - while (n > 0) { - curr.next = prev; - prev = curr; - curr = next; - if (next != null) { - next = next.next; - } - n--; - } - // 此时的 cur 是第 n + 1 个节点,head 是反转后的尾结点 - head.next = curr; - // 此时的 pre 是反转后的头结点 - return prev; - } - - public static ListNode reverseKGroup2(ListNode head, int k) { - if (head == null || head.next == null) { - return head; - } - //定义一个假的节点。 - ListNode dummy = new ListNode(0); - //假节点的next指向head。 - // dummy->1->2->3->4->5 - dummy.next = head; - //初始化pre和end都指向dummy。pre指每次要翻转的链表的头结点的上一个节点。end指每次要翻转的链表的尾节点 - ListNode pre = dummy; - ListNode end = dummy; - - while (end.next != null) { - //循环k次,找到需要翻转的链表的结尾,这里每次循环要判断end是否等于空,因为如果为空,end.next会报空指针异常。 - //dummy->1->2->3->4->5 若k为2,循环2次,end指向2 - for (int i = 0; i < k && end != null; i++) { - end = end.next; - } - //如果end==null,即需要翻转的链表的节点数小于k,不执行翻转。 - if (end == null) { - break; - } - //先记录下end.next,方便后面链接链表 - ListNode next = end.next; - //然后断开链表 - end.next = null; - //记录下要翻转链表的头节点 - ListNode start = pre.next; - //翻转链表,pre.next指向翻转后的链表。1->2 变成2->1。 dummy->2->1 - pre.next = reverse(start); - //翻转后头节点变到最后。通过.next把断开的链表重新链接。 - start.next = next; - //将pre换成下次要翻转的链表的头结点的上一个节点。即start - pre = start; - //翻转结束,将end置为下次要翻转的链表的头结点的上一个节点。即start - end = start; - } - return dummy.next; - } - - //链表翻转 - // 例子: head: 1->2->3->4 - public static ListNode reverse(ListNode head) { - //单链表为空或只有一个节点,直接返回原单链表 - if (head == null || head.next == null) { - return head; - } - //前一个节点指针 - ListNode preNode = null; - //当前节点指针 - ListNode curNode = head; - //下一个节点指针 - ListNode nextNode = null; - while (curNode != null) { - nextNode = curNode.next;//nextNode 指向下一个节点,保存当前节点后面的链表。 - curNode.next = preNode;//将当前节点next域指向前一个节点 null<-1<-2<-3<-4 - preNode = curNode;//preNode 指针向后移动。preNode指向当前节点。 - curNode = nextNode;//curNode指针向后移动。下一个节点变成当前节点 - } - return preNode; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListNode.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListNode.java deleted file mode 100644 index 86ef30e..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListNode.java +++ /dev/null @@ -1,57 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import java.util.Objects; - -public final class ListNode { - - public int val; - public ListNode next; - - ListNode(int val) { this.val = val; } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ListNode)) return false; - ListNode listNode = (ListNode) o; - return val == listNode.val && - Objects.equals(next, listNode.next); - } - - @Override - public int hashCode() { - return Objects.hash(val, next); - } - - public static ListNode createLinkedList(int[] arr) { - if (arr == null || arr.length == 0) { - return null; - } - ListNode head = new ListNode(arr[0]); - ListNode cur = head; - for (int i = 1; i < arr.length; i++) { - cur.next = new ListNode(arr[i]); - cur = cur.next; - } - return head; - } - - public static void addLast() { - - } - - public static void main(String[] args) { - int[] arr = { 1, 2, 3, 4, 5 }; - ListNode head = createLinkedList(arr); - ListNode p = head; - while (p.next != null) { - p = p.next; - } - p.next = new ListNode(6); - while (head != null) { - System.out.println(head.val); - head = head.next; - } - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListUtil.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListUtil.java deleted file mode 100644 index 6176f9f..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListUtil.java +++ /dev/null @@ -1,63 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Zhang Peng - * @since 2020-06-09 - */ -public class ListUtil { - - private ListUtil() { } - - public static ListNode buildList(int... list) { - ListNode head = new ListNode(-1); - ListNode node = head; - for (int val : list) { - node.next = new ListNode(val); - node = node.next; - } - return head.next; - } - - public static List toList(ListNode result) { - List list = new ArrayList<>(); - while (result != null) { - list.add(result.val); - result = result.next; - } - return list; - } - - public static List getValues(ListNode listNode) { - List list = new ArrayList<>(); - ListNode item = listNode; - while (item != null) { - list.add(item.val); - item = item.next; - } - return list; - } - - public static ListNode buildCycleList(int pos, int[] list) { - ListNode head = new ListNode(-1); - ListNode node = head; - ListNode cycleBeginNode = null; - for (int val : list) { - ListNode item = new ListNode(val); - if (pos == 0 && cycleBeginNode == null) { - cycleBeginNode = item; - } else { - pos--; - } - node.next = item; - node = node.next; - } - if (cycleBeginNode != null) { - node.next = cycleBeginNode; - } - return head.next; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240.java" deleted file mode 100644 index 20588d3..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240.java" +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -import java.util.List; - -/** - * 2. 两数相加 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 两数相加 { - - public static void main(String[] args) { - ListNode result = addTwoNumbers(ListUtil.buildList(2, 4, 3), ListUtil.buildList(5, 6, 4)); - List list = ListUtil.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 7, 0, 8 }, list.toArray()); - - ListNode result2 = addTwoNumbers(ListUtil.buildList(0), ListUtil.buildList(0)); - List list2 = ListUtil.toList(result2); - System.out.println(list2); - Assertions.assertArrayEquals(new Integer[] { 0 }, list2.toArray()); - - ListNode result3 = addTwoNumbers(ListUtil.buildList(9, 9, 9, 9, 9, 9, 9), ListUtil.buildList(9, 9, 9, 9)); - List list3 = ListUtil.toList(result3); - System.out.println(list3); - Assertions.assertArrayEquals(new Integer[] { 8, 9, 9, 9, 0, 0, 0, 1 }, list3.toArray()); - } - - public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { - int carry = 0; - ListNode dummy = new ListNode(0); - ListNode x = l1, y = l2, p = dummy; - while (x != null && y != null) { - int sum = x.val + y.val + carry; - carry = sum / 10; - p.next = sum >= 0 ? new ListNode(sum % 10) : new ListNode(sum); - p = p.next; - x = x.next; - y = y.next; - } - while (x != null) { - int sum = x.val + carry; - carry = sum / 10; - p.next = sum >= 0 ? new ListNode(sum % 10) : new ListNode(sum); - p = p.next; - x = x.next; - } - while (y != null) { - int sum = y.val + carry; - carry = sum / 10; - p.next = sum >= 0 ? new ListNode(sum % 10) : new ListNode(sum); - p = p.next; - y = y.next; - } - if (carry > 0) { - p.next = new ListNode(carry); - } - return dummy.next; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" deleted file mode 100644 index 029cc7f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\344\270\244\346\225\260\347\233\270\345\212\240II.java" +++ /dev/null @@ -1,79 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * LCR 025. 两数相加II - * - * @author Zhang Peng - * @date 2025-01-21 - */ -public class 两数相加II { - - public static void main(String[] args) { - ListNode result = addTwoNumbers(ListUtil.buildList(7, 2, 4, 3), ListUtil.buildList(5, 6, 4)); - List list = ListUtil.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 7, 8, 0, 7 }, list.toArray()); - - ListNode result2 = addTwoNumbers(ListUtil.buildList(2, 4, 3), ListUtil.buildList(5, 6, 4)); - List list2 = ListUtil.toList(result2); - System.out.println(list2); - Assertions.assertArrayEquals(new Integer[] { 8, 0, 7 }, list2.toArray()); - - ListNode result3 = addTwoNumbers(ListUtil.buildList(0), ListUtil.buildList(0)); - List list3 = ListUtil.toList(result3); - System.out.println(list3); - Assertions.assertArrayEquals(new Integer[] { 0 }, list3.toArray()); - } - - public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { - LinkedList list1 = reverse(l1); - LinkedList list2 = reverse(l2); - LinkedList list = new LinkedList<>(); - int carry = 0; - while (!list1.isEmpty() && !list2.isEmpty()) { - int x = list1.pop(); - int y = list2.pop(); - int sum = x + y + carry; - carry = sum / 10; - list.push(sum % 10); - } - while (!list1.isEmpty()) { - int x = list1.pop(); - int sum = x + carry; - carry = sum / 10; - list.push(sum % 10); - } - while (!list2.isEmpty()) { - int y = list2.pop(); - int sum = y + carry; - carry = sum / 10; - list.push(sum % 10); - } - if (carry > 0) { - list.push(carry); - } - ListNode dummy = new ListNode(-1); - ListNode p = dummy; - while (!list.isEmpty()) { - int x = list.pop(); - p.next = new ListNode(x); - p = p.next; - } - return dummy.next; - } - - public static LinkedList reverse(ListNode head) { - LinkedList list = new LinkedList<>(); - while (head != null) { - list.push(head.val); - head = head.next; - } - return list; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\206\351\232\224\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\206\351\232\224\351\223\276\350\241\250.java" deleted file mode 100644 index d0d19f2..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\206\351\232\224\351\223\276\350\241\250.java" +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -import java.util.List; - -/** - * 86. 分隔链表 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 分隔链表 { - - public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 4, 3, 2, 5, 2); - ListNode result = partition(head, 3); - List list = ListUtil.toList(result); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 2, 4, 3, 5 }, list.toArray(new Integer[0])); - - ListNode head2 = ListUtil.buildList(2, 1); - ListNode result2 = partition(head2, 2); - List list2 = ListUtil.toList(result2); - Assertions.assertArrayEquals(new Integer[] { 1, 2 }, list2.toArray(new Integer[0])); - - ListNode head3 = ListUtil.buildList(3, 1, 2); - ListNode result3 = partition(head3, 3); - List list3 = ListUtil.toList(result3); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, list3.toArray(new Integer[0])); - } - - public static ListNode partition(ListNode head, int x) { - ListNode left = new ListNode(-1); - ListNode right = new ListNode(-1); - ListNode p = head, l = left, r = right; - while (p != null) { - if (p.val < x) { - l.next = p; - l = l.next; - } else { - r.next = p; - r = r.next; - } - ListNode temp = p.next; - p.next = null; - p = temp; - } - l.next = right.next; - return left.next; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.java" deleted file mode 100644 index 918b444..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240II.java" +++ /dev/null @@ -1,91 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -import java.util.List; - -/** - * 82. 删除排序链表中的重复元素 II - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 删除排序链表中的重复元素II { - - public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 2, 3, 3, 4, 4, 5); - System.out.println(ListUtil.toList(head)); - ListNode result = deleteDuplicates2(head); - List list = ListUtil.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 5 }, list.toArray(new Integer[0])); - - ListNode head2 = ListUtil.buildList(1, 1, 1, 2, 3); - System.out.println(ListUtil.toList(head2)); - ListNode result2 = deleteDuplicates2(head2); - List list2 = ListUtil.toList(result2); - System.out.println(list2); - Assertions.assertArrayEquals(new Integer[] { 2, 3 }, list2.toArray(new Integer[0])); - - ListNode head3 = ListUtil.buildList(1, 2, 2); - System.out.println(ListUtil.toList(head3)); - ListNode result3 = deleteDuplicates2(head3); - List list3 = ListUtil.toList(result3); - System.out.println(list3); - Assertions.assertArrayEquals(new Integer[] { 1 }, list3.toArray(new Integer[0])); - } - - public static ListNode deleteDuplicates(ListNode head) { - if (head == null) { - return null; - } - boolean flag = false; - ListNode dummy = new ListNode(101); - dummy.next = head; - ListNode pre = dummy, begin = head, end = head.next; - while (end != null) { - if (begin.val == end.val) { - flag = true; - end = end.next; - } else { - if (flag) { - pre.next = end; - begin = end; - end = end.next; - flag = false; - } else { - pre = pre.next; - begin = begin.next; - end = end.next; - } - } - } - if (flag) { pre.next = end; } - return dummy.next; - } - - public static ListNode deleteDuplicates2(ListNode head) { - if (head == null) { - return null; - } - - ListNode dupList = new ListNode(101); - ListNode nodupList = new ListNode(101); - ListNode pDup = dupList, pNoDup = nodupList, p = head; - while (p != null) { - if (p.next != null && p.next.val == p.val || p.val == pDup.val) { - pDup.next = p; - pDup = pDup.next; - } else { - pNoDup.next = p; - pNoDup = pNoDup.next; - } - - p = p.next; - pDup.next = null; - pNoDup.next = null; - } - return nodupList.next; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" deleted file mode 100644 index 43e81d7..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" +++ /dev/null @@ -1,54 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -import java.util.List; - -/** - * 19. 删除链表的倒数第 N 个结点 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 删除链表的倒数第N个结点 { - - public static void main(String[] args) { - ListNode head1 = ListUtil.buildList(1, 2, 3, 4, 5); - ListNode result = removeNthFromEnd(head1, 2); - List list = ListUtil.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3, 5 }, list.toArray(new Integer[0])); - - ListNode head2 = ListUtil.buildList(1); - ListNode result2 = removeNthFromEnd(head2, 1); - List list2 = ListUtil.toList(result2); - System.out.println(list2); - Assertions.assertArrayEquals(new Integer[] {}, list2.toArray(new Integer[0])); - - ListNode head3 = ListUtil.buildList(1, 2); - ListNode result3 = removeNthFromEnd(head3, 1); - List list3 = ListUtil.toList(result3); - System.out.println(list3); - Assertions.assertArrayEquals(new Integer[] { 1 }, list3.toArray(new Integer[0])); - } - - public static ListNode removeNthFromEnd(ListNode head, int n) { - ListNode dummy = new ListNode(-1); - dummy.next = head; - - ListNode fast = dummy; - for (int i = 0; i < n + 1; i++) { - fast = fast.next; - } - - ListNode slow = dummy; - while (fast != null) { - fast = fast.next; - slow = slow.next; - } - - slow.next = slow.next.next; - return dummy.next; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250.java" deleted file mode 100644 index 22efea0..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250.java" +++ /dev/null @@ -1,88 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -import java.util.List; -import java.util.Stack; - -/** - * 206. 反转链表 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 反转链表 { - - public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 2, 3, 4); - System.out.println(ListUtil.toList(head)); - ListNode result = reverseList3(head); - List list = ListUtil.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 4, 3, 2, 1 }, list.toArray(new Integer[0])); - - ListNode head2 = ListUtil.buildList(1, 2); - System.out.println(ListUtil.toList(head2)); - ListNode result2 = reverseList3(head2); - List list2 = ListUtil.toList(result2); - System.out.println(list2); - Assertions.assertArrayEquals(new Integer[] { 2, 1 }, list2.toArray(new Integer[0])); - - ListNode head3 = ListUtil.buildList(); - System.out.println(ListUtil.toList(head3)); - ListNode result3 = reverseList3(head3); - List list3 = ListUtil.toList(result3); - System.out.println(list3); - Assertions.assertArrayEquals(new Integer[] {}, list3.toArray(new Integer[0])); - } - - /** - * 借助栈来实现,时间复杂度:O(2N) - */ - public static ListNode reverseList(ListNode head) { - if (head == null) { - return head; - } - - Stack stack = new Stack<>(); - ListNode node = head; - while (node != null) { - stack.push(node); - node = node.next; - } - - ListNode dummy = new ListNode(5001); - ListNode n = dummy; - while (!stack.isEmpty()) { - n.next = stack.pop(); - n = n.next; - n.next = null; - } - return dummy.next; - } - - public static ListNode reverseList2(ListNode head) { - if (head == null || head.next == null) return head; - - ListNode pre = null, cur = head, next = head.next; - while (cur != null) { - cur.next = pre; - pre = cur; - cur = next; - if (next != null) { - next = next.next; - } - } - return pre; - } - - public static ListNode reverseList3(ListNode head) { - if (head == null || head.next == null) return head; - - ListNode reverse = reverseList3(head.next); - head.next.next = head; - head.next = null; - return reverse; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" deleted file mode 100644 index 8f3d29c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\217\215\350\275\254\351\223\276\350\241\250II.java" +++ /dev/null @@ -1,60 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -import java.util.List; - -/** - * 92. 反转链表 II - * - * @author Zhang Peng - * @date 2025-01-20 - */ -public class 反转链表II { - - public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 2, 3, 4, 5); - System.out.println(ListUtil.toList(head)); - ListNode result = reverseBetween(head, 2, 4); - List list = ListUtil.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 1, 4, 3, 2, 5 }, list.toArray(new Integer[0])); - - ListNode head2 = ListUtil.buildList(3, 5); - System.out.println(ListUtil.toList(head2)); - ListNode result2 = reverseBetween(head2, 1, 2); - List list2 = ListUtil.toList(result2); - System.out.println(list2); - Assertions.assertArrayEquals(new Integer[] { 5, 3 }, list2.toArray(new Integer[0])); - } - - public static ListNode reverseBetween(ListNode head, int left, int right) { - if (left == 1) { - return reverseN(head, right); - } - - ListNode pre = head; - for (int i = 1; i < left - 1; i++) { - pre = pre.next; - } - pre.next = reverseN(pre.next, right - left + 1); - return head; - } - - static ListNode reverseN(ListNode head, int n) { - if (head == null || head.next == null) return head; - ListNode pre = null, cur = head, next = head.next; - while (n > 0) { - cur.next = pre; - pre = cur; - cur = next; - if (next != null) { - next = next.next; - } - n--; - } - head.next = cur; - return pre; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" deleted file mode 100644 index 2dfe1d3..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" +++ /dev/null @@ -1,112 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -import java.util.List; -import java.util.PriorityQueue; - -/** - * 23. 合并 K 个升序链表 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 合并K个升序链表 { - - public static void main(String[] args) { - ListNode head1 = ListUtil.buildList(1, 4, 5); - ListNode head2 = ListUtil.buildList(1, 3, 4); - ListNode head3 = ListUtil.buildList(2, 6); - ListNode[] array = new ListNode[] { head1, head2, head3 }; - ListNode result = mergeKLists3(array); - List list = ListUtil.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 1, 1, 2, 3, 4, 4, 5, 6 }, list.toArray(new Integer[0])); - - ListNode[] array2 = new ListNode[] {}; - ListNode result2 = mergeKLists3(array2); - List list2 = ListUtil.toList(result2); - System.out.println(list2); - Assertions.assertArrayEquals(new Integer[] {}, list2.toArray(new Integer[0])); - } - - public static ListNode mergeKLists(ListNode[] lists) { - if (lists == null || lists.length == 0) { - return null; - } - - ListNode dummy = new ListNode(-1); - ListNode p = dummy; - PriorityQueue queue = new PriorityQueue<>(lists.length, (a, b) -> a.val - b.val); - for (ListNode head : lists) { - if (head != null) { - queue.add(head); - } - } - - while (!queue.isEmpty()) { - ListNode node = queue.poll(); - p.next = node; - if (node.next != null) { - queue.add(node.next); - } - p = p.next; - } - return dummy.next; - } - - /** - * 效率不高 - */ - public static ListNode mergeKLists2(ListNode[] lists) { - if (lists == null || lists.length == 0) { - return null; - } - // 把 k 个有序链表都合并到 lists[0] 上 - ListNode resList = lists[0]; - for (int i = 1; i < lists.length; i++) { - resList = merge2List(resList, lists[i]); - } - return resList; - } - - public static ListNode merge2List(ListNode l1, ListNode l2) { - ListNode dummy = new ListNode(-1); - ListNode p = dummy, p1 = l1, p2 = l2; - while (p1 != null && p2 != null) { - if (p1.val <= p2.val) { - p.next = p1; - p1 = p1.next; - } else { - p.next = p2; - p2 = p2.next; - } - p = p.next; - } - if (p1 != null) { - p.next = p1; - } - if (p2 != null) { - p.next = p2; - } - return dummy.next; - } - - public static ListNode mergeKLists3(ListNode[] lists) { - if (lists == null || lists.length == 0) { - return null; - } - return mergeKLists3(lists, 0, lists.length - 1); - } - - public static ListNode mergeKLists3(ListNode[] lists, int start, int end) { - if (start == end) { - return lists[start]; - } - int mid = (start + end) / 2; - ListNode left = mergeKLists3(lists, start, mid); - ListNode right = mergeKLists3(lists, mid + 1, end); - return merge2List(left, right); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" deleted file mode 100644 index 652d419..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" +++ /dev/null @@ -1,42 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -import java.util.List; - -/** - * 21. 合并两个有序链表 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 合并两个有序链表 { - - public static void main(String[] args) { - ListNode head1 = ListUtil.buildList(1, 2, 4); - ListNode head2 = ListUtil.buildList(1, 3, 4); - ListNode result = mergeTwoLists(head1, head2); - List list = ListUtil.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 1, 1, 2, 3, 4, 4 }, list.toArray(new Integer[0])); - } - - public static ListNode mergeTwoLists(ListNode l1, ListNode l2) { - ListNode dummy = new ListNode(-1); - ListNode p = dummy; - while (l1 != null && l2 != null) { - if (l1.val <= l2.val) { - p.next = l1; - l1 = l1.next; - } else { - p.next = l2; - l2 = l2.next; - } - p = p.next; - } - - p.next = (l1 != null) ? l1 : l2; - return dummy.next; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" deleted file mode 100644 index f1a3ffa..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250.java" +++ /dev/null @@ -1,43 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -/** - * 141. 环形链表 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 环形链表 { - - public static void main(String[] args) { - ListNode head = ListUtil.buildList(3, 2, 0, -4); - Assertions.assertFalse(hasCycle(head)); - - ListNode head2 = ListUtil.buildCycleList(1, new int[] { 3, 2, 0, -4 }); - Assertions.assertTrue(hasCycle(head2)); - - ListNode head3 = ListUtil.buildCycleList(0, new int[] { 1, 2 }); - Assertions.assertTrue(hasCycle(head3)); - - ListNode head4 = ListUtil.buildCycleList(1, new int[] { 1 }); - Assertions.assertFalse(hasCycle(head4)); - } - - public static boolean hasCycle(ListNode head) { - // 快慢指针初始化指向 head - ListNode slow = head, fast = head; - // 快指针走到末尾时停止 - while (fast != null && fast.next != null) { - // 慢指针走一步,快指针走两步 - slow = slow.next; - fast = fast.next.next; - // 快慢指针相遇,说明含有环 - if (slow == fast) { - return true; - } - } - return false; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" deleted file mode 100644 index 888ba13..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\216\257\345\275\242\351\223\276\350\241\250II.java" +++ /dev/null @@ -1,48 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -/** - * 142. 环形链表 II - * - * @author Zhang Peng - * @since 2020-07-08 - */ -public class 环形链表II { - - public static void main(String[] args) { - ListNode head = ListUtil.buildList(3, 2, 0, -4); - Assertions.assertEquals(null, detectCycle(head)); - - ListNode head2 = ListUtil.buildCycleList(1, new int[] { 3, 2, 0, -4 }); - Assertions.assertEquals(2, detectCycle(head2).val); - - ListNode head3 = ListUtil.buildCycleList(0, new int[] { 1, 2 }); - Assertions.assertEquals(1, detectCycle(head3).val); - - ListNode head4 = ListUtil.buildCycleList(1, new int[] { 1 }); - Assertions.assertEquals(null, detectCycle(head4)); - } - - public static ListNode detectCycle(ListNode head) { - ListNode slow = head, fast = head; - while (fast != null && fast.next != null) { - slow = slow.next; - fast = fast.next.next; - if (slow == fast) { - break; - } - } - if (fast == null || fast.next == null) { - return null; - } - - fast = head; - while (fast != slow) { - slow = slow.next; - fast = fast.next; - } - return slow; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" deleted file mode 100644 index e93c7f9..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\347\233\270\344\272\244\351\223\276\350\241\250.java" +++ /dev/null @@ -1,54 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -/** - * 相交链表 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 相交链表 { - - public static void main(String[] args) { - ListNode listA = ListUtil.buildList(4, 1, 8, 4, 5); - ListNode listB = ListUtil.buildList(5, 6, 1, 8, 4, 5); - buildMetPot(listA, listB, 2, 3); - ListNode result = getIntersectionNode(listA, listB); - Assertions.assertEquals(8, result.val); - - ListNode listA2 = ListUtil.buildList(1, 9, 1, 2, 4); - ListNode listB2 = ListUtil.buildList(3, 2, 4); - buildMetPot(listA2, listB2, 3, 1); - ListNode result2 = getIntersectionNode(listA2, listB2); - Assertions.assertEquals(2, result2.val); - - ListNode listA3 = ListUtil.buildList(2,6,4); - ListNode listB3 = ListUtil.buildList(1,5); - ListNode result3 = getIntersectionNode(listA3, listB3); - Assertions.assertNull(result3); - } - - public static void buildMetPot(ListNode listA, ListNode listB, int skipA, int skipB) { - ListNode pA = listA; - for (int i = 0; i < skipA; i++) { - pA = pA.next; - } - ListNode pB = listB; - for (int i = 0; i < skipB - 1; i++) { - pB = pB.next; - } - pB.next = pA; - } - - public static ListNode getIntersectionNode(ListNode headA, ListNode headB) { - // pA 指向 A 链表头结点,pB 指向 B 链表头结点 - ListNode pA = headA, pB = headB; - while (pA != pB) { - pA = pA == null ? headB : pA.next; - pB = pB == null ? headA : pB.next; - } - return pA; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" deleted file mode 100644 index d2725ab..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -/** - * 面试题 02. 返回倒数第 k 个节点 - * LCR 140. 训练计划 II - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 返回倒数第k个节点 { - - public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 2, 3, 4, 5); - int val = kthToLast(head, 2); - Assertions.assertEquals(4, val); - - ListNode head2 = ListUtil.buildList(1); - int val2 = kthToLast(head2, 1); - Assertions.assertEquals(1, val2); - } - - public static int kthToLast(ListNode head, int k) { - ListNode fast = head; - // fast 指针先走 k 步 - for (int i = 0; i < k; i++) { - fast = fast.next; - } - // fast、slow 同时走,直到结束 - ListNode slow = head; - while (fast != null) { - fast = fast.next; - slow = slow.next; - } - // slow 现在指向第 n - k + 1 个节点,即倒数第 k 个节点 - return slow.val; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" deleted file mode 100644 index 47b9b1e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import org.junit.jupiter.api.Assertions; - -import java.util.List; - -/** - * 876. 链表的中间结点 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 链表的中间结点 { - - public static void main(String[] args) { - ListNode head = ListUtil.buildList(1, 2, 3, 4, 5); - System.out.println(ListUtil.toList(head)); - ListNode result = middleNode(head); - List list = ListUtil.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 3, 4, 5 }, list.toArray(new Integer[0])); - - ListNode head2 = ListUtil.buildList(1, 2, 3, 4, 5, 6); - System.out.println(ListUtil.toList(head2)); - ListNode result2 = middleNode(head2); - List list2 = ListUtil.toList(result2); - System.out.println(list2); - Assertions.assertArrayEquals(new Integer[] { 4, 5, 6 }, list2.toArray(new Integer[0])); - } - - public static ListNode middleNode(ListNode head) { - // 利用快慢指针,慢指针每次偏移一个节点,快指针每次偏移两个节点 - ListNode slow = head, fast = head; - while (fast != null && fast.next != null) { - slow = slow.next; - fast = fast.next.next; - } - return slow; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" index d0b428b..46f389d 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.queue_and_stack.stack; -import io.github.dunwu.algorithm.list.ListNode; -import io.github.dunwu.algorithm.list.ListUtil; +import io.github.dunwu.algorithm.linkedlist.ListNode; import org.junit.jupiter.api.Assertions; import java.util.List; @@ -16,15 +15,15 @@ public class 重排链表 { public static void main(String[] args) { - ListNode input = ListUtil.buildList(1, 2, 3, 4); + ListNode input = ListNode.buildList(1, 2, 3, 4); reorderList(input); - List list = ListUtil.toList(input); + List list = ListNode.toList(input); System.out.println(list); Assertions.assertArrayEquals(new Integer[] { 1, 4, 2, 3 }, list.toArray()); - ListNode input2 = ListUtil.buildList(1, 2, 3, 4, 5); + ListNode input2 = ListNode.buildList(1, 2, 3, 4, 5); reorderList(input2); - List list2 = ListUtil.toList(input2); + List list2 = ListNode.toList(input2); System.out.println(list2); Assertions.assertArrayEquals(new Integer[] { 1, 5, 2, 4, 3 }, list2.toArray()); } diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java index a89cfb7..448f347 100644 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java +++ b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java @@ -1,5 +1,6 @@ package io.github.dunwu.algorithm.list; +import io.github.dunwu.algorithm.linkedlist.DoublyLinkedList; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java index 06cf157..aabfe67 100644 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java +++ b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java @@ -1,5 +1,6 @@ package io.github.dunwu.algorithm.list; +import io.github.dunwu.algorithm.linkedlist.SinglyLinkedList; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; From 8da0a4ce5310c78ff39f174ea20f5ed6e565bc45 Mon Sep 17 00:00:00 2001 From: dunwu Date: Thu, 20 Nov 2025 23:01:30 +0800 Subject: [PATCH 15/21] =?UTF-8?q?feat:=20leetcode=20=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 101 +++++++++--------- ...\347\232\204\345\215\225\350\257\215.java" | 69 ++++++++++++ ...\350\275\254\345\233\276\345\203\217.java" | 55 ++++++++++ ...\346\227\213\347\237\251\351\230\265.java" | 75 +++++++++++++ ...346\227\213\347\237\251\351\230\2652.java" | 59 ++++++++++ ...\347\273\264\346\225\260\347\273\204.java" | 84 +++++++++++++++ ...\345\217\243\346\250\241\346\235\277.java" | 46 ++++++++ ...\346\225\260\344\271\213\345\222\214.java" | 67 ++++++++++++ ...346\225\260\344\271\213\345\222\2142.java" | 69 ++++++++++++ ...\346\240\274\350\277\201\347\247\273.java" | 88 +++++++++++++++ ...\351\207\215\345\244\215\351\241\271.java" | 37 +++++++ ...351\207\215\345\244\215\351\241\2712.java" | 45 ++++++++ ...\345\255\227\347\254\246\344\270\262.java" | 39 +++++++ ...\345\272\217\346\225\260\347\273\204.java" | 67 ++++++++++++ ...\347\272\277\346\216\222\345\272\217.java" | 70 ++++++++++++ ...\345\205\261\345\211\215\347\274\200.java" | 49 +++++++++ ...\346\226\207\345\255\220\344\270\262.java" | 84 +++++++++++++++ ...\347\232\204\345\271\263\346\226\271.java" | 49 +++++++++ ...\344\270\252\345\225\206\345\223\201.java" | 39 +++++++ ...\347\247\273\345\212\250\351\233\266.java" | 50 +++++++++ ...\351\231\244\345\205\203\347\264\240.java" | 43 ++++++++ ...\347\275\256\347\237\251\351\230\265.java" | 41 +++++++ ...\350\211\262\345\210\206\347\261\273.java" | 53 +++++++++ ...\345\233\236\346\226\207\344\270\262.java" | 74 +++++++++++++ ...\347\232\204\346\216\222\345\210\227.java" | 80 ++++++-------- ...\346\223\215\344\275\234\346\225\260.java" | 60 ++++++----- ...\345\274\202\344\275\215\350\257\215.java" | 79 +++++++------- ...\351\225\277\345\255\220\344\270\262.java" | 62 +++++------ ...\347\233\226\345\255\220\344\270\262.java" | 82 +++++++------- ...\346\225\260\344\271\213\345\222\214.java" | 56 ---------- ...46\225\260\344\271\213\345\222\214II.java" | 79 -------------- ...\347\273\264\346\225\260\347\273\204.java" | 34 ------ ...\346\240\274\350\277\201\347\247\273.java" | 97 ----------------- ...\351\207\215\345\244\215\351\241\271.java" | 41 ------- ...51\207\215\345\244\215\351\241\271II.java" | 43 -------- ...\345\255\227\347\254\246\344\270\262.java" | 34 ------ ...\345\272\217\346\225\260\347\273\204.java" | 66 ------------ ...\347\272\277\346\216\222\345\272\217.java" | 56 ---------- ...\350\275\254\345\233\276\345\203\217.java" | 55 ---------- ...\350\275\254\346\225\260\347\273\204.java" | 63 ----------- ...\350\275\254\347\237\251\351\230\265.java" | 45 -------- ...\345\205\261\345\211\215\347\274\200.java" | 44 -------- ...\346\226\207\345\255\220\344\270\262.java" | 43 -------- ...\347\232\204\345\271\263\346\226\271.java" | 43 -------- ...\347\247\273\345\212\250\351\233\266.java" | 64 ----------- ...\351\231\244\345\205\203\347\264\240.java" | 34 ------ ...\346\227\213\347\237\251\351\230\265.java" | 85 --------------- ...\347\275\256\347\237\251\351\230\265.java" | 37 ------- ...\350\211\262\345\210\206\347\261\273.java" | 82 -------------- ...\345\233\236\346\226\207\344\270\262.java" | 39 ------- ...\346\226\207\345\255\220\344\270\262.java" | 53 --------- ...\350\275\254\351\223\276\350\241\250.java" | 82 ++++++++++++++ 52 files changed, 1664 insertions(+), 1427 deletions(-) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\346\227\213\350\275\254\345\233\276\345\203\217.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\265.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\2652.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\351\201\215\345\216\206\344\272\214\347\273\264\346\225\260\347\273\204.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\346\273\221\345\212\250\347\252\227\345\217\243\346\250\241\346\235\277.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\244\346\225\260\344\271\213\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\244\346\225\260\344\271\213\345\222\2142.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\2712.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\347\247\273\345\212\250\351\233\266.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\347\247\273\351\231\244\345\205\203\347\264\240.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\350\275\254\347\275\256\347\237\251\351\230\265.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\351\242\234\350\211\262\345\210\206\347\261\273.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\346\225\260\347\273\204.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271II.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\345\233\276\345\203\217.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\346\225\260\347\273\204.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\347\237\251\351\230\265.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\345\212\250\351\233\266.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\351\231\244\345\205\203\347\264\240.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\236\272\346\227\213\347\237\251\351\230\265.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\275\254\347\275\256\347\237\251\351\230\265.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\242\234\350\211\262\345\210\206\347\261\273.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\346\227\213\350\275\254\351\223\276\350\241\250.java" diff --git a/README.md b/README.md index 0943177..1d6d6d7 100644 --- a/README.md +++ b/README.md @@ -81,9 +81,10 @@ | 题目 | 难度 | 掌握度 | | ------------------------------------------------------------------------------ | ---- | ------ | -| [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/) | 💚 | ✔️ | -| [92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/) | 💛 | ❗ | -| [25. K 个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group/) | ❤️ | ❗ | +| [61. 旋转链表](https://leetcode.cn/problems/rotate-list/) | 💛 | ✔️ | +| [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/) | 💚 | ✔️ | +| [92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/) | 💛 | ❗ | +| [25. K 个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group/) | ❤️ | ❗ | #### 回文链表 @@ -95,59 +96,53 @@ #### 双指针技巧 -| 题目 | 掌握度 | -| ------------------------------------------------------------------------------------------------------ | ------ | --- | -| [26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/) | ✔️ | -| [27. 移除元素](https://leetcode.cn/problems/remove-element/) | ✔️ | -| [283. 移动零](https://leetcode.cn/problems/move-zeroes/) | ✔️ | -| [704. 二分查找](https://leetcode.cn/problems/binary-search/) | ✔️ | -| [1. 两数之和](https://leetcode.cn/problems/two-sum/) | ✔️ | -| [167. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/) | ✔️ | -| [LCR 179. 查找总价格为目标值的两个商品](https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/) | ✔️ | -| [LCR 006. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/kLl5u1/) | ✔️ | -| [344. 反转字符串](https://leetcode.cn/problems/reverse-string/) | ✔️ | -| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | ❌ | -| [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | 💛 | ❌ | -| [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | 💛 | ❌ | - -#### 数组双指针经典习题 - -| 题目 | 掌握度 | -| ----------------------------------------------------------------------------------------------------- | ------ | -| [80. 删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/) | ✔️ | -| [125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/) | ✔️ | -| [75. 颜色分类](https://leetcode.cn/problems/sort-colors/) | ✔️ | -| [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/) | ❗ | -| [977. 有序数组的平方](https://leetcode.cn/problems/squares-of-a-sorted-array/) | ✔️ | -| [1329. 将矩阵按对角线排序](https://leetcode.cn/problems/sort-the-matrix-diagonally/) | ❗ | -| [1260. 二维网格迁移](https://leetcode.cn/problems/shift-2d-grid/) | ❌ | -| [867. 转置矩阵](https://leetcode.cn/problems/transpose-matrix/) | ✔️ | -| [14. 最长公共前缀](https://leetcode.cn/problems/longest-common-prefix/) | ✔️ | - -#### 二维数组的花式遍历技巧 - -| 题目 | 掌握度 | -| ----------------------------------------------------------------- | ------ | -| [48. 旋转图像](https://leetcode.cn/problems/rotate-image/) | ❌ | -| [54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/) | ❌ | -| [59. 螺旋矩阵 II](https://leetcode.cn/problems/spiral-matrix-ii/) | ❌ | +| 题目 | 难度 | 掌握度 | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | +| [27. 移除元素](https://leetcode.cn/problems/remove-element/) | 💚 | ✔️ | +| [283. 移动零](https://leetcode.cn/problems/move-zeroes/) | 💚 | ✔️ | +| [LCR 179. 查找总价格为目标值的两个商品](https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/) | 💚 | ✔️ | +| [1. 两数之和](https://leetcode.cn/problems/two-sum/) | 💚 | ✔️ | +| [167. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/)
[LCR 006. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/kLl5u1/) | 💛 | ✔️ | +| [26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/) | 💚 | ✔️ | +| [80. 删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/) | 💛 | ✔️ | +| [344. 反转字符串](https://leetcode.cn/problems/reverse-string/) | 💚 | ✔️ | +| [125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/) | 💚 | ✔️ | +| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 💛 | ❗ | +| [75. 颜色分类](https://leetcode.cn/problems/sort-colors/) | 💛 | ✔️ | +| [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/) | 💚 | ❗ | +| [977. 有序数组的平方](https://leetcode.cn/problems/squares-of-a-sorted-array/) | 💚 | ✔️ | +| [1329. 将矩阵按对角线排序](https://leetcode.cn/problems/sort-the-matrix-diagonally/) | 💛 | ❗ | +| [1260. 二维网格迁移](https://leetcode.cn/problems/shift-2d-grid/) | 💚 | ❗ | +| [867. 转置矩阵](https://leetcode.cn/problems/transpose-matrix/) | 💚 | ✔️ | +| [14. 最长公共前缀](https://leetcode.cn/problems/longest-common-prefix/) | 💚 | ✔️ | +| [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | 💛 | | +| [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | 💛 | | + +#### 二维数组遍历 + +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---- | ------ | +| [151. 反转字符串中的单词](https://leetcode.cn/problems/reverse-words-in-a-string/) | 💛 | ❌ | +| [48. 旋转图像](https://leetcode.cn/problems/rotate-image/) | 💛 | ❗ | +| [54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/)
[LCR 146. 螺旋遍历二维数组](https://leetcode.cn/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/) | 💛 | ❌ | +| [59. 螺旋矩阵 II](https://leetcode.cn/problems/spiral-matrix-ii/) | 💛 | ❗ | #### 滑动窗口算法 -| 题目 | 掌握度 | -| -------------------------------------------------------------------------------------------------------------------------- | ------ | -| [3. 无重复字符的最长子串](https://leetcode.cn/problems/longest-substring-without-repeating-characters/) | ✔️ | -| [438. 找到字符串中所有字母异位词](https://leetcode.cn/problems/find-all-anagrams-in-a-string/) | ❗ | -| [567. 字符串的排列](https://leetcode.cn/problems/permutation-in-string/) | ❗ | -| [76. 最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring/) | ❌ | -| [1658. 将 x 减到 0 的最小操作数](https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/) | ❌ | -| [713. 乘积小于 K 的子数组](https://leetcode.cn/problems/subarray-product-less-than-k/) | ❌ | -| [1004. 最大连续 1 的个数 III](https://leetcode.cn/problems/max-consecutive-ones-iii/) | ✔️ | -| [424. 替换后的最长重复字符](https://leetcode.cn/problems/longest-repeating-character-replacement/) | ❗ | -| [219. 存在重复元素 II](https://leetcode.cn/problems/contains-duplicate-ii/) | ❗ | -| [220. 存在重复元素 III](https://leetcode.cn/problems/contains-duplicate-iii/) | ❌ | -| [209. 长度最小的子数组](https://leetcode.cn/problems/minimum-size-subarray-sum/) | ❌ | -| [395. 至少有 K 个重复字符的最长子串](https://leetcode.cn/problems/longest-substring-with-at-least-k-repeating-characters/) | ❌ | +| 题目 | 难度 | 掌握度 | +| -------------------------------------------------------------------------------------------------------------------------- | ------ | ------ | +| [3. 无重复字符的最长子串](https://leetcode.cn/problems/longest-substring-without-repeating-characters/) | | ❗ | +| [438. 找到字符串中所有字母异位词](https://leetcode.cn/problems/find-all-anagrams-in-a-string/) | | ❗ | +| [567. 字符串的排列](https://leetcode.cn/problems/permutation-in-string/) | | ❗ | +| [76. 最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring/) | | ❌ | +| [1658. 将 x 减到 0 的最小操作数](https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/) | | ❌ | +| [713. 乘积小于 K 的子数组](https://leetcode.cn/problems/subarray-product-less-than-k/) | | ❌ | +| [1004. 最大连续 1 的个数 III](https://leetcode.cn/problems/max-consecutive-ones-iii/) | | ✔️ | +| [424. 替换后的最长重复字符](https://leetcode.cn/problems/longest-repeating-character-replacement/) | | ❗ | +| [219. 存在重复元素 II](https://leetcode.cn/problems/contains-duplicate-ii/) | | ❗ | +| [220. 存在重复元素 III](https://leetcode.cn/problems/contains-duplicate-iii/) | | ❌ | +| [209. 长度最小的子数组](https://leetcode.cn/problems/minimum-size-subarray-sum/) | | ❌ | +| [395. 至少有 K 个重复字符的最长子串](https://leetcode.cn/problems/longest-substring-with-at-least-k-repeating-characters/) | | ❌ | #### 二分查找算法 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215.java" new file mode 100644 index 0000000..1e6eff6 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215.java" @@ -0,0 +1,69 @@ +package io.github.dunwu.algorithm.array.matrix; + +import org.junit.jupiter.api.Assertions; + +/** + * 151. 反转字符串中的单词 + * + * @author Zhang Peng + * @since 2020-06-05 + */ +public class 反转字符串中的单词 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals("blue is sky the", s.reverseWords("the sky is blue")); + Assertions.assertEquals("world hello", s.reverseWords(" hello world ")); + Assertions.assertEquals("example good a", s.reverseWords("a good example")); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals("blue is sky the", s2.reverseWords("the sky is blue")); + Assertions.assertEquals("world hello", s2.reverseWords(" hello world ")); + Assertions.assertEquals("example good a", s2.reverseWords("a good example")); + } + + // 利用库函数 + static class Solution { + + public String reverseWords(String s) { + String[] strs = s.split(" "); + StringBuilder sb = new StringBuilder(); + for (int i = strs.length - 1; i >= 0; i--) { + if (strs[i].equals("")) { + continue; + } + sb.append(strs[i]).append(" "); + } + if (sb.lastIndexOf(" ") == sb.length() - 1) { + return sb.substring(0, sb.length() - 1); + } + return sb.toString(); + } + + } + + // 双指针 + static class Solution2 { + + public String reverseWords(String s) { + // 删除首尾空格 + s = s.trim(); + int i = s.length() - 1, j = i; + StringBuilder res = new StringBuilder(); + while (i >= 0) { + // 搜索首个空格 + while (i >= 0 && s.charAt(i) != ' ') { i--; } + // 添加单词 + res.append(s.substring(i + 1, j + 1)).append(" "); + // 跳过单词间空格 + while (i >= 0 && s.charAt(i) == ' ') { i--; } + // j 指向下个单词的尾字符 + j = i; + } + // 转化为字符串并返回 + return res.toString().trim(); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\346\227\213\350\275\254\345\233\276\345\203\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\346\227\213\350\275\254\345\233\276\345\203\217.java" new file mode 100644 index 0000000..b4bdd6d --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\346\227\213\350\275\254\345\233\276\345\203\217.java" @@ -0,0 +1,55 @@ +package io.github.dunwu.algorithm.array.matrix; + +import cn.hutool.core.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +/** + * LCR 006. 两数之和 II - 输入有序数组 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 旋转图像 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[][] matrix = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + s.rotate(matrix); + int[][] expect = { { 7, 4, 1 }, { 8, 5, 2 }, { 9, 6, 3 } }; + Assertions.assertTrue(ArrayUtil.equals(expect, matrix)); + + int[][] matrix2 = { { 5, 1, 9, 11 }, { 2, 4, 8, 10 }, { 13, 3, 6, 7 }, { 15, 14, 12, 16 } }; + s.rotate(matrix2); + int[][] expect2 = { { 15, 13, 2, 5 }, { 14, 3, 4, 1 }, { 12, 6, 8, 9 }, { 16, 7, 10, 11 } }; + Assertions.assertTrue(ArrayUtil.equals(expect2, matrix2)); + } + + static class Solution { + + public void rotate(int[][] matrix) { + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { return; } + int n = matrix.length; + // 沿对角线置换 + for (int i = 0; i < n; i++) { + for (int j = 0; j < i; j++) { + int temp = matrix[i][j]; + matrix[i][j] = matrix[j][i]; + matrix[j][i] = temp; + } + } + + for (int i = 0; i < n; i++) { + int left = 0, right = n - 1; + while (left < right) { + int temp = matrix[i][left]; + matrix[i][left] = matrix[i][right]; + matrix[i][right] = temp; + left++; + right--; + } + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\265.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\265.java" new file mode 100644 index 0000000..dc2eee6 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\265.java" @@ -0,0 +1,75 @@ +package io.github.dunwu.algorithm.array.matrix; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 54. 螺旋矩阵 + * + * @author Zhang Peng + * @since 2018-11-04 + */ +public class 螺旋矩阵 { + + public static void main(String[] args) { + Solution s = new Solution(); + List output = s.spiralOrder(new int[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }); + Assertions.assertArrayEquals(new Integer[] { 1, 2, 3, 6, 9, 8, 7, 4, 5 }, output.toArray()); + List output2 = s.spiralOrder(new int[][] { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }); + Assertions.assertArrayEquals(new Integer[] { 1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7 }, output2.toArray()); + } + + static class Solution { + + public List spiralOrder(int[][] matrix) { + if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) { + return new LinkedList<>(); + } + + int m = matrix.length, n = matrix[0].length; + int up = 0, down = m - 1; + int left = 0, right = n - 1; + List res = new LinkedList<>(); + while (res.size() < m * n) { + // 向右 + if (up <= down) { + for (int i = left; i <= right; i++) { + res.add(matrix[up][i]); + } + up++; + } + // System.out.printf("\t [right] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); + // 向下 + if (left <= right) { + for (int i = up; i <= down; i++) { + res.add(matrix[i][right]); + } + right--; + } + // System.out.printf("\t [down] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); + // 向左 + if (up <= down) { + for (int i = right; i >= left; i--) { + res.add(matrix[down][i]); + } + down--; + } + // System.out.printf("\t [left] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); + // 向上 + if (left <= right) { + for (int i = down; i >= up; i--) { + res.add(matrix[i][left]); + } + left++; + } + // System.out.printf("\t [up] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); + // System.out.printf("res: %s\n", JSONUtil.toJsonStr(res)); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\2652.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\2652.java" new file mode 100644 index 0000000..a9de77a --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\2652.java" @@ -0,0 +1,59 @@ +package io.github.dunwu.algorithm.array.matrix; + +import org.junit.jupiter.api.Assertions; + +/** + * 54. 螺旋矩阵 + * + * @author Zhang Peng + * @since 2018-11-04 + */ +public class 螺旋矩阵2 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[][] output = s.generateMatrix(3); + Assertions.assertArrayEquals(new int[][] { { 1, 2, 3 }, { 8, 9, 4 }, { 7, 6, 5 } }, output); + int[][] output2 = s.generateMatrix(1); + Assertions.assertArrayEquals(new int[][] { { 1 } }, output2); + } + + static class Solution { + + public int[][] generateMatrix(int n) { + + int cnt = 0; + int up = 0, down = n - 1; + int left = 0, right = n - 1; + int[][] res = new int[n][n]; + while (cnt < n * n) { + // 向右 + for (int i = left; i <= right; i++) { + res[up][i] = ++cnt; + } + up++; + + // 向下 + for (int i = up; i <= down; i++) { + res[i][right] = ++cnt; + } + right--; + + // 向左 + for (int i = right; i >= left; i--) { + res[down][i] = ++cnt; + } + down--; + + // 向上 + for (int i = down; i >= up; i--) { + res[i][left] = ++cnt; + } + left++; + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\351\201\215\345\216\206\344\272\214\347\273\264\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\351\201\215\345\216\206\344\272\214\347\273\264\346\225\260\347\273\204.java" new file mode 100644 index 0000000..c39ed1a --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\351\201\215\345\216\206\344\272\214\347\273\264\346\225\260\347\273\204.java" @@ -0,0 +1,84 @@ +package io.github.dunwu.algorithm.array.matrix; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 54. 螺旋矩阵 + * + * @author Zhang Peng + * @since 2018-11-04 + */ +public class 螺旋遍历二维数组 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[] output = s.spiralArray(new int[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }); + Assertions.assertArrayEquals(new int[] { 1, 2, 3, 6, 9, 8, 7, 4, 5 }, output); + int[] output2 = s.spiralArray(new int[][] { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }); + Assertions.assertArrayEquals(new int[] { 1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7 }, output2); + } + + static class Solution { + + public int[] spiralArray(int[][] array) { + List list = spiralOrder(array); + int[] res = new int[list.size()]; + for (int i = 0; i < list.size(); i++) { + res[i] = list.get(i); + } + return res; + } + + public List spiralOrder(int[][] matrix) { + if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) { + return new LinkedList<>(); + } + + int m = matrix.length, n = matrix[0].length; + int up = 0, down = m - 1; + int left = 0, right = n - 1; + List res = new LinkedList<>(); + while (res.size() < m * n) { + // 向右 + if (up <= down) { + for (int i = left; i <= right; i++) { + res.add(matrix[up][i]); + } + up++; + } + // System.out.printf("\t [right] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); + // 向下 + if (left <= right) { + for (int i = up; i <= down; i++) { + res.add(matrix[i][right]); + } + right--; + } + // System.out.printf("\t [down] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); + // 向左 + if (up <= down) { + for (int i = right; i >= left; i--) { + res.add(matrix[down][i]); + } + down--; + } + // System.out.printf("\t [left] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); + // 向上 + if (left <= right) { + for (int i = down; i >= up; i--) { + res.add(matrix[i][left]); + } + left++; + } + // System.out.printf("\t [up] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); + // System.out.printf("res: %s\n", JSONUtil.toJsonStr(res)); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\346\273\221\345\212\250\347\252\227\345\217\243\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\346\273\221\345\212\250\347\252\227\345\217\243\346\250\241\346\235\277.java" new file mode 100644 index 0000000..66a46d4 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\346\273\221\345\212\250\347\252\227\345\217\243\346\250\241\346\235\277.java" @@ -0,0 +1,46 @@ +package io.github.dunwu.algorithm.array.template; + +/** + * 滑动窗口模板 + * + * @author Zhang Peng + * @date 2025-11-20 + */ +public class 滑动窗口模板 { + + // 滑动窗口算法伪码框架 + // void slidingWindow(String s) { + // // 用合适的数据结构记录窗口中的数据,根据具体场景变通 + // // 比如说,我想记录窗口中元素出现的次数,就用 map + // // 如果我想记录窗口中的元素和,就可以只用一个 int + // Object window = ... + // + // int left = 0, right = 0; + // while (right < s.length()) { + // // c 是将移入窗口的字符 + // char c = s[right]; + // window.add(c) + // // 增大窗口 + // right++; + // // 进行窗口内数据的一系列更新 + // // ... + // + // // *** debug 输出的位置 *** + // // 注意在最终的解法代码中不要 print + // // 因为 IO 操作很耗时,可能导致超时 + // printf("window: [%d, %d)\n", left, right); + // // *********************** + // + // // 判断左侧窗口是否要收缩 + // while (left < right && window needs shrink){ + // // d 是将移出窗口的字符 + // char d = s[left]; + // window.remove(d) + // // 缩小窗口 + // left++; + // // 进行窗口内数据的一系列更新 + // ... + // } + // } + // } +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\244\346\225\260\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\244\346\225\260\344\271\213\345\222\214.java" new file mode 100644 index 0000000..27e751f --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\244\346\225\260\344\271\213\345\222\214.java" @@ -0,0 +1,67 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; +import java.util.Map; + +/** + * 1. 两数之和 + * + * @author Zhang Peng + * @since 2020-06-05 + */ +public class 两数之和 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new int[] { 0, 1 }, s.twoSum(new int[] { 2, 7, 11, 15 }, 9)); + Assertions.assertArrayEquals(new int[] { 1, 2 }, s.twoSum(new int[] { 3, 2, 4 }, 6)); + Assertions.assertArrayEquals(new int[] { 0, 1 }, s.twoSum(new int[] { 3, 3 }, 6)); + + Solution2 s2 = new Solution2(); + Assertions.assertArrayEquals(new int[] { 0, 1 }, s2.twoSum(new int[] { 2, 7, 11, 15 }, 9)); + Assertions.assertArrayEquals(new int[] { 1, 2 }, s2.twoSum(new int[] { 3, 2, 4 }, 6)); + Assertions.assertArrayEquals(new int[] { 0, 1 }, s2.twoSum(new int[] { 3, 3 }, 6)); + } + + /** + * 两次 for 循环暴力求解,时间复杂度 o(n^2) + */ + static class Solution { + + public int[] twoSum(int[] nums, int target) { + int n = nums.length; + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + if (nums[i] + nums[j] == target) { + return new int[] { i, j }; + } + } + } + return new int[0]; + } + + } + + /** + * Hash 存值、下标,一次 for 循环,每次判断 map 中是否有值和当前下标的值凑成 target + */ + static class Solution2 { + + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(nums.length); + for (int i = 0; i < nums.length; i++) { + int diff = target - nums[i]; + if (map.containsKey(diff)) { + return new int[] { map.get(diff), i }; + } else { + map.put(nums[i], i); + } + } + return new int[0]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\244\346\225\260\344\271\213\345\222\2142.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\244\346\225\260\344\271\213\345\222\2142.java" new file mode 100644 index 0000000..2585dda --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\244\346\225\260\344\271\213\345\222\2142.java" @@ -0,0 +1,69 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; +import java.util.Map; + +/** + * 167. 两数之和 II - 输入有序数组 + * + * @author Zhang Peng + * @since 2020-06-05 + */ +public class 两数之和2 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new int[] { 1, 2 }, s.twoSum(new int[] { 2, 7, 11, 15 }, 9)); + Assertions.assertArrayEquals(new int[] { 1, 3 }, s.twoSum(new int[] { 2, 3, 4 }, 6)); + Assertions.assertArrayEquals(new int[] { 1, 2 }, s.twoSum(new int[] { -1, 0 }, -1)); + + Solution2 s2 = new Solution2(); + Assertions.assertArrayEquals(new int[] { 1, 2 }, s2.twoSum(new int[] { 2, 7, 11, 15 }, 9)); + Assertions.assertArrayEquals(new int[] { 1, 3 }, s2.twoSum(new int[] { 2, 3, 4 }, 6)); + Assertions.assertArrayEquals(new int[] { 1, 2 }, s2.twoSum(new int[] { -1, 0 }, -1)); + } + + /** + * Hash 存值、下标,一次 for 循环,每次判断 map 中是否有值和当前下标的值凑成 target + */ + static class Solution { + + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(nums.length); + for (int i = 0; i < nums.length; i++) { + int diff = target - nums[i]; + if (map.containsKey(diff)) { + return new int[] { map.get(diff), i + 1 }; + } else { + map.put(nums[i], i + 1); + } + } + return new int[0]; + } + + } + + /** + * 双指针 + */ + static class Solution2 { + + public int[] twoSum(int[] nums, int target) { + int left = 0, right = nums.length - 1; + while (left < right) { + if (nums[left] + nums[right] == target) { + return new int[] { left + 1, right + 1 }; + } else if (nums[left] + nums[right] < target) { + left++; + } else { + right--; + } + } + return new int[0]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" new file mode 100644 index 0000000..9ab9ae6 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" @@ -0,0 +1,88 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import cn.hutool.json.JSONUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.List; + +/** + * 1260. 二维网格迁移 + * + * @author Zhang Peng + * @date 2025-10-14 + */ +public class 二维网格迁移 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + int[][] grid1 = new int[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + List> res1 = s.shiftGrid(grid1, 1); + Assertions.assertNotNull(res1); + Assertions.assertArrayEquals(new Integer[] { 9, 1, 2 }, res1.get(0).toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 3, 4, 5 }, res1.get(1).toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 6, 7, 8 }, res1.get(2).toArray(new Integer[0])); + + int[][] grid2 = new int[][] { { 3, 8, 1, 9 }, { 19, 7, 2, 5 }, { 4, 6, 11, 10 }, { 12, 0, 21, 13 } }; + List> res2 = s.shiftGrid(grid2, 4); + Assertions.assertNotNull(res2); + Assertions.assertArrayEquals(new Integer[] { 12, 0, 21, 13 }, res2.get(0).toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 3, 8, 1, 9 }, res2.get(1).toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 19, 7, 2, 5 }, res2.get(2).toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 4, 6, 11, 10 }, res2.get(3).toArray(new Integer[0])); + + int[][] grid3 = new int[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + List> res3 = s.shiftGrid(grid3, 9); + Assertions.assertNotNull(res3); + Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, res3.get(0).toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 4, 5, 6 }, res3.get(1).toArray(new Integer[0])); + Assertions.assertArrayEquals(new Integer[] { 7, 8, 9 }, res3.get(2).toArray(new Integer[0])); + } + + static class Solution { + + public List> shiftGrid(int[][] grid, int k) { + for (int i = 0; i < k; i++) { + shift(grid); + // System.out.println("grid = " + JSONUtil.toJsonPrettyStr(grid)); + } + List> res = new ArrayList<>(); + for (int i = 0; i < grid.length; i++) { + List list = new ArrayList<>(); + for (int j = 0; j < grid[0].length; j++) { + list.add(grid[i][j]); + } + res.add(list); + } + return res; + } + + public void shift(int[][] grid) { + int m = grid.length, n = grid[0].length; + int last = get(grid, m * n - 1); + for (int i = m * n - 1; i > 0; i--) { + int prev = get(grid, i - 1); + set(grid, i, prev); + } + set(grid, 0, last); + } + + public void set(int[][] grid, int index, int val) { + int m = grid.length, n = grid[0].length; + int i = index / n; + int j = index % n; + grid[i][j] = val; + } + + public int get(int[][] grid, int index) { + int m = grid.length, n = grid[0].length; + int i = index / n; + int j = index % n; + return grid[i][j]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" new file mode 100644 index 0000000..ce195a8 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" @@ -0,0 +1,37 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +/** + * 26. 删除有序数组中的重复项 + * + * @author Zhang Peng + * @since 2018-11-05 + */ +public class 删除排序数组中的重复项 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(2, s.removeDuplicates(new int[] { 1, 1, 2 })); + Assertions.assertEquals(5, s.removeDuplicates(new int[] { 0, 0, 1, 1, 1, 2, 2, 3, 3, 4 })); + Assertions.assertEquals(2, s.removeDuplicates(new int[] { 1, 2 })); + Assertions.assertEquals(1, s.removeDuplicates(new int[] { 2, 2 })); + } + + static class Solution { + + public int removeDuplicates(int[] nums) { + int slow = 0, fast = 1; + while (fast < nums.length) { + if (nums[fast] != nums[slow]) { + slow++; + nums[slow] = nums[fast]; + } + fast++; + } + return slow + 1; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\2712.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\2712.java" new file mode 100644 index 0000000..ad47707 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\2712.java" @@ -0,0 +1,45 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +/** + * 80. 删除有序数组中的重复项 II + * + * @author Zhang Peng + * @since 2018-11-05 + */ +public class 删除排序数组中的重复项2 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(5, s.removeDuplicates(new int[] { 1, 1, 1, 2, 2, 3 })); + Assertions.assertEquals(7, s.removeDuplicates(new int[] { 0, 0, 1, 1, 1, 1, 2, 3, 3 })); + } + + static class Solution { + + public int removeDuplicates(int[] nums) { + int slow = 0, fast = 1; + int cnt = 1; + while (fast < nums.length) { + if (nums[fast] != nums[slow]) { + cnt = 1; + slow++; + nums[slow] = nums[fast]; + } else { + if (cnt < 2) { + slow++; + nums[slow] = nums[fast]; + } + cnt++; + } + fast++; + } + // System.out.printf("slow: %d, fast: %d, nums: %s\n", slow, fast, + // JSONUtil.toJsonStr(ArrayUtil.sub(nums, 0, slow + 1))); + return slow + 1; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" new file mode 100644 index 0000000..75e2bc1 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" @@ -0,0 +1,39 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +/** + * 344. 反转字符串 + * + * @author Zhang Peng + * @since 2020-06-05 + */ +public class 反转字符串 { + + public static void main(String[] args) { + Solution s = new Solution(); + char[] arr1 = new char[] { 'h', 'e', 'l', 'l', 'o' }; + s.reverseString(arr1); + Assertions.assertArrayEquals(new char[] { 'o', 'l', 'l', 'e', 'h' }, arr1); + + char[] arr2 = new char[] { 'H', 'a', 'n', 'n', 'a', 'h' }; + s.reverseString(arr2); + Assertions.assertArrayEquals(new char[] { 'h', 'a', 'n', 'n', 'a', 'H' }, arr2); + } + + static class Solution { + + public void reverseString(char[] s) { + int left = 0, right = s.length - 1; + while (left < right) { + char temp = s[left]; + s[left] = s[right]; + s[right] = temp; + left++; + right--; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" new file mode 100644 index 0000000..7465ea6 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" @@ -0,0 +1,67 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +/** + * 88. 合并两个有序数组 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 合并两个有序数组 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + int[] nums1 = new int[] { 1, 2, 3, 0, 0, 0 }; + int[] nums2 = new int[] { 2, 5, 6 }; + s.merge(nums1, 3, nums2, 3); + Assertions.assertArrayEquals(new int[] { 1, 2, 2, 3, 5, 6 }, nums1); + + int[] nums3 = new int[] { 1 }; + int[] nums4 = new int[] {}; + s.merge(nums3, 1, nums4, 0); + Assertions.assertArrayEquals(new int[] { 1 }, nums3); + + int[] nums5 = new int[] { 0 }; + int[] nums6 = new int[] { 1 }; + s.merge(nums5, 0, nums6, 1); + Assertions.assertArrayEquals(new int[] { 1 }, nums5); + + int[] nums7 = new int[] { 4, 5, 6, 0, 0, 0 }; + int[] nums8 = new int[] { 1, 2, 3 }; + s.merge(nums7, 3, nums8, 3); + Assertions.assertArrayEquals(new int[] { 1, 2, 3, 4, 5, 6 }, nums7); + } + + static class Solution { + + public void merge(int[] nums1, int m, int[] nums2, int n) { + // 两个指针分别初始化在两个数组的最后一个元素(类似拉链两端的锯齿) + int i = m - 1, j = n - 1; + // 生成排序的结果(类似拉链的拉锁) + int p = nums1.length - 1; + // 从后向前生成结果数组,类似合并两个有序链表的逻辑 + while (i >= 0 && j >= 0) { + if (nums1[i] >= nums2[j]) { + nums1[p] = nums1[i]; + i--; + } else { + nums1[p] = nums2[j]; + j--; + } + p--; + } + // 可能其中一个数组的指针走到尽头了,而另一个还没走完 + while (i >= 0) { + nums1[p--] = nums1[i--]; + } + while (j >= 0) { + nums1[p--] = nums2[j--]; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" new file mode 100644 index 0000000..cabacab --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" @@ -0,0 +1,70 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.PriorityQueue; + +/** + * 1329. 将矩阵按对角线排序 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 将矩阵按对角线排序 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + int[][] input1 = { { 3, 3, 1, 1 }, { 2, 2, 1, 2 }, { 1, 1, 1, 2 } }; + int[][] expected1 = { { 1, 1, 1, 1 }, { 1, 2, 2, 2 }, { 1, 2, 3, 3 } }; + int[][] output1 = s.diagonalSort(input1); + Assertions.assertArrayEquals(expected1, output1); + + int[][] input2 = { { 11, 25, 66, 1, 69, 7 }, { 23, 55, 17, 45, 15, 52 }, { 75, 31, 36, 44, 58, 8 }, + { 22, 27, 33, 25, 68, 4 }, { 84, 28, 14, 11, 5, 50 } }; + int[][] expected2 = { { 5, 17, 4, 1, 52, 7 }, { 11, 11, 25, 45, 8, 69 }, { 14, 23, 25, 44, 58, 15 }, + { 22, 27, 31, 36, 50, 66 }, { 84, 28, 75, 33, 55, 68 } }; + int[][] output2 = s.diagonalSort(input2); + Assertions.assertArrayEquals(expected2, output2); + } + + static class Solution { + + public int[][] diagonalSort(int[][] mat) { + + int m = mat.length, n = mat[0].length; + + // 在同一个对角线上的元素,其横纵坐标之差是相同的 + // 存储所有对角线的元素列表,利用 PriorityQueue 自动对对角线元素排序 + Map> map = new HashMap<>(); + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + // 横纵坐标之差可以作为一条对角线的 ID + int diff = i - j; + if (!map.containsKey(diff)) { + map.put(diff, new PriorityQueue<>(Comparator.comparingInt(a -> mat[a[0]][a[1]]))); + } + map.get(diff).add(new int[] { i, j }); + } + } + + // 把排序结果回填二维矩阵 + int[][] res = new int[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + int diff = i - j; + PriorityQueue queue = map.get(diff); + int[] point = queue.poll(); + res[i][j] = mat[point[0]][point[1]]; + } + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" new file mode 100644 index 0000000..008fb47 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" @@ -0,0 +1,49 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +/** + * 14. 最长公共前缀 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 最长公共前缀 { + + public static void main(String[] args) { + + Solution s = new Solution(); + String[] input1 = { "flower", "flow", "flight" }; + String expect1 = "fl"; + String output1 = s.longestCommonPrefix(input1); + Assertions.assertEquals(expect1, output1); + + String[] input2 = { "dog", "racecar", "car" }; + String expect2 = ""; + String output2 = s.longestCommonPrefix(input2); + Assertions.assertEquals(expect2, output2); + } + + static class Solution { + + public String longestCommonPrefix(String[] strs) { + int m = strs.length; + // 以第一行的列数为基准 + int n = strs[0].length(); + for (int col = 0; col < n; col++) { + for (int row = 1; row < m; row++) { + String cur = strs[row], prev = strs[row - 1]; + // 判断每个字符串的 col 索引是否都相同 + if (col >= cur.length() || col >= prev.length() || + cur.charAt(col) != prev.charAt(col)) { + // 发现不匹配的字符,只有 strs[row][0..col-1] 是公共前缀 + return strs[row].substring(0, col); + } + } + } + return strs[0]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" new file mode 100644 index 0000000..44ca954 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" @@ -0,0 +1,84 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +/** + * 5. 最长回文子串 + * + * @author Zhang Peng + * @date 2025-11-10 + */ +public class 最长回文子串 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals("bab", s.longestPalindrome("babad")); + Assertions.assertEquals("bb", s.longestPalindrome("cbbd")); + Assertions.assertEquals("a", s.longestPalindrome("a")); + Assertions.assertEquals("bb", s.longestPalindrome("bb")); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals("bab", s2.longestPalindrome("babad")); + Assertions.assertEquals("bb", s2.longestPalindrome("cbbd")); + Assertions.assertEquals("a", s2.longestPalindrome("a")); + Assertions.assertEquals("bb", s2.longestPalindrome("bb")); + } + + /** + * 双指针判断回文串 + 暴力解决,时间复杂度 o(n^2) + */ + static class Solution { + + public String longestPalindrome(String s) { + String res = s.substring(0, 1); + for (int i = 0; i < s.length(); i++) { + for (int j = i + 1; j < s.length(); j++) { + if (isPalindrome(s, i, j)) { + int len = j - i + 1; + if (len > res.length()) { + res = s.substring(i, j + 1); + } + } + } + } + return res; + } + + public boolean isPalindrome(String s, int left, int right) { + while (left < right) { + if (s.charAt(left) != s.charAt(right)) { + return false; + } + left++; + right--; + } + return true; + } + + } + + static class Solution2 { + + public String longestPalindrome(String s) { + String res = ""; + for (int i = 0; i < s.length(); i++) { + String s1 = palindrome(s, i, i); + String s2 = palindrome(s, i, i + 1); + res = s1.length() > res.length() ? s1 : res; + res = s2.length() > res.length() ? s2 : res; + } + return res; + } + + public String palindrome(String s, int i, int j) { + if (i < 0 || j >= s.length() || i > j) return ""; + while (i >= 0 && j < s.length() && s.charAt(i) == s.charAt(j)) { + i--; + j++; + } + return s.substring(i + 1, j); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" new file mode 100644 index 0000000..e9324ca --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" @@ -0,0 +1,49 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +/** + * 977. 有序数组的平方 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 有序数组的平方 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + int[] input1 = { -4, -1, 0, 3, 10 }; + int[] expect1 = { 0, 1, 9, 16, 100 }; + int[] output1 = s.sortedSquares(input1); + Assertions.assertArrayEquals(expect1, output1); + + int[] input2 = { -7, -3, 2, 3, 11 }; + int[] expect2 = { 4, 9, 9, 49, 121 }; + int[] output2 = s.sortedSquares(input2); + Assertions.assertArrayEquals(expect2, output2); + } + + public static class Solution { + + public int[] sortedSquares(int[] nums) { + int p = nums.length - 1; + int i = 0, j = nums.length - 1; + int[] res = new int[nums.length]; + while (i <= j) { + if (Math.abs(nums[i]) > Math.abs(nums[j])) { + res[p] = nums[i] * nums[i]; + i++; + } else { + res[p] = nums[j] * nums[j]; + j--; + } + p--; + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" new file mode 100644 index 0000000..626bd5b --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" @@ -0,0 +1,39 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashSet; +import java.util.Set; + +/** + * LCR 179. 查找总价格为目标值的两个商品 + * + * @author Zhang Peng + * @since 2020-06-05 + */ +public class 查找总价格为目标值的两个商品 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new int[] { 3, 15 }, s.twoSum(new int[] { 3, 9, 12, 15 }, 18)); + Assertions.assertArrayEquals(new int[] { 27, 34 }, s.twoSum(new int[] { 8, 21, 27, 34, 52, 66 }, 61)); + } + + static class Solution { + + public int[] twoSum(int[] nums, int target) { + Set set = new HashSet<>(); + for (int num : nums) { + int diff = target - num; + if (set.contains(diff)) { + return new int[] { num, diff }; + } else { + set.add(num); + } + } + return new int[0]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\347\247\273\345\212\250\351\233\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\347\247\273\345\212\250\351\233\266.java" new file mode 100644 index 0000000..b682999 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\347\247\273\345\212\250\351\233\266.java" @@ -0,0 +1,50 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +/** + * 283. 移动零 + * + * @author Zhang Peng + * @since 2018-11-05 + */ +public class 移动零 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + int[] arr1 = { 0, 1, 0, 3, 12 }; + s.moveZeroes(arr1); + Assertions.assertArrayEquals(new int[] { 1, 3, 12, 0, 0 }, arr1); + + int[] arr2 = { 0, 0, 1 }; + s.moveZeroes(arr2); + Assertions.assertArrayEquals(new int[] { 1, 0, 0 }, arr2); + + int[] arr3 = { 0 }; + s.moveZeroes(arr3); + Assertions.assertArrayEquals(new int[] { 0 }, arr3); + } + + public static class Solution { + + public void moveZeroes(int[] nums) { + // slow 指针维护所有不为 0 的元素 + int slow = 0, fast = 0; + while (fast < nums.length) { + if (nums[fast] != 0) { + nums[slow] = nums[fast]; + slow++; + } + fast++; + } + // 后续补零 + for (int i = slow; i < nums.length; i++) { + nums[i] = 0; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\347\247\273\351\231\244\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\347\247\273\351\231\244\345\205\203\347\264\240.java" new file mode 100644 index 0000000..52992a1 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\347\247\273\351\231\244\345\205\203\347\264\240.java" @@ -0,0 +1,43 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +/** + * 27. 移除元素 + * + * @author Zhang Peng + * @since 2018-11-05 + */ +public class 移除元素 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + int[] arr1 = { 3, 2, 2, 3 }; + Assertions.assertEquals(2, s.removeElement(arr1, 3)); + + int[] arr2 = { 0, 1, 2, 2, 3, 0, 4, 2 }; + Assertions.assertEquals(5, s.removeElement(arr2, 2)); + + int[] arr3 = { 1 }; + Assertions.assertEquals(0, s.removeElement(arr3, 1)); + } + + static class Solution { + + public int removeElement(int[] nums, int val) { + int slow = 0, fast = 0; + while (fast < nums.length) { + if (nums[fast] != val) { + nums[slow] = nums[fast]; + slow++; + } + fast++; + } + return slow; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\350\275\254\347\275\256\347\237\251\351\230\265.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\350\275\254\347\275\256\347\237\251\351\230\265.java" new file mode 100644 index 0000000..92104fe --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\350\275\254\347\275\256\347\237\251\351\230\265.java" @@ -0,0 +1,41 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +/** + * 1329. 将矩阵按对角线排序 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 转置矩阵 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[][] input1 = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + int[][] expect1 = { { 1, 4, 7 }, { 2, 5, 8 }, { 3, 6, 9 } }; + int[][] output1 = s.transpose(input1); + Assertions.assertArrayEquals(expect1, output1); + + int[][] input2 = { { 1, 2, 3 }, { 4, 5, 6 } }; + int[][] expect2 = { { 1, 4 }, { 2, 5 }, { 3, 6 } }; + int[][] output2 = s.transpose(input2); + Assertions.assertArrayEquals(expect2, output2); + } + + public static class Solution { + + public int[][] transpose(int[][] matrix) { + int m = matrix.length, n = matrix[0].length; + int[][] res = new int[n][m]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + res[j][i] = matrix[i][j]; + } + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\351\242\234\350\211\262\345\210\206\347\261\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\351\242\234\350\211\262\345\210\206\347\261\273.java" new file mode 100644 index 0000000..d8d6d83 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\351\242\234\350\211\262\345\210\206\347\261\273.java" @@ -0,0 +1,53 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import cn.hutool.json.JSONUtil; +import org.junit.jupiter.api.Assertions; + +/** + * 75. 颜色分类 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 颜色分类 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + int[] nums1 = { 2, 0, 2, 1, 1, 0 }; + s.sortColors(nums1); + Assertions.assertArrayEquals(new int[] { 0, 0, 1, 1, 2, 2 }, nums1); + + int[] nums2 = { 2, 0, 1 }; + s.sortColors(nums2); + Assertions.assertArrayEquals(new int[] { 0, 1, 2 }, nums2); + } + + static class Solution { + + public void sortColors(int[] nums) { + moveToTail(nums, 1); + System.out.println("nums = " + JSONUtil.toJsonStr(nums)); + moveToTail(nums, 2); + System.out.println("nums = " + JSONUtil.toJsonStr(nums)); + } + + public void moveToTail(int[] nums, int val) { + if (nums == null || nums.length == 0) { return; } + int slow = 0, fast = 0; + while (fast < nums.length) { + if (nums[fast] != val) { + nums[slow] = nums[fast]; + slow++; + } + fast++; + } + for (int i = slow; i < nums.length; i++) { + nums[i] = val; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" new file mode 100644 index 0000000..4c1597e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" @@ -0,0 +1,74 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +/** + * 125. 验证回文串 + * + * @author Zhang Peng + * @since 2025-08-06 + */ +public class 验证回文串 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.isPalindrome("A man, a plan, a canal: Panama")); + Assertions.assertFalse(s.isPalindrome("race a car")); + Assertions.assertTrue(s.isPalindrome(" ")); + Assertions.assertTrue(s.isPalindrome("ab_a")); + + Solution2 s2 = new Solution2(); + Assertions.assertTrue(s2.isPalindrome("A man, a plan, a canal: Panama")); + Assertions.assertFalse(s2.isPalindrome("race a car")); + Assertions.assertTrue(s2.isPalindrome(" ")); + Assertions.assertTrue(s2.isPalindrome("ab_a")); + } + + static class Solution { + + public boolean isPalindrome(String s) { + String format = s.replaceAll("[^a-zA-Z0-9]", "").toLowerCase(); + return isPalindrome(format, 0, format.length() - 1); + } + + public boolean isPalindrome(String s, int left, int right) { + while (left < right) { + if (s.charAt(left) != s.charAt(right)) { + return false; + } + left++; + right--; + } + return true; + } + + } + + static class Solution2 { + + public boolean isPalindrome(String s) { + int left = 0, right = s.length() - 1; + while (left < right) { + if (!Character.isLetterOrDigit(s.charAt(left))) { + left++; + continue; + } + if (!Character.isLetterOrDigit(s.charAt(right))) { + right--; + continue; + } + + char l = Character.toLowerCase(s.charAt(left)); + char r = Character.toLowerCase(s.charAt(right)); + if (l != r) { + return false; + } + left++; + right--; + } + return true; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" index c7b51f3..22f6ea9 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" @@ -3,6 +3,7 @@ import org.junit.jupiter.api.Assertions; import java.util.HashMap; +import java.util.Map; /** * 567. 字符串的排列 @@ -13,63 +14,46 @@ public class 字符串的排列 { public static void main(String[] args) { - Assertions.assertTrue(checkInclusion("ab", "eidbaooo")); - Assertions.assertFalse(checkInclusion("ab", "eidboaoo")); + Solution s = new Solution(); + Assertions.assertTrue(s.checkInclusion("ab", "eidbaooo")); + Assertions.assertFalse(s.checkInclusion("ab", "eidboaoo")); } - public static boolean checkInclusion(String s1, String s2) { - - // 定义 need 和 window - HashMap need = new HashMap<>(); - HashMap window = new HashMap<>(); - for (int i = 0; i < s1.length(); i++) { - need.put(s1.charAt(i), need.getOrDefault(s1.charAt(i), 0) + 1); - } - - // 符合 need 排列的字符个数 - int valid = 0; - // 扫描 s 的窗口游标 - int left = 0, right = 0; - // 符合要求的子串窗口信息 - int start = 0, len = Integer.MAX_VALUE; - while (right < s2.length()) { - char r = s2.charAt(right); - // 窗口扩展 - right++; - // 窗口 window 满足 need 的一系列更新 - if (need.containsKey(r)) { - window.put(r, window.getOrDefault(r, 0) + 1); - if (window.get(r).equals(need.get(r))) { - valid++; - } - } - - // 判断窗口左边界是否收缩 - while (valid == need.size()) { - // 更新最小窗口信息 - if (right - left < len) { - start = left; - len = right - left; - System.out.format("窗口:[left: %s, right: %s), 子串:%s\n", left, right, - s2.substring(start, right)); - if (len == s1.length()) { - return true; - } + static class Solution { + + public boolean checkInclusion(String t, String s) { + Map need = new HashMap<>(); + Map window = new HashMap<>(); + for (char c : t.toCharArray()) need.put(c, need.getOrDefault(c, 0) + 1); + + int left = 0, right = 0; + int valid = 0; + while (right < s.length()) { + char c = s.charAt(right); + right++; + // 进行窗口内数据的一系列更新 + if (need.containsKey(c)) { + window.put(c, window.getOrDefault(c, 0) + 1); + if (window.get(c).equals(need.get(c))) { valid++; } } - // 窗口左边界收缩 - char l = s2.charAt(left); - left++; - if (need.containsKey(l)) { - if (window.get(l).equals(need.get(l))) { - valid--; + // 判断左侧窗口是否要收缩 + while (right - left >= t.length()) { + // 在这里判断是否找到了合法的子串 + if (valid == need.size()) { return true; } + char d = s.charAt(left); + left++; + // 进行窗口内数据的一系列更新 + if (need.containsKey(d)) { + if (window.get(d).equals(need.get(d))) { valid--; } + window.put(d, window.get(d) - 1); } - window.put(l, window.get(l) - 1); } } + // 未找到符合条件的子串 + return false; } - return false; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" index 1763320..ebf048c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" @@ -11,35 +11,47 @@ public class 将x减到0的最小操作数 { public static void main(String[] args) { - Assertions.assertEquals(2, minOperations(new int[] { 1, 1, 4, 2, 3 }, 5)); - Assertions.assertEquals(-1, minOperations(new int[] { 5, 6, 7, 8, 9 }, 4)); - Assertions.assertEquals(5, minOperations(new int[] { 3, 2, 20, 1, 1, 3 }, 10)); + Solution s = new Solution(); + Assertions.assertEquals(2, s.minOperations(new int[] { 1, 1, 4, 2, 3 }, 5)); + Assertions.assertEquals(-1, s.minOperations(new int[] { 5, 6, 7, 8, 9 }, 4)); + Assertions.assertEquals(5, s.minOperations(new int[] { 3, 2, 20, 1, 1, 3 }, 10)); } - public static int minOperations(int[] nums, int x) { - int sum = 0; - for (int num : nums) { - sum += num; - } - int target = sum - x; - int windowSum = 0; - int maxLen = Integer.MIN_VALUE; - int left = 0, right = 0; - - while (right < nums.length) { - windowSum += nums[right]; - right++; - - while (windowSum > target && left < right) { - windowSum -= nums[left]; - left++; - } + static class Solution { - if (windowSum == target) { - maxLen = Math.max(maxLen, right - left); + public int minOperations(int[] nums, int x) { + int n = nums.length, sum = 0; + for (int num : nums) { + sum += num; } + // 滑动窗口需要寻找的子数组目标和 + int target = sum - x; + + int left = 0, right = 0; + // 记录窗口内所有元素和 + int windowSum = 0; + // 记录目标子数组的最大长度 + int maxLen = Integer.MIN_VALUE; + // 开始执行滑动窗口框架 + while (right < nums.length) { + // 扩大窗口 + windowSum += nums[right]; + right++; + + while (windowSum > target && left < right) { + // 缩小窗口 + windowSum -= nums[left]; + left++; + } + // 寻找目标子数组 + if (windowSum == target) { + maxLen = Math.max(maxLen, right - left); + } + } + // 目标子数组的最大长度可以推导出需要删除的字符数量 + return maxLen == Integer.MIN_VALUE ? -1 : n - maxLen; } - return maxLen == Integer.MIN_VALUE ? -1 : nums.length - maxLen; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" index efa3b6a..2a6bb20 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; /** * 438. 找到字符串中所有字母异位词 @@ -15,56 +16,54 @@ public class 找到字符串中所有字母异位词 { public static void main(String[] args) { - Assertions.assertArrayEquals(new Integer[] { 0, 6 }, findAnagrams("cbaebabacd", "abc").toArray()); - Assertions.assertArrayEquals(new Integer[] { 0, 1, 2 }, findAnagrams("abab", "ab").toArray()); + Solution s = new Solution(); + Assertions.assertArrayEquals(new Integer[] { 0, 6 }, s.findAnagrams("cbaebabacd", "abc").toArray()); + Assertions.assertArrayEquals(new Integer[] { 0, 1, 2 }, s.findAnagrams("abab", "ab").toArray()); } - public static List findAnagrams(String s, String p) { - // 定义窗口:条件窗口、临时窗口 - HashMap need = new HashMap<>(p.length()); - HashMap window = new HashMap<>(p.length()); - for (char c : p.toCharArray()) { - need.put(c, need.getOrDefault(c, 0) + 1); - } - - // 符合条件字符数 - int valid = 0; - // 窗口边界 - int left = 0, right = 0; - // 符合条件的子串起始位置(长度固定,和 p 相等) - List res = new ArrayList<>(); + static class Solution { - while (right < s.length()) { - char r = s.charAt(right); - // 窗口扩展 - right++; - if (need.containsKey(r)) { - window.put(r, window.getOrDefault(r, 0) + 1); - if (window.get(r).equals(need.get(r))) { - valid++; - } + public List findAnagrams(String s, String t) { + Map need = new HashMap<>(); + Map window = new HashMap<>(); + for (char c : t.toCharArray()) { + need.put(c, need.getOrDefault(c, 0) + 1); } - while (valid == need.size()) { - // 更新信息 - if (right - left == p.length()) { - // System.out.format("窗口:[left: %s, right: %s), 子串:%s\n", - // left, right, s.substring(left, left + p.length())); - res.add(left); + int left = 0, right = 0; + int valid = 0; + // 记录结果 + List res = new ArrayList<>(); + while (right < s.length()) { + char c = s.charAt(right); + right++; + // 进行窗口内数据的一系列更新 + if (need.containsKey(c)) { + window.put(c, window.getOrDefault(c, 0) + 1); + if (window.get(c).equals(need.get(c))) { + valid++; + } } - - char l = s.charAt(left); - // 窗口收缩 - left++; - if (need.containsKey(l)) { - if (window.get(l).equals(need.get(l))) { - valid--; + // 判断左侧窗口是否要收缩 + while (right - left >= t.length()) { + // 当窗口符合条件时,把起始索引加入 res + if (valid == need.size()) { + res.add(left); + } + char d = s.charAt(left); + left++; + // 进行窗口内数据的一系列更新 + if (need.containsKey(d)) { + if (window.get(d).equals(need.get(d))) { + valid--; + } + window.put(d, window.get(d) - 1); } - window.put(l, window.get(l) - 1); } } + return res; } - return res; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" index ab45d37..52f0955 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" @@ -2,7 +2,8 @@ import org.junit.jupiter.api.Assertions; -import java.util.HashSet; +import java.util.HashMap; +import java.util.Map; /** * 3. 无重复字符的最长子串 @@ -13,44 +14,39 @@ public class 无重复字符的最长子串 { public static void main(String[] args) { - Assertions.assertEquals(3, lengthOfLongestSubstring("abcabcbb")); - Assertions.assertEquals(1, lengthOfLongestSubstring("bbbbb")); - Assertions.assertEquals(3, lengthOfLongestSubstring("pwwkew")); - Assertions.assertEquals(2, lengthOfLongestSubstring("aab")); + Solution s = new Solution(); + Assertions.assertEquals(3, s.lengthOfLongestSubstring("abcabcbb")); + Assertions.assertEquals(1, s.lengthOfLongestSubstring("bbbbb")); + Assertions.assertEquals(3, s.lengthOfLongestSubstring("pwwkew")); + Assertions.assertEquals(2, s.lengthOfLongestSubstring("aab")); } - public static int lengthOfLongestSubstring(String s) { - // 【debug】 - System.out.println("============> 原始字符串:" + s); - // 定义窗口 - HashSet window = new HashSet<>(); - // 窗口边界 - int left = 0, right = 0; - int max = 0; - - while (right < s.length()) { - char r = s.charAt(right); - // 扩大边界 - right++; - if (window.contains(r)) { - while (r != s.charAt(left)) { - char l = s.charAt(left); - window.remove(l); + static class Solution { + + public int lengthOfLongestSubstring(String s) { + Map window = new HashMap<>(); + + int left = 0, right = 0; + // 记录结果 + int res = 0; + while (right < s.length()) { + char c = s.charAt(right); + right++; + // 进行窗口内数据的一系列更新 + window.put(c, window.getOrDefault(c, 0) + 1); + // 判断左侧窗口是否要收缩 + while (window.get(c) > 1) { + char d = s.charAt(left); left++; + // 进行窗口内数据的一系列更新 + window.put(d, window.get(d) - 1); } - char l = s.charAt(left); - left++; - } else { - window.add(r); - if (window.size() > max) { - // 【debug】 - System.out.format("首个最大不重复子串:%s, Offset: [%d, %d)\n", - s.substring(left, right), left, right); - max = window.size(); - } + // 在这里更新答案 + res = Math.max(res, right - left); } + return res; } - return max; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" index ea03017..1f2eb58 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Assertions; import java.util.HashMap; +import java.util.Map; /** * 76. 最小覆盖子串 @@ -15,51 +16,60 @@ public class 最小覆盖子串 { public static void main(String[] args) { - Assertions.assertEquals("BANC", minWindow("ADOBECODEBANC", "ABC")); - Assertions.assertEquals("a", minWindow("a", "a")); - Assertions.assertEquals("", minWindow("a", "aa")); + Solution s = new Solution(); + Assertions.assertEquals("BANC", s.minWindow("ADOBECODEBANC", "ABC")); + Assertions.assertEquals("a", s.minWindow("a", "a")); + Assertions.assertEquals("", s.minWindow("a", "aa")); } - public static String minWindow(String s, String t) { - HashMap window = new HashMap<>(); - HashMap need = new HashMap<>(); - for (int i = 0; i < t.length(); i++) { - need.put(t.charAt(i), need.getOrDefault(t.charAt(i), 0) + 1); - } + static class Solution { - int valid = 0; - int start = 0, len = Integer.MAX_VALUE; - int left = 0, right = 0; - while (right < s.length()) { - char r = s.charAt(right); - // 扩大窗口:右边界右移 - right++; - // 窗口 window 满足 need 的一系列更新 - if (need.containsKey(r)) { - window.put(r, window.getOrDefault(r, 0) + 1); - if (window.get(r).equals(need.get(r))) { - valid++; - } + public String minWindow(String s, String t) { + Map need = new HashMap<>(); + Map window = new HashMap<>(); + for (char c : t.toCharArray()) { + need.put(c, need.getOrDefault(c, 0) + 1); } - // 判断左侧窗口是否要收缩 - while (valid == need.size()) { - if (right - left < len) { - start = left; - len = right - left; - System.out.format("窗口:[left: %s, right: %s), 子串:%s\n", left, right, - s.substring(start, right)); + int left = 0, right = 0; + + int valid = 0; + // 记录最小覆盖子串的起始索引及长度 + int start = 0, len = Integer.MAX_VALUE; + while (right < s.length()) { + // c 是将移入窗口的字符 + char c = s.charAt(right); + // 扩大窗口 + right++; + // 进行窗口内数据的一系列更新 + if (need.containsKey(c)) { + window.put(c, window.getOrDefault(c, 0) + 1); + if (window.get(c).equals(need.get(c))) { valid++; } } - char l = s.charAt(left); - // 缩小窗口:左边界右移 - left++; - if (need.containsKey(l)) { - if (window.get(l).equals(need.get(l))) valid--; - window.put(l, window.get(l) - 1); + + // 判断左侧窗口是否要收缩 + while (valid == need.size()) { + + // 在这里更新最小覆盖子串 + if (right - left < len) { + start = left; + len = right - left; + } + // d 是将移出窗口的字符 + char d = s.charAt(left); + // 缩小窗口 + left++; + // 进行窗口内数据的一系列更新 + if (need.containsKey(d)) { + if (window.get(d).equals(need.get(d))) { valid--; } + window.put(d, window.get(d) - 1); + } } } + // 返回最小覆盖子串 + return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len); } - return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len); + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214.java" deleted file mode 100644 index e20ac30..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214.java" +++ /dev/null @@ -1,56 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; - -/** - * 1. 两数之和 - * - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 两数之和 { - - public static void main(String[] args) { - Assertions.assertArrayEquals(new int[] { 0, 1 }, twoSumInSorted(new int[] { 2, 7, 11, 15 }, 9)); - Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSumInSorted(new int[] { 3, 2, 4 }, 6)); - Assertions.assertArrayEquals(new int[] { 0, 1 }, twoSumInSorted(new int[] { 3, 3 }, 6)); - - Assertions.assertArrayEquals(new int[] { 0, 1 }, twoSumInSorted2(new int[] { 2, 7, 11, 15 }, 9)); - Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSumInSorted2(new int[] { 3, 2, 4 }, 6)); - Assertions.assertArrayEquals(new int[] { 0, 1 }, twoSumInSorted2(new int[] { 3, 3 }, 6)); - } - - /** - * 时间复杂度:O(n^2) - */ - public static int[] twoSumInSorted(int[] nums, int target) { - for (int left = 0; left < nums.length; left++) { - for (int right = left + 1; right < nums.length; right++) { - if (nums[left] + nums[right] == target) { - return new int[] { left, right }; - } - } - } - return new int[] {}; - } - - /** - * 时间复杂度:O(n) - */ - public static int[] twoSumInSorted2(int[] nums, int target) { - Map map = new HashMap<>(nums.length); - for (int i = 0; i < nums.length; i++) { - int diff = target - nums[i]; - if (map.containsKey(diff)) { - return new int[] { map.get(diff), i }; - } else { - map.put(nums[i], i); - } - } - return new int[] {}; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II.java" deleted file mode 100644 index 4a1b96f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II.java" +++ /dev/null @@ -1,79 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; - -/** - * 167. 两数之和 II - 输入有序数组 - * - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 两数之和II { - - public static void main(String[] args) { - Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSum(new int[] { 2, 7, 11, 15 }, 9)); - Assertions.assertArrayEquals(new int[] { 1, 3 }, twoSum(new int[] { 2, 3, 4 }, 6)); - Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSum(new int[] { -1, 0 }, -1)); - - Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSum2(new int[] { 2, 7, 11, 15 }, 9)); - Assertions.assertArrayEquals(new int[] { 1, 3 }, twoSum2(new int[] { 2, 3, 4 }, 6)); - Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSum2(new int[] { -1, 0 }, -1)); - - Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSum3(new int[] { 2, 7, 11, 15 }, 9)); - Assertions.assertArrayEquals(new int[] { 1, 3 }, twoSum3(new int[] { 2, 3, 4 }, 6)); - Assertions.assertArrayEquals(new int[] { 1, 2 }, twoSum3(new int[] { -1, 0 }, -1)); - } - - /** - * 时间复杂度:O(logn) - */ - public static int[] twoSum(int[] numbers, int target) { - int left = 0, right = numbers.length - 1; - while (left < right) { - int sum = numbers[left] + numbers[right]; - if (sum == target) { - return new int[] { left + 1, right + 1 }; - } else if (sum < target) { - left++; - } else { - right--; - } - } - return new int[] {}; - } - - /** - * 时间复杂度:O(n) - */ - public static int[] twoSum2(int[] numbers, int target) { - int len = numbers.length; - Map map = new HashMap<>(len); - for (int i = 0; i < len; i++) { - int diff = target - numbers[i]; - if (map.containsKey(diff)) { - return new int[] { map.get(diff) + 1, i + 1 }; - } else { - map.put(numbers[i], i); - } - } - return new int[] {}; - } - - /** - * 时间复杂度:O(n^2) - */ - public static int[] twoSum3(int[] numbers, int target) { - for (int left = 0; left < numbers.length; left++) { - for (int right = left + 1; right < numbers.length; right++) { - if (numbers[left] + numbers[right] == target) { - return new int[] { left + 1, right + 1 }; - } - } - } - return new int[] {}; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\346\225\260\347\273\204.java" deleted file mode 100644 index 5bd729c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\346\225\260\347\273\204.java" +++ /dev/null @@ -1,34 +0,0 @@ -package io.github.dunwu.algorithm.array; - -/** - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 二维数组 { - - public static void main(String[] args) { - System.out.println("Example I:"); - int[][] a = new int[2][5]; - printArray(a); - System.out.println("Example II:"); - int[][] b = new int[2][]; - printArray(b); - System.out.println("Example III:"); - b[0] = new int[3]; - b[1] = new int[5]; - printArray(b); - } - - private static void printArray(int[][] a) { - for (int i = 0; i < a.length; ++i) { - System.out.println(a[i]); - } - for (int i = 0; i < a.length; ++i) { - for (int j = 0; a[i] != null && j < a[i].length; ++j) { - System.out.print(a[i][j] + " "); - } - System.out.println(); - } - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" deleted file mode 100644 index 8cdcb07..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" +++ /dev/null @@ -1,97 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.List; - -/** - * @author Zhang Peng - * @date 2025-10-14 - */ -public class 二维网格迁移 { - // 给你一个 m 行 n 列的二维网格 grid 和一个整数 k。你需要将 grid 迁移 k 次。 - // - // 每次「迁移」操作将会引发下述活动: - // - // 位于 grid[i][j](j < n - 1)的元素将会移动到 grid[i][j + 1]。 - // 位于 grid[i][n - 1] 的元素将会移动到 grid[i + 1][0]。 - // 位于 grid[m - 1][n - 1] 的元素将会移动到 grid[0][0]。 - // 请你返回 k 次迁移操作后最终得到的 二维网格。 - - // 输入:grid = {{1,2,3},{4,5,6},{7,8,9}}, k = 1 - // 输出:{{9,1,2},{3,4,5},{6,7,8}} - // - // - // 输入:grid = {{3,8,1,9},{19,7,2,5},{4,6,11,10},{12,0,21,13}}, k = 4 - // 输出:{{12,0,21,13},{3,8,1,9},{19,7,2,5},{4,6,11,10}} - // - // 输入:grid = {{1,2,3},{4,5,6},{7,8,9}}, k = 9 - // 输出:{{1,2,3},{4,5,6},{7,8,9}} - - public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { - int[][] grid1 = new int[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; - List> res1 = shiftGrid(grid1, 1); - Assertions.assertNotNull(res1); - Assertions.assertArrayEquals(new Integer[] { 9, 1, 2 }, res1.get(0).toArray(new Integer[0])); - Assertions.assertArrayEquals(new Integer[] { 3, 4, 5 }, res1.get(1).toArray(new Integer[0])); - Assertions.assertArrayEquals(new Integer[] { 6, 7, 8 }, res1.get(2).toArray(new Integer[0])); - - int[][] grid2 = new int[][] { { 3, 8, 1, 9 }, { 19, 7, 2, 5 }, { 4, 6, 11, 10 }, { 12, 0, 21, 13 } }; - List> res2 = shiftGrid(grid2, 4); - Assertions.assertNotNull(res2); - Assertions.assertArrayEquals(new Integer[] { 12, 0, 21, 13 }, res2.get(0).toArray(new Integer[0])); - Assertions.assertArrayEquals(new Integer[] { 3, 8, 1, 9 }, res2.get(1).toArray(new Integer[0])); - Assertions.assertArrayEquals(new Integer[] { 19, 7, 2, 5 }, res2.get(2).toArray(new Integer[0])); - Assertions.assertArrayEquals(new Integer[] { 4, 6, 11, 10 }, res2.get(3).toArray(new Integer[0])); - - int[][] grid3 = new int[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; - List> res3 = shiftGrid(grid3, 9); - Assertions.assertNotNull(res3); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, res3.get(0).toArray(new Integer[0])); - Assertions.assertArrayEquals(new Integer[] { 4, 5, 6 }, res3.get(1).toArray(new Integer[0])); - Assertions.assertArrayEquals(new Integer[] { 7, 8, 9 }, res3.get(2).toArray(new Integer[0])); - } - - /** - * 低效方法 - */ - public static List> shiftGrid(int[][] grid, int k) { - int M = grid.length, N = grid[0].length; - k = k % (M * N); - List> listlist = new ArrayList<>(); - for (int i = 0; i < k; i++) { - shift(grid); - } - for (int[] array : grid) { - ArrayList list = new ArrayList<>(); - for (int val : array) { - list.add(val); - } - listlist.add(list); - } - return listlist; - } - - public static void shift(int[][] grid) { - int M = grid.length, N = grid[0].length; - int[][] shift = new int[M][N]; - for (int i = M - 1; i >= 0; i--) { - for (int j = N - 1; j >= 0; j--) { - int val = grid[i][j]; - if (i == M - 1 && j == N - 1) { - shift[0][0] = val; - } else if (j == N - 1) { - shift[i + 1][0] = val; - } else if (j < N - 1) { - shift[i][j + 1] = val; - } - } - } - for (int i = M - 1; i >= 0; i--) { - System.arraycopy(shift[i], 0, grid[i], 0, N - 1 + 1); - } - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" deleted file mode 100644 index 7c504b5..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 26. 删除有序数组中的重复项 - * - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 删除排序数组中的重复项 { - - public static void main(String[] args) { - int[] nums1 = { 1, 1, 2 }; - Assertions.assertEquals(2, removeDuplicates(nums1)); - - int[] nums2 = { 0, 0, 1, 1, 1, 2, 2, 3, 3, 4 }; - Assertions.assertEquals(5, removeDuplicates(nums2)); - - int[] nums3 = { 1, 2 }; - Assertions.assertEquals(2, removeDuplicates(nums3)); - - int[] nums4 = { 2, 2 }; - Assertions.assertEquals(1, removeDuplicates(nums4)); - } - - public static int removeDuplicates(int[] nums) { - if (nums == null || nums.length == 0) return 0; - if (nums.length == 1) return 1; - int slow = 0, fast = 1; - while (fast < nums.length) { - if (nums[slow] != nums[fast]) { - slow++; - nums[slow] = nums[fast]; - } - fast++; - } - return slow + 1; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271II.java" deleted file mode 100644 index 964ee51..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271II.java" +++ /dev/null @@ -1,43 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 26. 删除有序数组中的重复项 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 删除排序数组中的重复项II { - - public static void main(String[] args) { - int[] nums1 = { 1, 1, 1, 2, 2, 3 }; - Assertions.assertEquals(5, removeDuplicates(nums1)); - - int[] nums2 = { 0, 0, 1, 1, 1, 1, 2, 3, 3 }; - Assertions.assertEquals(7, removeDuplicates(nums2)); - } - - public static int removeDuplicates(int[] nums) { - if (nums == null || nums.length == 0) return 0; - if (nums.length == 1) return 1; - int slow = 0, fast = 1; - int count = 0; - while (fast < nums.length) { - if (nums[slow] != nums[fast]) { - slow++; - nums[slow] = nums[fast]; - count = 0; - } else { - if (count == 0) { - slow++; - nums[slow] = nums[fast]; - count++; - } - } - fast++; - } - return slow + 1; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" deleted file mode 100644 index 33114c6..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" +++ /dev/null @@ -1,34 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 344. 反转字符串 - * - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 反转字符串 { - - public static void main(String[] args) { - char[] s1 = new char[] { 'h', 'e', 'l', 'l', 'o' }; - reverseString(s1); - Assertions.assertArrayEquals(new char[] { 'o', 'l', 'l', 'e', 'h' }, s1); - - char[] s2 = new char[] { 'H', 'a', 'n', 'n', 'a', 'h' }; - reverseString(s2); - Assertions.assertArrayEquals(new char[] { 'h', 'a', 'n', 'n', 'a', 'H' }, s2); - } - - public static void reverseString(char[] s) { - int left = 0, right = s.length - 1; - while (left < right) { - char temp = s[left]; - s[left] = s[right]; - s[right] = temp; - left++; - right--; - } - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" deleted file mode 100644 index f6b1cd9..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" +++ /dev/null @@ -1,66 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import cn.hutool.core.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -import java.lang.reflect.InvocationTargetException; - -/** - * 88. 合并两个有序数组 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 合并两个有序数组 { - - public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { - int[] nums1 = new int[] { 1, 2, 3, 0, 0, 0 }; - int[] nums2 = new int[] { 2, 5, 6 }; - merge(nums1, 3, nums2, 3); - Assertions.assertTrue(ArrayUtil.equals(new int[] { 1, 2, 2, 3, 5, 6 }, nums1)); - - int[] nums3 = new int[] { 1 }; - int[] nums4 = new int[] {}; - merge(nums3, 1, nums4, 0); - Assertions.assertTrue(ArrayUtil.equals(new int[] { 1 }, nums3)); - - int[] nums5 = new int[] { 0 }; - int[] nums6 = new int[] { 1 }; - merge(nums5, 0, nums6, 1); - Assertions.assertTrue(ArrayUtil.equals(new int[] { 1 }, nums5)); - } - - public static void merge(int[] nums1, int m, int[] nums2, int n) { - int i = m - 1, j = n - 1; - int p = m + n - 1; - while (i >= 0 && j >= 0) { - if (nums1[i] > nums2[j]) { - nums1[p--] = nums1[i--]; - } else { - nums1[p--] = nums2[j--]; - } - } - while (j >= 0) { - nums1[p--] = nums2[j--]; - } - } - - public static void merge2(int[] nums1, int m, int[] nums2, int n) { - // 两个指针分别初始化在两个数组的最后一个元素(类似拉链两端的锯齿) - int i = m - 1, j = n - 1; - // 生成排序的结果(类似拉链的拉锁) - int p = nums1.length - 1; - // 从后向前生成结果数组,类似合并两个有序链表的逻辑 - while (i >= 0 && j >= 0) { - if (nums1[i] > nums2[j]) { - nums1[p--] = nums1[i--]; - } else { - nums1[p--] = nums2[j--]; - } - } - while (j >= 0) { - nums1[p--] = nums2[j--]; - } - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" deleted file mode 100644 index 36f8db9..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" +++ /dev/null @@ -1,56 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.PriorityQueue; - -/** - * 1329. 将矩阵按对角线排序 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 将矩阵按对角线排序 { - - public static void main(String[] args) { - int[][] input1 = { { 3, 3, 1, 1 }, { 2, 2, 1, 2 }, { 1, 1, 1, 2 } }; - int[][] expected1 = { { 1, 1, 1, 1 }, { 1, 2, 2, 2 }, { 1, 2, 3, 3 } }; - int[][] output1 = diagonalSort(input1); - Assertions.assertArrayEquals(expected1, output1); - - int[][] input2 = { { 11, 25, 66, 1, 69, 7 }, { 23, 55, 17, 45, 15, 52 }, { 75, 31, 36, 44, 58, 8 }, - { 22, 27, 33, 25, 68, 4 }, { 84, 28, 14, 11, 5, 50 } }; - int[][] expected2 = { { 5, 17, 4, 1, 52, 7 }, { 11, 11, 25, 45, 8, 69 }, { 14, 23, 25, 44, 58, 15 }, - { 22, 27, 31, 36, 50, 66 }, { 84, 28, 75, 33, 55, 68 } }; - int[][] output2 = diagonalSort(input2); - Assertions.assertArrayEquals(expected2, output2); - } - - public static int[][] diagonalSort(int[][] mat) { - int R = mat.length, C = mat[0].length; - - // 存储所有对角线的元素列表 - HashMap> map = new HashMap<>(); - - for (int i = 0; i < R; i++) { - for (int j = 0; j < C; j++) { - // 横纵坐标之差可以作为一条对角线的 ID - int diff = i - j; - map.putIfAbsent(diff, new PriorityQueue<>((a, b) -> a - b)); - map.get(diff).offer(mat[i][j]); - } - } - - // 把排序结果回填二维矩阵 - for (int i = 0; i < R; i++) { - for (int j = 0; j < C; j++) { - PriorityQueue pq = map.get(i - j); - mat[i][j] = pq.poll(); - } - } - - return mat; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\345\233\276\345\203\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\345\233\276\345\203\217.java" deleted file mode 100644 index e8dce72..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\345\233\276\345\203\217.java" +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.json.JSONUtil; -import org.junit.jupiter.api.Assertions; - -/** - * LCR 006. 两数之和 II - 输入有序数组 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 旋转图像 { - - public static void main(String[] args) { - int[][] matrix = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; - rotate(matrix); - int[][] expect = { { 7, 4, 1 }, { 8, 5, 2 }, { 9, 6, 3 } }; - System.out.println("matrix: " + JSONUtil.toJsonStr(matrix)); - Assertions.assertTrue(ArrayUtil.equals(expect, matrix)); - - int[][] matrix2 = { { 5, 1, 9, 11 }, { 2, 4, 8, 10 }, { 13, 3, 6, 7 }, { 15, 14, 12, 16 } }; - rotate(matrix2); - int[][] expect2 = { { 15, 13, 2, 5 }, { 14, 3, 4, 1 }, { 12, 6, 8, 9 }, { 16, 7, 10, 11 } }; - System.out.println("matrix: " + JSONUtil.toJsonStr(matrix2)); - Assertions.assertTrue(ArrayUtil.equals(expect2, matrix2)); - } - - public static void rotate(int[][] matrix) { - int n = matrix.length; - for (int i = 0; i < n; i++) { - for (int j = i; j < n; j++) { - int temp = matrix[i][j]; - matrix[i][j] = matrix[j][i]; - matrix[j][i] = temp; - } - } - - for (int i = 0; i < n; i++) { - reverse(matrix[i]); - } - } - - public static void reverse(int[] arr) { - int left = 0, right = arr.length - 1; - while (left < right) { - int temp = arr[left]; - arr[left] = arr[right]; - arr[right] = temp; - left++; - right--; - } - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\346\225\260\347\273\204.java" deleted file mode 100644 index 7108f7a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\346\225\260\347\273\204.java" +++ /dev/null @@ -1,63 +0,0 @@ -package io.github.dunwu.algorithm.array; - -// 【旋转数组】 - -// -// 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 -// -// 示例 1: -// -// 输入: [1,2,3,4,5,6,7] 和 k = 3 -// 输出: [5,6,7,1,2,3,4] -// 解释: -// 向右旋转 1 步: [7,1,2,3,4,5,6] -// 向右旋转 2 步: [6,7,1,2,3,4,5] -// 向右旋转 3 步: [5,6,7,1,2,3,4] -// 示例 2: -// -// 输入: [-1,-100,3,99] 和 k = 2 -// 输出: [3,99,-1,-100] -// 解释: -// 向右旋转 1 步: [99,-1,-100,3] -// 向右旋转 2 步: [3,99,-1,-100] -// 说明: -// -// 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 -// 要求使用空间复杂度为 O(1) 的原地算法。 - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 旋转数组 { - - public static void main(String[] args) { - int[] nums1 = { 1, 2, 3, 4, 5, 6, 7 }; - int[] expected1 = { 5, 6, 7, 1, 2, 3, 4 }; - 旋转数组.rotate(nums1, 3); - Assertions.assertArrayEquals(expected1, nums1); - - int[] nums2 = { -1, -100, 3, 99 }; - int[] expected2 = { 3, 99, -1, -100 }; - 旋转数组.rotate(nums2, 2); - Assertions.assertArrayEquals(expected2, nums2); - } - - public static void rotate(int[] nums, int k) { - int i = 0; - while (i < k) { - int j = nums.length - 1; - int temp = nums[nums.length - 1]; - while (j > 0) { - nums[j] = nums[j - 1]; - j--; - } - nums[0] = temp; - // System.out.println(ArrayUtil.getArrayString(nums, 0, nums.length - 1)); - i++; - } - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\347\237\251\351\230\265.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\347\237\251\351\230\265.java" deleted file mode 100644 index d040256..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\227\213\350\275\254\347\237\251\351\230\265.java" +++ /dev/null @@ -1,45 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 旋转矩阵 { - - public static void main(String[] args) { - int[][] array = { - { 1, 2, 3 }, - { 4, 5, 6 }, - { 7, 8, 9 } - }; - int[][] array2 = { - { 7, 4, 1 }, - { 8, 5, 2 }, - { 9, 6, 3 } - }; - rotate(array); - Assertions.assertArrayEquals(array2, array); - } - - /** - * @see 07. 旋转矩阵 - */ - public static void rotate(int[][] matrix) { - int row = matrix.length; - int column = matrix[0].length; - int[][] array = new int[row][column]; - for (int i = 0; i < row; i++) { - for (int j = 0; j < column; j++) { - array[j][row - i - 1] = matrix[i][j]; - } - } - for (int i = 0; i < row; i++) { - for (int j = 0; j < column; j++) { - matrix[i][j] = array[i][j]; - } - } - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" deleted file mode 100644 index d653928..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" +++ /dev/null @@ -1,44 +0,0 @@ -import org.junit.jupiter.api.Assertions; - -/** - * 14. 最长公共前缀 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 最长公共前缀 { - - public static void main(String[] args) { - String[] input1 = { "flower", "flow", "flight" }; - String expect1 = "fl"; - String output1 = longestCommonPrefix(input1); - Assertions.assertEquals(expect1, output1); - - String[] input2 = { "dog", "racecar", "car" }; - String expect2 = ""; - String output2 = longestCommonPrefix(input2); - Assertions.assertEquals(expect2, output2); - } - - public static String longestCommonPrefix(String[] strs) { - if (strs == null || strs.length == 0) return ""; - int p = 0; - int len = strs.length; - while (true) { - if (strs[0].length() <= p) { - break; - } - char c = strs[0].charAt(p); - int i = 1; - while (i < len && p < strs[i].length() && strs[i].charAt(p) == c) { - i++; - } - if (i < len) { - break; - } - p++; - } - return strs[0].substring(0, p); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" deleted file mode 100644 index c881410..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" +++ /dev/null @@ -1,43 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @date 2025-01-10 - */ -public class 最长回文子串 { - - public static void main(String[] args) { - Assertions.assertEquals("bab", longestPalindrome("babad")); - Assertions.assertEquals("bb", longestPalindrome("cbbd")); - Assertions.assertEquals("aca", longestPalindrome("aacabdkacaa")); - } - - public static String longestPalindrome(String s) { - String res = ""; - for (int i = 0; i < s.length(); i++) { - // 以 s[i] 为中心的最长回文子串 - String s1 = palindrome(s, i, i); - // 以 s[i] 和 s[i+1] 为中心的最长回文子串 - String s2 = palindrome(s, i, i + 1); - // res = longest(res, s1, s2) - res = res.length() > s1.length() ? res : s1; - res = res.length() > s2.length() ? res : s2; - } - return res; - } - - public static String palindrome(String s, int l, int r) { - // 防止索引越界 - while (l >= 0 && r < s.length() - && s.charAt(l) == s.charAt(r)) { - // 向两边展开 - l--; - r++; - } - // 此时 [l+1, r-1] 就是最长回文串 - return s.substring(l + 1, r); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" deleted file mode 100644 index 02f5277..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" +++ /dev/null @@ -1,43 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 977. 有序数组的平方 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 有序数组的平方 { - - public static void main(String[] args) { - int[] input1 = { -4, -1, 0, 3, 10 }; - int[] expect1 = { 0, 1, 9, 16, 100 }; - int[] output1 = sortedSquares(input1); - Assertions.assertArrayEquals(expect1, output1); - - int[] input2 = { -7, -3, 2, 3, 11 }; - int[] expect2 = { 4, 9, 9, 49, 121 }; - int[] output2 = sortedSquares(input2); - Assertions.assertArrayEquals(expect2, output2); - } - - public static int[] sortedSquares(int[] nums) { - int len = nums.length; - int left = 0, right = len - 1; - int p = len - 1; - int[] output = new int[len]; - while (left <= right) { - if (Math.abs(nums[left]) > Math.abs(nums[right])) { - output[p] = nums[left] * nums[left]; - left++; - } else { - output[p] = nums[right] * nums[right]; - right--; - } - p--; - } - return output; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\345\212\250\351\233\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\345\212\250\351\233\266.java" deleted file mode 100644 index ceb6050..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\345\212\250\351\233\266.java" +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 283. 移动零 - * - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 移动零 { - - public static void main(String[] args) { - int[] nums1 = { 0, 1, 0, 3, 12 }; - moveZeroes(nums1); - Assertions.assertArrayEquals(new int[] { 1, 3, 12, 0, 0 }, nums1); - - int[] nums2 = { 0, 0, 1 }; - moveZeroes(nums2); - Assertions.assertArrayEquals(new int[] { 1, 0, 0 }, nums2); - - int[] nums3 = { 0 }; - moveZeroes(nums3); - Assertions.assertArrayEquals(new int[] { 0 }, nums3); - } - - public static void moveZeroes(int[] nums) { - int pos = 移除元素.removeElement(nums, 0); - while (pos < nums.length) { - nums[pos] = 0; - pos++; - } - } - - /** - * 时间复杂度:O(N^2) - */ - public static void moveZeroes2(int[] nums) { - if (nums.length <= 1) { - return; - } - int slow = 0; - while (slow < nums.length) { - if (nums[slow] == 0) { - int fast = slow + 1; - while (fast < nums.length && nums[fast] == 0) { - fast++; - } - if (fast >= nums.length) { - break; - } - replacePos(nums, slow, fast); - } - slow++; - } - } - - private static void replacePos(int[] nums, int left, int right) { - int temp = nums[left]; - nums[left] = nums[right]; - nums[right] = temp; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\351\231\244\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\351\231\244\345\205\203\347\264\240.java" deleted file mode 100644 index e1c519d..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\347\247\273\351\231\244\345\205\203\347\264\240.java" +++ /dev/null @@ -1,34 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 27. 移除元素 - * - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 移除元素 { - - public static void main(String[] args) { - int[] nums1 = { 3, 2, 2, 3 }; - Assertions.assertEquals(2, removeElement(nums1, 3)); - - int[] nums2 = { 0, 1, 2, 2, 3, 0, 4, 2 }; - Assertions.assertEquals(5, removeElement(nums2, 2)); - } - - public static int removeElement(int[] nums, int val) { - if (nums == null || nums.length == 0) return 0; - int slow = 0, fast = 0; - while (fast < nums.length) { - if (nums[fast] != val) { - nums[slow] = nums[fast]; - slow++; - } - fast++; - } - return slow; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\236\272\346\227\213\347\237\251\351\230\265.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\236\272\346\227\213\347\237\251\351\230\265.java" deleted file mode 100644 index 95a3576..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\236\272\346\227\213\347\237\251\351\230\265.java" +++ /dev/null @@ -1,85 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; - -// 【螺旋矩阵】 -// -// 给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。 -// -// 示例 1: -// -// 输入: -// [ -// [ 1, 2, 3 ], -// [ 4, 5, 6 ], -// [ 7, 8, 9 ] -// ] -// 输出: [1,2,3,6,9,8,7,4,5] -// 示例 2: -// -// 输入: -// [ -// [1, 2, 3, 4], -// [5, 6, 7, 8], -// [9,10,11,12] -// ] -// 输出: [1,2,3,4,8,12,11,10,9,5,6,7] - -/** - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 螺旋矩阵 { - - public static void main(String[] args) { - int[] nums1 = { 1, 2, 3, 4, 5, 6, 7 }; - int[] expected1 = { 5, 6, 7, 1, 2, 3, 4 }; - 旋转数组.rotate(nums1, 3); - Assertions.assertArrayEquals(expected1, nums1); - - int[] nums2 = { -1, -100, 3, 99 }; - int[] expected2 = { 3, 99, -1, -100 }; - 旋转数组.rotate(nums2, 2); - Assertions.assertArrayEquals(expected2, nums2); - } - - public static List spiralOrder(int[][] matrix) { - ArrayList list = new ArrayList<>(); - if (matrix.length == 0) { - return list; - } - - final int M = matrix.length; - final int N = matrix[0].length; - final int MAX = M * N; - int x = 0, y = 0; - int XMIN = 0, YMIN = 0; - int XMAX = M - 1, YMAX = N - 1; - for (int index = 0; index < MAX; index++) { - list.add(matrix[x][y]); - - if (x == XMIN && y != YMAX) { - y++; - } else if (y == YMAX && x != XMAX) { - x++; - } else if (x == XMAX && y != YMIN) { - y--; - } else if (y == YMIN && x != XMIN + 1) { - x--; - } else if (x == XMIN + 1 && y == YMIN) { - XMIN = XMIN + 1; - YMIN = YMIN + 1; - XMAX = XMAX - 1; - YMAX = YMAX - 1; - x = XMIN; - y = YMIN; - } - } - - return list; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\275\254\347\275\256\347\237\251\351\230\265.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\275\254\347\275\256\347\237\251\351\230\265.java" deleted file mode 100644 index c01dc98..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\275\254\347\275\256\347\237\251\351\230\265.java" +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 1329. 将矩阵按对角线排序 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 转置矩阵 { - - public static void main(String[] args) { - int[][] input1 = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; - int[][] expect1 = { { 1, 4, 7 }, { 2, 5, 8 }, { 3, 6, 9 } }; - int[][] output1 = transpose(input1); - Assertions.assertArrayEquals(expect1, output1); - - int[][] input2 = { { 1, 4, 7 }, { 2, 5, 8 }, { 3, 6, 9 } }; - int[][] expect2 = { { 1, 4, 7 }, { 2, 5, 8 }, { 3, 6, 9 } }; - int[][] output2 = transpose(input2); - Assertions.assertArrayEquals(expect2, output2); - } - - public static int[][] transpose(int[][] matrix) { - int m = matrix.length; - int n = matrix[0].length; - int[][] result = new int[n][m]; - for (int i = 0; i < n; i++) { - for (int j = 0; j < m; j++) { - result[i][j] = matrix[j][i]; - } - } - return result; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\242\234\350\211\262\345\210\206\347\261\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\242\234\350\211\262\345\210\206\347\261\273.java" deleted file mode 100644 index cac5676..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\242\234\350\211\262\345\210\206\347\261\273.java" +++ /dev/null @@ -1,82 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.ReflectUtil; -import org.junit.jupiter.api.Assertions; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * 75. 颜色分类 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 颜色分类 { - - public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { - test(颜色分类.class, "sortColors2"); - test(颜色分类.class, "sortColors3"); - } - - public static void test(Class clazz, String methodName) - throws InvocationTargetException, IllegalAccessException { - - Method method = ReflectUtil.getMethodByName(clazz, methodName); - - int[] arr1 = new int[] { 2, 0, 2, 1, 1, 0 }; - method.invoke(clazz, arr1); - Assertions.assertTrue(ArrayUtil.equals(new int[] { 0, 0, 1, 1, 2, 2 }, arr1)); - - int[] arr2 = new int[] { 2, 0, 1 }; - method.invoke(clazz, arr2); - Assertions.assertTrue(ArrayUtil.equals(new int[] { 0, 1, 2 }, arr2)); - - int[] arr3 = new int[] { 1, 2 }; - method.invoke(clazz, arr3); - Assertions.assertTrue(ArrayUtil.equals(new int[] { 1, 2 }, arr3)); - } - - /** - * 先将 2 往后移,再将 1 往后移:时间复杂度 O(2N) - */ - public static void sortColors2(int[] nums) { - int len = moveToTail(nums, nums.length, 2); - int len2 = moveToTail(nums, len, 1); - } - - public static int moveToTail(int[] nums, int len, int val) { - if (nums == null || len <= 1) { - return len; - } - int slow = 0, fast = 0; - while (fast < len) { - if (nums[fast] != val) { - int temp = nums[slow]; - nums[slow] = nums[fast]; - nums[fast] = temp; - slow++; - } - fast++; - } - return slow; - } - - /** - * 冒泡排序:时间复杂度 O(N^2) - */ - public static void sortColors3(int[] nums) { - if (nums == null || nums.length <= 1) return; - for (int i = 0; i < nums.length; i++) { - for (int j = i + 1; j < nums.length; j++) { - if (nums[i] > nums[j]) { - int temp = nums[i]; - nums[i] = nums[j]; - nums[j] = temp; - } - } - } - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" deleted file mode 100644 index de13f69..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" +++ /dev/null @@ -1,39 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 125. 验证回文串 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 验证回文串 { - - public static void main(String[] args) { - Assertions.assertTrue(isPalindrome("A man, a plan, a canal: Panama")); - Assertions.assertFalse(isPalindrome("race a car")); - Assertions.assertTrue(isPalindrome(" ")); - Assertions.assertTrue(isPalindrome("ab_a")); - } - - public static boolean isPalindrome(String s) { - String format = s.toLowerCase(); - format = format.replaceAll("[^a-zA-Z0-9]", ""); - return doIsPalindrome(format); - } - - public static boolean doIsPalindrome(String s) { - if (s.length() == 0) { return true; } - int left = 0, right = s.length() - 1; - while (left < right) { - if (s.charAt(left) != s.charAt(right)) { - return false; - } - left++; - right--; - } - return true; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" deleted file mode 100644 index 3734a30..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.dunwu.algorithm.dp.str; - -import org.junit.jupiter.api.Assertions; - -/** - * 5. 最长回文子串 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 最长回文子串 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals("bab", s.longestPalindrome("babad")); - Assertions.assertEquals("bb", s.longestPalindrome("cbbd")); - Assertions.assertEquals("a", s.longestPalindrome("a")); - } - - static class Solution { - - public String longestPalindrome(String s) { - String max = ""; - for (int i = 0; i < s.length(); i++) { - for (int j = i; j < s.length(); j++) { - if (isPalindrome(s, i, j)) { - // System.out.println("s = " + s.substring(i, j + 1)); - if (max.length() < (j - i + 1)) { - max = s.substring(i, j + 1); - } - } - } - } - return max; - } - - public boolean isPalindrome(String s, int left, int right) { - if (s == null || s.length() == 0) { return false; } - if (left == right) { return true; } - if (left > right) { return false; } - while (left <= right) { - if (s.charAt(left) != s.charAt(right)) { - return false; - } - left++; - right--; - } - return true; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\346\227\213\350\275\254\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\346\227\213\350\275\254\351\223\276\350\241\250.java" new file mode 100644 index 0000000..a27b82a --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\346\227\213\350\275\254\351\223\276\350\241\250.java" @@ -0,0 +1,82 @@ +package io.github.dunwu.algorithm.linkedlist.reverse; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 61. 旋转链表 + * + * @author Zhang Peng + * @since 2025-11-20 + */ +public class 旋转链表 { + + public static void main(String[] args) { + Solution s = new Solution(); + + ListNode input = ListNode.buildList(1, 2, 3, 4, 5); + ListNode output = s.rotateRight(input, 2); + Assertions.assertEquals(ListNode.buildList(4, 5, 1, 2, 3), output); + + ListNode input2 = ListNode.buildList(0, 1, 2); + ListNode output2 = s.rotateRight(input2, 4); + Assertions.assertEquals(ListNode.buildList(2, 0, 1), output2); + + ListNode input3 = ListNode.buildList(1, 2); + ListNode output3 = s.rotateRight(input3, 1); + Assertions.assertEquals(ListNode.buildList(2, 1), output3); + + ListNode input4 = ListNode.buildList(1, 2); + ListNode output4 = s.rotateRight(input4, 3); + Assertions.assertEquals(ListNode.buildList(2, 1), output4); + } + + static class Solution { + + public ListNode rotateRight(ListNode head, int k) { + if (head == null || head.next == null) { + return head; + } + + ListNode dummy = new ListNode(-1); + dummy.next = head; + + ListNode newLast = lastFromEnd(head, k + 1); + ListNode last = newLast; + while (last.next != null) { + last = last.next; + } + + last.next = head; + dummy.next = newLast.next; + newLast.next = null; + + return dummy.next; + } + + public ListNode lastFromEnd(ListNode head, int k) { + + if (head == null || head.next == null) { + return null; + } + + int i = 0; + ListNode slow = head, fast = head; + while (i < k) { + i++; + if (fast == null) { + fast = head; + } + fast = fast.next; + } + + // fast 先走 k 步后,slow 从 head 开始出发,当 fast 到底,slow 正好是倒数第 k 个节点 + while (fast != null) { + slow = slow.next; + fast = fast.next; + } + return slow; + } + } + +} From 7b0e42adad3470e1395deca205b9a5ad4c932c67 Mon Sep 17 00:00:00 2001 From: dunwu Date: Thu, 27 Nov 2025 22:11:42 +0800 Subject: [PATCH 16/21] =?UTF-8?q?feat:=20leetcode=20=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 186 +++++---- .../io/github/dunwu/algorithm/Parklot.java | 157 -------- .../java/io/github/dunwu/algorithm/Test2.java | 123 ------ ...\345\210\206\346\237\245\346\211\276.java" | 32 +- ...\346\234\200\345\244\247\345\200\274.java" | 71 ++-- ...\347\232\204\350\203\275\345\212\233.java" | 85 ++-- ...\344\270\252\344\275\215\347\275\256.java" | 102 ++--- ...\347\232\204\347\217\202\347\217\202.java" | 71 ++-- ...\347\216\260\346\254\241\346\225\260.java" | 53 +-- ...346\227\213\347\237\251\351\230\2652.java" | 39 +- .../range/\346\213\274\350\275\246.java" | 106 ++--- ...\350\256\242\347\273\237\350\256\241.java" | 77 +++- ...\347\240\201\346\250\241\346\235\277.java" | 4 +- ...\347\240\201\346\250\241\346\235\277.java" | 4 +- ...\346\240\274\350\277\201\347\247\273.java" | 26 +- ...\345\255\220\346\225\260\347\273\204.java" | 52 ++- ...\345\244\215\345\205\203\347\264\240.java" | 27 +- ...345\244\215\345\205\203\347\264\2402.java" | 46 +++ ...345\244\215\345\205\203\347\264\2403.java" | 55 +++ ...45\244\215\345\205\203\347\264\240II.java" | 56 --- ...5\244\215\345\205\203\347\264\240III.java" | 52 --- ...\346\223\215\344\275\234\346\225\260.java" | 4 +- ...\345\244\215\345\255\227\347\254\246.java" | 45 ++- ...347\232\204\344\270\252\346\225\2603.java" | 40 ++ ...7\232\204\344\270\252\346\225\260III.java" | 39 -- ...\351\225\277\345\255\220\344\270\262.java" | 110 ++--- ...\345\255\220\346\225\260\347\273\204.java" | 46 ++- ...\346\210\267\345\220\210\345\271\266.java" | 3 - ...\347\232\204\345\207\272\345\217\243.java" | 2 - .../design/LRU\347\274\223\345\255\230.java" | 2 +- ...\350\256\241\347\256\227\345\231\250.java" | 2 +- ...350\256\241\347\256\227\345\231\2502.java" | 3 +- ...\345\256\211\346\216\222\350\241\250.java" | 2 +- ...\347\244\272\345\215\241\347\211\214.java" | 2 +- ...\347\224\237\346\225\260\351\207\217.java" | 3 +- ...\350\256\241\347\256\227\345\231\250.java" | 2 +- ...\345\255\227\347\254\246\344\270\262.java" | 2 +- ...\350\267\257\345\276\204\345\222\214.java" | 2 - ...\346\225\260\347\273\204\345\222\214.java" | 2 - ...351\222\261\345\205\221\346\215\2422.java" | 2 - ...\346\211\200\346\234\211\350\276\271.java" | 2 +- ...\344\272\214\345\210\206\345\233\276.java" | 4 - .../{hashtable => hash}/JewelsAndStones.java | 2 +- .../SubdomainVisitCount.java | 2 +- .../{hashtable => hash}/ToLowerCase.java | 2 +- ...\346\226\207\351\223\276\350\241\250.java" | 53 ++- ...350\275\254\351\223\276\350\241\2502.java" | 40 +- .../queue/GenericQueue.java | 2 +- ...\347\232\204\351\230\237\345\210\227.java" | 2 +- ...\347\232\204\351\230\237\345\210\227.java" | 2 +- ...\347\232\204\351\230\237\345\210\227.java" | 2 +- .../queue/monotonic/MonotonicQueue.java | 66 +++ ...\346\234\200\345\244\247\345\200\274.java" | 74 ++++ ...\347\256\227\347\263\273\347\273\237.java" | 44 ++ ...\347\232\204\346\227\266\351\227\264.java" | 36 ++ ...\346\261\202\346\254\241\346\225\260.java" | 8 +- ...\345\256\236\347\216\260\346\240\210.java" | 2 +- ...\347\253\257\351\230\237\345\210\227.java" | 11 +- .../StackBasedOnLinkedList.java | 68 ---- ...\345\257\271\350\267\257\345\276\204.java" | 47 --- ...\347\232\204\346\213\254\345\217\267.java" | 54 --- ...\345\214\226\350\267\257\345\276\204.java" | 46 --- ...\345\274\217\346\261\202\345\200\274.java" | 50 --- ...\346\216\222\351\223\276\350\241\250.java" | 60 --- ...\344\270\211\345\220\210\344\270\200.java" | 56 --- ...345\244\247\345\205\203\347\264\240I.java" | 81 ---- ...\346\240\210\346\216\222\345\272\217.java" | 73 ---- ...\347\220\203\346\257\224\350\265\233.java" | 44 -- ...\345\255\227\347\254\246\344\270\262.java" | 42 -- .../io/github/dunwu/algorithm/sort/Sort.java | 2 + .../dunwu/algorithm/sort/SortStrategy.java | 14 +- .../algorithm/sort/strategy/BubbleSort.java | 3 +- .../algorithm/sort/strategy/BubbleSort2.java | 11 +- .../algorithm/sort/strategy/HeapSort.java | 2 +- .../algorithm/sort/strategy/InsertSort.java | 5 +- .../algorithm/sort/strategy/MergeSort.java | 2 +- .../algorithm/sort/strategy/QuickSort.java | 2 +- .../sort/strategy/SelectionSort.java | 2 +- .../algorithm/sort/strategy/ShellSort.java | 2 +- .../stack/GenericStack.java | 2 +- .../stack/monotonic/package-info.java | 7 + ...\345\244\247\345\205\203\347\264\240.java" | 47 +++ ...345\244\247\345\205\203\347\264\2402.java" | 39 ++ ...\347\273\210\344\273\267\346\240\274.java" | 39 ++ ...\345\255\220\346\225\260\347\273\204.java" | 54 +++ ...\346\227\245\346\270\251\345\272\246.java" | 40 ++ ...\344\275\215\346\225\260\345\255\227.java" | 49 +++ ...\346\240\274\350\267\250\345\272\246.java" | 46 +++ .../monotonic/\350\275\246\344\275\215.java" | 66 +++ ...\345\244\247\350\212\202\347\202\271.java" | 53 +++ ...\345\257\271\350\267\257\345\276\204.java" | 51 +++ ...\351\242\221\347\216\207\346\240\210.java" | 32 +- ...\346\234\200\345\260\217\346\240\210.java" | 8 +- ...\347\232\204\346\213\254\345\217\267.java" | 53 +++ ...\346\240\210\346\216\222\345\272\217.java" | 71 ++++ ...\347\220\203\346\257\224\350\265\233.java" | 56 +++ ...\345\255\227\347\254\246\344\270\262.java" | 52 +++ ...\350\277\233\345\220\216\351\200\200.java" | 8 +- ...\347\216\260\351\230\237\345\210\227.java" | 18 +- ...\345\214\226\350\267\257\345\276\204.java" | 50 +++ ...\345\274\217\346\261\202\345\200\274.java" | 53 +++ ...\346\216\222\351\223\276\350\241\250.java" | 60 +++ .../dunwu/algorithm/str/StringAlgorithm.java | 381 ++++++++++-------- .../{string => str}/ValidAnagram.java | 2 +- .../algorithm/string/StringAlgorithm.java | 289 ------------- ...346\220\234\347\264\242\346\240\2212.java" | 2 - ...\345\260\217\350\267\235\347\246\273.java" | 4 - ...\346\217\222\345\205\245\345\231\250.java" | 1 - ...\351\245\260\350\256\260\345\275\225.java" | 3 - ...\345\205\203\347\264\240\345\222\214.java" | 1 - ...\347\202\271\346\210\220\346\236\227.java" | 3 - ...344\272\214\345\217\211\346\240\2212.java" | 2 - ...\345\272\217\345\210\227\345\214\226.java" | 1 - ...\346\226\207\350\267\257\345\276\204.java" | 4 - ...\345\217\263\350\247\206\345\233\276.java" | 2 - ...\344\270\272\351\223\276\350\241\250.java" | 14 +- ...\345\272\217\345\210\227\345\214\226.java" | 41 +- ...\347\232\204\347\233\264\345\276\204.java" | 31 +- ...\344\272\214\345\217\211\346\240\221.java" | 32 +- ...50\257\215\346\220\234\347\264\242II.java" | 6 +- .../dunwu/algorithm/util/ArrayUtil.java | 43 +- ...\345\217\267\347\224\237\346\210\220.java" | 42 -- .../algorithm/sort/SortStrategyTest.java | 81 ++-- .../algorithm/str/StringAlgorithmTest.java | 63 --- .../algorithm/string/StringAlgorithmTest.java | 1 + 125 files changed, 2361 insertions(+), 2399 deletions(-) delete mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/Parklot.java delete mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/Test2.java rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" (95%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" (93%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2402.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2403.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240II.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240III.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\2603.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260III.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/LRU\347\274\223\345\255\230.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/LRU\347\274\223\345\255\230.java" (97%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" (98%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" (94%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" (95%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" (95%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" (95%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\350\256\241\347\256\227\345\231\250.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\350\256\241\347\256\227\345\231\250.java" (92%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/recursive/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" (95%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{hashtable => hash}/JewelsAndStones.java (96%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{hashtable => hash}/SubdomainVisitCount.java (98%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{hashtable => hash}/ToLowerCase.java (95%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{queue_and_stack => }/queue/GenericQueue.java (95%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" (96%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" (96%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" (96%) create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/MonotonicQueue.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/\346\273\221\345\212\250\347\252\227\345\217\243\346\234\200\345\244\247\345\200\274.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/\350\256\276\350\256\241\350\207\252\345\212\251\347\273\223\347\256\227\347\263\273\347\273\237.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\344\271\260\347\245\250\351\234\200\350\246\201\347\232\204\346\227\266\351\227\264.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" (86%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" (96%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/MyCircularDeque.java => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\256\276\350\256\241\345\276\252\347\216\257\345\217\214\347\253\257\351\230\237\345\210\227.java" (91%) delete mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/StackBasedOnLinkedList.java delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\211\345\220\210\344\270\200.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\240\210\346\216\222\345\272\217.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{queue_and_stack => }/stack/GenericStack.java (95%) create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/package-info.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\2402.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\345\225\206\345\223\201\346\212\230\346\211\243\345\220\216\347\232\204\346\234\200\347\273\210\344\273\267\346\240\274.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\234\200\347\237\255\346\227\240\345\272\217\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\257\217\346\227\245\346\270\251\345\272\246.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\202\241\347\245\250\344\273\267\346\240\274\350\267\250\345\272\246.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\275\246\344\275\215.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\351\223\276\350\241\250\344\270\255\347\232\204\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\350\212\202\347\202\271.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" (63%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\260\217\346\240\210.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" (87%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\240\210\346\216\222\345\272\217.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/SampleBrowser.java => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\346\265\217\350\247\210\345\231\250\347\232\204\345\211\215\350\277\233\345\220\216\351\200\200.java" (95%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" (78%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/{string => str}/ValidAnagram.java (98%) delete mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/StringAlgorithm.java delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/\346\213\254\345\217\267\347\224\237\346\210\220.java" delete mode 100644 codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/StringAlgorithmTest.java diff --git a/README.md b/README.md index 1d6d6d7..ceb1146 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ | 题目 | 难度 | 掌握度 | | ------------------------------------------------------------------------------------------------------ | ---- | ------ | | [141. 环形链表](https://leetcode.cn/problems/linked-list-cycle/) | 💚 | ✔️ | -| [142. 环形链表 II](https://leetcode.cn/problems/linked-list-cycle-ii/) | 💛 | ❗ | +| [142. 环形链表 II](https://leetcode.cn/problems/linked-list-cycle-ii/) | 💛 | ✔️ | | [160. 相交链表](https://leetcode.cn/problems/intersection-of-two-linked-lists/) | 💚 | ✔️ | | [19. 删除链表的倒数第 N 个结点](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/) | 💛 | ✔️ | | [21. 合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/) | 💚 | ✔️ | @@ -73,7 +73,7 @@ | [86. 分隔链表](https://leetcode.cn/problems/partition-list/) | 💛 | ✔️ | | [876. 链表的中间结点](https://leetcode.cn/problems/middle-of-the-linked-list/) | 💚 | ✔️ | | [面试题 02. 返回倒数第 k 个节点](https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/) | 💚 | ✔️ | -| [82. 删除排序链表中的重复元素 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/) | 💛 | ❗ | +| [82. 删除排序链表中的重复元素 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/) | 💛 | ✔️ | | [2. 两数相加](https://leetcode.cn/problems/add-two-numbers/) | 💛 | ✔️ | | [445. 两数相加 II](https://leetcode.cn/problems/add-two-numbers-ii/) | 💛 | ✔️ | @@ -83,7 +83,7 @@ | ------------------------------------------------------------------------------ | ---- | ------ | | [61. 旋转链表](https://leetcode.cn/problems/rotate-list/) | 💛 | ✔️ | | [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/) | 💚 | ✔️ | -| [92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/) | 💛 | ❗ | +| [92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/) | 💛 | ✔️ | | [25. K 个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group/) | ❤️ | ❗ | #### 回文链表 @@ -109,10 +109,10 @@ | [125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/) | 💚 | ✔️ | | [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 💛 | ❗ | | [75. 颜色分类](https://leetcode.cn/problems/sort-colors/) | 💛 | ✔️ | -| [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/) | 💚 | ❗ | +| [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/) | 💚 | ✔️ | | [977. 有序数组的平方](https://leetcode.cn/problems/squares-of-a-sorted-array/) | 💚 | ✔️ | -| [1329. 将矩阵按对角线排序](https://leetcode.cn/problems/sort-the-matrix-diagonally/) | 💛 | ❗ | -| [1260. 二维网格迁移](https://leetcode.cn/problems/shift-2d-grid/) | 💚 | ❗ | +| [1329. 将矩阵按对角线排序](https://leetcode.cn/problems/sort-the-matrix-diagonally/) | 💛 | ✔️ | +| [1260. 二维网格迁移](https://leetcode.cn/problems/shift-2d-grid/) | 💚 | ✔️ | | [867. 转置矩阵](https://leetcode.cn/problems/transpose-matrix/) | 💚 | ✔️ | | [14. 最长公共前缀](https://leetcode.cn/problems/longest-common-prefix/) | 💚 | ✔️ | | [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | 💛 | | @@ -122,106 +122,122 @@ | 题目 | 难度 | 掌握度 | | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---- | ------ | -| [151. 反转字符串中的单词](https://leetcode.cn/problems/reverse-words-in-a-string/) | 💛 | ❌ | -| [48. 旋转图像](https://leetcode.cn/problems/rotate-image/) | 💛 | ❗ | -| [54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/)
[LCR 146. 螺旋遍历二维数组](https://leetcode.cn/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/) | 💛 | ❌ | -| [59. 螺旋矩阵 II](https://leetcode.cn/problems/spiral-matrix-ii/) | 💛 | ❗ | +| [151. 反转字符串中的单词](https://leetcode.cn/problems/reverse-words-in-a-string/) | 💛 | ❗ | +| [48. 旋转图像](https://leetcode.cn/problems/rotate-image/) | 💛 | ✔️ | +| [54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/)
[LCR 146. 螺旋遍历二维数组](https://leetcode.cn/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/) | 💛 | ❗ | +| [59. 螺旋矩阵 II](https://leetcode.cn/problems/spiral-matrix-ii/) | 💛 | ✔️ | #### 滑动窗口算法 | 题目 | 难度 | 掌握度 | -| -------------------------------------------------------------------------------------------------------------------------- | ------ | ------ | -| [3. 无重复字符的最长子串](https://leetcode.cn/problems/longest-substring-without-repeating-characters/) | | ❗ | -| [438. 找到字符串中所有字母异位词](https://leetcode.cn/problems/find-all-anagrams-in-a-string/) | | ❗ | -| [567. 字符串的排列](https://leetcode.cn/problems/permutation-in-string/) | | ❗ | -| [76. 最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring/) | | ❌ | -| [1658. 将 x 减到 0 的最小操作数](https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/) | | ❌ | -| [713. 乘积小于 K 的子数组](https://leetcode.cn/problems/subarray-product-less-than-k/) | | ❌ | -| [1004. 最大连续 1 的个数 III](https://leetcode.cn/problems/max-consecutive-ones-iii/) | | ✔️ | -| [424. 替换后的最长重复字符](https://leetcode.cn/problems/longest-repeating-character-replacement/) | | ❗ | -| [219. 存在重复元素 II](https://leetcode.cn/problems/contains-duplicate-ii/) | | ❗ | -| [220. 存在重复元素 III](https://leetcode.cn/problems/contains-duplicate-iii/) | | ❌ | -| [209. 长度最小的子数组](https://leetcode.cn/problems/minimum-size-subarray-sum/) | | ❌ | -| [395. 至少有 K 个重复字符的最长子串](https://leetcode.cn/problems/longest-substring-with-at-least-k-repeating-characters/) | | ❌ | +| -------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | +| [3. 无重复字符的最长子串](https://leetcode.cn/problems/longest-substring-without-repeating-characters/) | 💛 | ✔️ | +| [438. 找到字符串中所有字母异位词](https://leetcode.cn/problems/find-all-anagrams-in-a-string/) | 💛 | ✔️ | +| [567. 字符串的排列](https://leetcode.cn/problems/permutation-in-string/) | 💛 | ✔️ | +| [76. 最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring/) | ❤️ | ❗ | +| [1658. 将 x 减到 0 的最小操作数](https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/) | 💛 | ❌ | +| [713. 乘积小于 K 的子数组](https://leetcode.cn/problems/subarray-product-less-than-k/) | 💛 | ❗ | +| [1004. 最大连续 1 的个数 III](https://leetcode.cn/problems/max-consecutive-ones-iii/) | 💛 | ✔️ | +| [424. 替换后的最长重复字符](https://leetcode.cn/problems/longest-repeating-character-replacement/) | 💛 | ❗ | +| [217. 存在重复元素](https://leetcode.cn/problems/contains-duplicate/) | 💚 | ✔️ | +| [219. 存在重复元素 II](https://leetcode.cn/problems/contains-duplicate-ii/) | 💛 | ❗ | +| [220. 存在重复元素 III](https://leetcode.cn/problems/contains-duplicate-iii/) | 💛 | ❌ | +| [209. 长度最小的子数组](https://leetcode.cn/problems/minimum-size-subarray-sum/) | 💛 | ✔️ | +| [395. 至少有 K 个重复字符的最长子串](https://leetcode.cn/problems/longest-substring-with-at-least-k-repeating-characters/) | 💛 | ❌ | #### 二分查找算法 -| 题目 | 掌握度 | -| :-------------------------------------------------------------------------------------------------------------------------------------- | :----- | -| [34. 在排序数组中查找元素的第一个和最后一个位置](https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/) | ❗ | -| [704. 二分查找](https://leetcode.cn/problems/binary-search/) | ✔️ | -| [LCR 172. 统计目标成绩的出现次数](https://leetcode.cn/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/) | ✔️ | -| [875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) | ❌ | -| [1011. 在 D 天内送达包裹的能力](https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/) | ❌ | -| [410. 分割数组的最大值](https://leetcode.cn/problems/split-array-largest-sum/) | ❌ | +| 题目 | 难度 | 掌握度 | +| :-------------------------------------------------------------------------------------------------------------------------------------- | :--- | ------ | +| [34. 在排序数组中查找元素的第一个和最后一个位置](https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/) | 💛 | ✔️ | +| [704. 二分查找](https://leetcode.cn/problems/binary-search/) | 💚 | ✔️ | +| [LCR 172. 统计目标成绩的出现次数](https://leetcode.cn/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/) | 💚 | ✔️ | +| [875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) | 💛 | ❌ | +| [1011. 在 D 天内送达包裹的能力](https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/) | 💛 | ❌ | +| [410. 分割数组的最大值](https://leetcode.cn/problems/split-array-largest-sum/) | 💛 | ❌ | #### 前缀和数组 -| 题目 | 掌握度 | -| ---------------------------------------------------------------------------------------------- | ------ | -| [303. 区域和检索 - 数组不可变](https://leetcode.cn/problems/range-sum-query-immutable/) | ✔️ | -| [304. 二维区域和检索 - 矩阵不可变](https://leetcode.cn/problems/range-sum-query-2d-immutable/) | ❌ | +| 题目 | 难度 | 掌握度 | +| ---------------------------------------------------------------------------------------------- | ---- | ------ | +| [303. 区域和检索 - 数组不可变](https://leetcode.cn/problems/range-sum-query-immutable/) | 💚 | ✔️ | +| [304. 二维区域和检索 - 矩阵不可变](https://leetcode.cn/problems/range-sum-query-2d-immutable/) | 💛 | ❌ | #### 差分数组 -| 题目 | 掌握度 | -| ----------------------------------------------------------------------------- | ------ | -| [1094. 拼车](https://leetcode.cn/problems/car-pooling/) | | -| [1109. 航班预订统计](https://leetcode.cn/problems/corporate-flight-bookings/) | | -| [370. 区间加法](https://leetcode.cn/problems/range-addition/) | | +| 题目 | 难度 | 掌握度 | +| ----------------------------------------------------------------------------- | ---- | ------ | +| [1094. 拼车](https://leetcode.cn/problems/car-pooling/) | 💛 | ❗ | +| [1109. 航班预订统计](https://leetcode.cn/problems/corporate-flight-bookings/) | 💛 | ❌ | ### 栈和队列 -#### 队列实现栈以及栈实现队列 - -| 题目 | 掌握度 | -| ------------------------------------------------------------------------------- | ------ | -| [225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/) | ✔️ | -| [232. 用栈实现队列](https://leetcode.cn/problems/implement-queue-using-stacks/) | ✔️ | - -#### 栈的经典习题 - -| 题目 | 掌握度 | -| --------------------------------------------------------------------------------------- | ------ | -| [71. 简化路径](https://leetcode.cn/problems/simplify-path/) | ✔️ | -| [143. 重排链表](https://leetcode.cn/problems/reorder-list/) | ✔️ | -| [20. 有效的括号](https://leetcode.cn/problems/valid-parentheses/) | ✔️ | -| [150. 逆波兰表达式求值](https://leetcode.cn/problems/evaluate-reverse-polish-notation/) | ✔️ | -| [388. 文件的最长绝对路径](https://leetcode.cn/problems/longest-absolute-file-path/) | ❌ | -| [155. 最小栈](https://leetcode.cn/problems/min-stack/) | ✔️ | -| 最大频率栈](https://leetcode.cn/problems/maximum-frequency-stack/) | ❌ | - -#### 队列的经典习题 - -| 题目 | 掌握度 | -| --------------------------------------------------------------------------- | ------ | -| [933. 最近的请求次数](https://leetcode.cn/problems/number-of-recent-calls/) | ❗ | -| [622. 设计循环队列](https://leetcode.cn/problems/design-circular-queue/) | ❌ | -| | | - -#### 单调栈算法模板 - -| 题目 | 掌握度 | -| ------------------------------------------------------------------------------- | ------ | -| [496. 下一个更大元素 I](https://leetcode.cn/problems/next-greater-element-i/) | | -| [503. 下一个更大元素 II](https://leetcode.cn/problems/next-greater-element-ii/) | | -| [739. 每日温度](https://leetcode.cn/problems/daily-temperatures/) | | -| [剑指 Offer II 038. 每日温度](https://leetcode.cn/problems/iIQa4I/) | | +#### 队列 + +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------------------------------------ | ---- | ------ | +| [225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/) | 💚 | ✔️ | +| [933. 最近的请求次数](https://leetcode.cn/problems/number-of-recent-calls/) | 💚 | ❗ | +| [622. 设计循环队列](https://leetcode.cn/problems/design-circular-queue/) | 💛 | ❌ | +| [641. 设计循环双端队列](https://leetcode.cn/problems/design-circular-deque/) | 💛 | | +| [1670. 设计前中后队列](https://leetcode.cn/problems/design-front-middle-back-queue/) | 💛 | | +| [2073. 买票需要的时间](https://leetcode.cn/problems/time-needed-to-buy-tickets/) | 💚 | ✔️ | + +#### 栈 + +| 题目 | 难度 | 掌握度 | +| --------------------------------------------------------------------------------------- | ---- | ------ | +| [20. 有效的括号](https://leetcode.cn/problems/valid-parentheses/) | 💚 | ✔️ | +| [232. 用栈实现队列](https://leetcode.cn/problems/implement-queue-using-stacks/) | 💚 | ✔️ | +| [682. 棒球比赛](https://leetcode.cn/problems/baseball-game/) | 💚 | ✔️ | +| [844. 比较含退格的字符串](https://leetcode.cn/problems/backspace-string-compare/) | 💚 | ✔️ | +| [71. 简化路径](https://leetcode.cn/problems/simplify-path/) | 💛 | ✔️ | +| [143. 重排链表](https://leetcode.cn/problems/reorder-list/) | 💛 | ✔️ | +| [150. 逆波兰表达式求值](https://leetcode.cn/problems/evaluate-reverse-polish-notation/) | 💛 | ✔️ | +| [388. 文件的最长绝对路径](https://leetcode.cn/problems/longest-absolute-file-path/) | 💛 | ❌ | +| [155. 最小栈](https://leetcode.cn/problems/min-stack/) | 💛 | ✔️ | +| [面试题 03.05. 栈排序](https://leetcode.cn/problems/sort-of-stacks-lcci/) | 💛 | ✔️ | +| [895. 最大频率栈](https://leetcode.cn/problems/maximum-frequency-stack/) | ❤️ | ❌ | + +#### 单调栈 + +| 题目 | 难度 | 掌握度 | +| ----------------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | +| [496. 下一个更大元素 I](https://leetcode.cn/problems/next-greater-element-i/) | 💚 | ❗ | +| [503. 下一个更大元素 II](https://leetcode.cn/problems/next-greater-element-ii/) | 💛 | ❗ | +| [739. 每日温度](https://leetcode.cn/problems/daily-temperatures/)
[剑指 Offer II 038. 每日温度](https://leetcode.cn/problems/iIQa4I/) | 💛 | ✔️ | +| [1019. 链表中的下一个更大节点](https://leetcode.cn/problems/next-greater-node-in-linked-list/) | 💛 | ✔️ | +| [1944. 队列中可以看到的人数](https://leetcode.cn/problems/number-of-visible-people-in-a-queue/) | ❤️ | | +| [1475. 商品折扣后的最终价格](https://leetcode.cn/problems/final-prices-with-a-special-discount-in-a-shop/) | 💛 | ✔️ | +| [901. 股票价格跨度](https://leetcode.cn/problems/online-stock-span/) | 💛 | ❌ | +| [402. 移掉 K 位数字](https://leetcode.cn/problems/remove-k-digits/) | 💛 | ❌ | +| [853. 车队](https://leetcode.cn/problems/car-fleet/) | 💛 | ❌ | +| [581. 最短无序连续子数组](https://leetcode.cn/problems/shortest-unsorted-continuous-subarray/) | 💛 | ❌ | + +#### 单调队列 + +| 题目 | 难度 | 掌握度 | +| -------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | +| [LCR 184. 设计自助结算系统](https://leetcode.cn/problems/dui-lie-de-zui-da-zhi-lcof/) | 💛 | | +| [239. 滑动窗口最大值](https://leetcode.cn/problems/sliding-window-maximum/) | ❤️ | ❌ | +| [1438. 绝对差不超过限制的最长连续子数组](https://leetcode.cn/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit/) | 💛 | | +| [862. 和至少为 K 的最短子数组](https://leetcode.cn/problems/shortest-subarray-with-sum-at-least-k/) | ❤️ | | +| [918. 环形子数组的最大和](https://labuladong.online/algo/problem-set/monotonic-queue/#slug_maximum-sum-circular-subarray) | 💛 | | ### 二叉树 #### 基础 -| 题目 | 掌握度 | -| ---------------------------------------------------------------------------------------------------- | ------ | -| [104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) | ✔️ | -| [111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/) | ✔️ | -| [543. 二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree/) | ❌ | -| [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/) | ❗ | -| [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/) | ✔️ | -| [654. 最大二叉树](https://leetcode.cn/problems/maximum-binary-tree/) | ✔️ | -| [297. 二叉树的序列化与反序列化](https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/) | ❌ | -| [222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/) | ✔️ | +| 题目 | 难度 | 掌握度 | +| ---------------------------------------------------------------------------------------------------- | ------ | ------ | +| [104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) | 💚 | ✔️ | +| [111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/) | 💚 | ✔️ | +| [543. 二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree/) | 💚 | ❌ | +| [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/) | 💛 | ✔️ | +| [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/) | 💚 | ✔️ | +| [654. 最大二叉树](https://leetcode.cn/problems/maximum-binary-tree/) | 💛 | ✔️ | +| [297. 二叉树的序列化与反序列化](https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/) | ❤️ | ❗ | +| [222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/) | 💚 | ✔️ | #### DFS diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/Parklot.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/Parklot.java deleted file mode 100644 index 2451364..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/Parklot.java +++ /dev/null @@ -1,157 +0,0 @@ -package io.github.dunwu.algorithm; - -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -/** - * @author Zhang Peng - * @since 2020-05-13 - */ -public class Parklot { - - private volatile AtomicInteger space; - private volatile AtomicLong sum; - private volatile int MAX = 1000; - - public boolean enter(Car car) { - if (space.get() >= MAX) { - // reject - return false; - } - - // TODO 判断车类型 - - car.enter(); - space.getAndIncrement(); - return true; - } - - public long exit(Car car) { - if (space.get() >= MAX) { - // reject - return 0L; - } - - // TODO 判断车类型 - car.exit(); - long money = car.money(); - // 扣费 - space.getAndDecrement(); - sum.getAndAdd(money); - return money; - } - - public void getSum() { - - } - - public interface Parking { - - enum Type { - car, - truck - } - - int getPrice(); - - int getMax(); - - void enter(); - - void exit(); - - LocalDateTime getBeginTime(); - - LocalDateTime getEndTime(); - - default long money() { - if (getEndTime() == null) { - return 0; - } - long l2 = getEndTime().toEpochSecond(ZoneOffset.UTC); - long l1 = getBeginTime().toEpochSecond(ZoneOffset.UTC); - long time = l2 - l1; - long hours = TimeUnit.NANOSECONDS.toHours(time); - long total = getPrice() * hours; - return Math.min(total, getMax()); - } - - } - - public abstract class Car implements Parking { - - private static final int price = 5; - private static final int max = 60; - private LocalDateTime beginTime; - private LocalDateTime endTime; - - @Override - public int getPrice() { - return price; - } - - @Override - public int getMax() { - return max; - } - - @Override - public void enter() { - beginTime = LocalDateTime.now(); - } - - @Override - public void exit() { - endTime = LocalDateTime.now(); - } - - @Override - public LocalDateTime getBeginTime() { - return beginTime; - } - - @Override - public LocalDateTime getEndTime() { - return endTime; - } - - } - - public class LittleCar extends Car { - - private static final int price = 5; - private static final int max = 60; - - @Override - public int getPrice() { - return price; - } - - @Override - public int getMax() { - return max; - } - - } - - public class Truck extends Car implements Parking { - - private static final int price = 10; - private static final int max = 120; - - @Override - public int getPrice() { - return price; - } - - @Override - public int getMax() { - return max; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/Test2.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/Test2.java deleted file mode 100644 index e918626..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/Test2.java +++ /dev/null @@ -1,123 +0,0 @@ -package io.github.dunwu.algorithm; - -/** - * @author Zhang Peng - * @since 2020-05-13 - */ -public class Test2 { - - public static void main(String[] args) { - ListNode l1 = new ListNode(2); - l1.next = new ListNode(4); - l1.next.next = new ListNode(3); - - ListNode l2 = new ListNode(5); - l2.next = new ListNode(6); - l2.next.next = new ListNode(4); - - ListNode result = add(l1, l2); - ListNode temp = result; - while (temp != null) { - System.out.println(temp.val); - temp = temp.next; - } - - System.out.println("result = " + listNodeToNum(result)); - } - - public static ListNode add(ListNode l1, ListNode l2) { - ListNode n1 = l1; - ListNode n2 = l2; - ListNode resultNode = new ListNode(-1); - ListNode temp = resultNode; - boolean flag = false; - while (n1 != null && n2 != null) { - int value = n1.val + n2.val; - if (flag) { - value++; - } - int num = 0; - if (value >= 10) { - num = value % 10; - flag = true; - } else { - num = value; - flag = false; - } - - n1 = n1.next; - n2 = n2.next; - temp.next = new ListNode(num); - temp = temp.next; - } - - if (n1 != null) { - while (n1 != null) { - int num = 0; - if (flag) { - num = 1 + n1.val; - } else { - num = n1.val; - } - n1 = n1.next; - temp = new ListNode(num); - temp = temp.next; - } - } - - if (n2 != null) { - while (n2 != null) { - int num = 0; - if (flag) { - num = 1 + n2.val; - } else { - num = n2.val; - } - n2 = n2.next; - temp = new ListNode(num); - temp = temp.next; - } - } - - return resultNode.next; - } - - public static int listNodeToNum(ListNode head) { - if (head == null) { - return 0; - } - - int result = 0; - int pos = 0; - ListNode node = head; - while (node != null) { - result += getBase(pos) * node.val; - node = node.next; - pos++; - } - - return result; - } - - public static int getBase(int pos) { - if (pos <= 0) { - return 1; - } else { - pos--; - return 10 * getBase(pos); - } - } - - public static class ListNode { - - public int val; - public ListNode next; - - public ListNode(int val) { - this.val = val; - this.next = null; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\344\272\214\345\210\206\346\237\245\346\211\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\344\272\214\345\210\206\346\237\245\346\211\276.java" index feae11a..1a47983 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\344\272\214\345\210\206\346\237\245\346\211\276.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\344\272\214\345\210\206\346\237\245\346\211\276.java" @@ -11,24 +11,28 @@ public class 二分查找 { public static void main(String[] args) { - Assertions.assertEquals(4, search(new int[] { -1, 0, 3, 5, 9, 12 }, 9)); - Assertions.assertEquals(-1, search(new int[] { -1, 0, 3, 5, 9, 12 }, 2)); + Solution s = new Solution(); + Assertions.assertEquals(4, s.search(new int[] { -1, 0, 3, 5, 9, 12 }, 9)); + Assertions.assertEquals(-1, s.search(new int[] { -1, 0, 3, 5, 9, 12 }, 2)); } - public static int search(int[] nums, int target) { - if (nums == null || nums.length == 0) return -1; - int left = 0, right = nums.length - 1; - while (left <= right) { - int mid = left + (right - left) / 2; - if (nums[mid] == target) { - return mid; - } else if (nums[mid] < target) { - left = mid + 1; - } else if (nums[mid] > target) { - right = mid - 1; + static class Solution { + + public int search(int[] nums, int target) { + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + if (nums[mid] == target) { + return mid; + } else if (nums[mid] < target) { + left = mid + 1; + } else { + right = mid - 1; + } } + return -1; } - return -1; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" index 43692b1..f302150 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" @@ -11,47 +11,54 @@ public class 分割数组的最大值 { public static void main(String[] args) { - Assertions.assertEquals(18, splitArray(new int[] { 7, 2, 5, 10, 8 }, 2)); - Assertions.assertEquals(9, splitArray(new int[] { 1, 2, 3, 4, 5 }, 2)); - Assertions.assertEquals(4, splitArray(new int[] { 1, 4, 4 }, 3)); + Solution s = new Solution(); + Assertions.assertEquals(18, s.splitArray(new int[] { 7, 2, 5, 10, 8 }, 2)); + Assertions.assertEquals(9, s.splitArray(new int[] { 1, 2, 3, 4, 5 }, 2)); + Assertions.assertEquals(4, s.splitArray(new int[] { 1, 4, 4 }, 3)); } - public static int splitArray(int[] nums, int k) { - int left = 0; - int right = 0; - for (int w : nums) { - left = Math.max(left, w); - right += w; - } + static class Solution { - while (left <= right) { - int mid = left + (right - left) / 2; - if (f(nums, mid) == k) { - right = mid - 1; - } else if (f(nums, mid) < k) { - right = mid - 1; - } else if (f(nums, mid) > k) { - left = mid + 1; + public int splitArray(int[] nums, int k) { + int left = 0; + int right = 1; + for (int w : nums) { + left = Math.max(left, w); + right += w; } - } - return left; - } - public static int f(int[] weights, int x) { - int days = 0; - for (int i = 0; i < weights.length; ) { - int cap = x; - while (i < weights.length) { - if (cap < weights[i]) { - break; + int res = 0; + while (left <= right) { + int mid = left + (right - left) / 2; + if (f(nums, mid) <= k) { + res = mid; + right = mid - 1; } else { - cap -= weights[i]; + left = mid + 1; + } + } + return res; + } + + public int f(int[] nums, int x) { + int i = 0; + int days = 0; + while (i < nums.length) { + // 尽可能多装货物 + int cap = x; + while (i < nums.length) { + if (cap < nums[i]) { + break; + } else { + cap -= nums[i]; + } + i++; } - i++; + days++; } - days++; + return days; } - return days; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" index 850a9f2..46be717 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" @@ -2,9 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.lang.reflect.InvocationTargetException; -import java.util.Arrays; - /** * 1011. 在 D 天内送达包裹的能力 * @@ -13,53 +10,59 @@ */ public class 在D天内送达包裹的能力 { - public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { - - // Assertions.assertEquals(5, f(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 15)); - // Assertions.assertEquals(3, f(new int[] { 3, 2, 2, 4, 1, 4 }, 6)); - // Assertions.assertEquals(4, f(new int[] { 1, 2, 3, 1, 1 }, 3)); - - Assertions.assertEquals(15, shipWithinDays(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 5)); - Assertions.assertEquals(6, shipWithinDays(new int[] { 3, 2, 2, 4, 1, 4 }, 3)); - Assertions.assertEquals(3, shipWithinDays(new int[] { 1, 2, 3, 1, 1 }, 4)); + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(15, s.shipWithinDays(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 5)); + Assertions.assertEquals(6, s.shipWithinDays(new int[] { 3, 2, 2, 4, 1, 4 }, 3)); + Assertions.assertEquals(3, s.shipWithinDays(new int[] { 1, 2, 3, 1, 1 }, 4)); } - public static int shipWithinDays(int[] weights, int days) { - int left = 0; - int right = 0; - for (int w : weights) { - left = Math.max(left, w); - right += w; - } + static class Solution { - while (left <= right) { - int mid = left + (right - left) / 2; - if (f(weights, mid) == days) { - right = mid - 1; - } else if (f(weights, mid) < days) { - right = mid - 1; - } else if (f(weights, mid) > days) { - left = mid + 1; + public int shipWithinDays(int[] weights, int days) { + int left = 0; + // 注意,right 是开区间,所以额外加一 + int right = 1; + for (int w : weights) { + left = Math.max(left, w); + right += w; } + + while (left < right) { + int mid = left + (right - left) / 2; + if (f(weights, mid) == days) { + // 搜索左侧边界,则需要收缩右侧边界 + right = mid; + } else if (f(weights, mid) < days) { + // 需要让 f(x) 的返回值大一些 + right = mid; + } else if (f(weights, mid) > days) { + // 需要让 f(x) 的返回值小一些 + left = mid + 1; + } + } + return left; } - return left; - } - public static int f(int[] weights, int x) { - int days = 0; - for (int i = 0; i < weights.length; ) { - int cap = x; - while (i < weights.length) { - if (cap < weights[i]) { - break; - } else { - cap -= weights[i]; + // 定义:当运载能力为 x 时,需要 f(x) 天运完所有货物 + // f(x) 随着 x 的增加单调递减 + int f(int[] weights, int x) { + int days = 0; + for (int i = 0; i < weights.length; ) { + int cap = x; + while (i < weights.length) { + if (cap < weights[i]) { + break; + } else { + cap -= weights[i]; + } + i++; } - i++; + days++; } - days++; + return days; } - return days; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" index 77a838c..fb14865 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" @@ -12,68 +12,68 @@ public class 在排序数组中查找元素的第一个和最后一个位置 { public static void main(String[] args) { - Assertions.assertArrayEquals(new int[] { 3, 4 }, searchRange(new int[] { 5, 7, 7, 8, 8, 10 }, 8)); - Assertions.assertArrayEquals(new int[] { -1, -1 }, searchRange(new int[] { 5, 7, 7, 8, 8, 10 }, 6)); - Assertions.assertArrayEquals(new int[] { -1, -1 }, searchRange(new int[] {}, 0)); - Assertions.assertArrayEquals(new int[] { 0, 0 }, searchRange(new int[] { 1 }, 1)); + Solution s = new Solution(); - Assertions.assertEquals(-1, searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 3)); - Assertions.assertEquals(0, searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 5)); - Assertions.assertEquals(5, searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 10)); - Assertions.assertEquals(-1, searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 12)); - Assertions.assertEquals(1, searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 7)); + Assertions.assertEquals(-1, s.searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 3)); + Assertions.assertEquals(0, s.searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 5)); + Assertions.assertEquals(5, s.searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 10)); + Assertions.assertEquals(-1, s.searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 12)); + Assertions.assertEquals(1, s.searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 7)); - Assertions.assertEquals(-1, searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 3)); - Assertions.assertEquals(0, searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 5)); - Assertions.assertEquals(5, searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 10)); - Assertions.assertEquals(-1, searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 12)); - Assertions.assertEquals(2, searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 7)); + Assertions.assertEquals(-1, s.searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 3)); + Assertions.assertEquals(0, s.searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 5)); + Assertions.assertEquals(5, s.searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 10)); + Assertions.assertEquals(-1, s.searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 12)); + Assertions.assertEquals(2, s.searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 7)); + + Assertions.assertArrayEquals(new int[] { 3, 4 }, s.searchRange(new int[] { 5, 7, 7, 8, 8, 10 }, 8)); + Assertions.assertArrayEquals(new int[] { -1, -1 }, s.searchRange(new int[] { 5, 7, 7, 8, 8, 10 }, 6)); + Assertions.assertArrayEquals(new int[] { -1, -1 }, s.searchRange(new int[] {}, 0)); + Assertions.assertArrayEquals(new int[] { 0, 0 }, s.searchRange(new int[] { 1 }, 1)); } - public static int[] searchRange(int[] nums, int target) { - final int[] notFound = { -1, -1 }; - if (nums == null || nums.length == 0) { - return notFound; + static class Solution { + + public int[] searchRange(int[] nums, int target) { + int left = searchLeft(nums, target); + int right = searchRight(nums, target); + return new int[] { left, right }; } - int begin = searchLeft(nums, target); - int end = searchRight(nums, target); - return new int[] { begin, end }; - } - static int searchLeft(int[] nums, int target) { - int left = 0, right = nums.length - 1; - while (left <= right) { - int mid = left + (right - left) / 2; - if (nums[mid] == target) { - right = mid - 1; - } else if (nums[mid] > target) { - right = mid - 1; - } else if (nums[mid] < target) { - left = mid + 1; + public int searchLeft(int[] nums, int target) { + int res = -1; + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + if (nums[mid] < target) { + left = mid + 1; + } else if (nums[mid] > target) { + right = mid - 1; + } else if (nums[mid] == target) { + res = mid; + right = mid - 1; + } } + return res; } - if (left < 0 || left >= nums.length) { - return -1; - } - return nums[left] == target ? left : -1; - } - static int searchRight(int[] nums, int target) { - int left = 0, right = nums.length - 1; - while (left <= right) { - int mid = left + (right - left) / 2; - if (nums[mid] == target) { - left = mid + 1; - } else if (nums[mid] < target) { - left = mid + 1; - } else if (nums[mid] > target) { - right = mid - 1; + public int searchRight(int[] nums, int target) { + int res = -1; + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + if (nums[mid] > target) { + right = mid - 1; + } else if (nums[mid] < target) { + left = mid + 1; + } else if (nums[mid] == target) { + res = mid; + left = mid + 1; + } } + return res; } - if (right < 0 || right >= nums.length) { - return -1; - } - return nums[right] == target ? right : -1; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" index 111a36c..bae535a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" @@ -2,9 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.lang.reflect.InvocationTargetException; -import java.util.Arrays; - /** * 875. 爱吃香蕉的珂珂 * @@ -13,40 +10,56 @@ */ public class 爱吃香蕉的珂珂 { - public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { - Assertions.assertEquals(4, minEatingSpeed(new int[] { 3, 6, 7, 11 }, 8)); - Assertions.assertEquals(30, minEatingSpeed(new int[] { 30, 11, 23, 4, 20 }, 5)); - Assertions.assertEquals(23, minEatingSpeed(new int[] { 30, 11, 23, 4, 20 }, 6)); + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(4, s.minEatingSpeed(new int[] { 3, 6, 7, 11 }, 8)); + Assertions.assertEquals(30, s.minEatingSpeed(new int[] { 30, 11, 23, 4, 20 }, 5)); + Assertions.assertEquals(23, s.minEatingSpeed(new int[] { 30, 11, 23, 4, 20 }, 6)); + Assertions.assertEquals(2, s.minEatingSpeed(new int[] { 312884470 }, 312884469)); + Assertions.assertEquals(3, s.minEatingSpeed(new int[] { 805306368, 805306368, 805306368 }, 1000000000)); + Assertions.assertEquals(14, s.minEatingSpeed( + new int[] { 332484035, 524908576, 855865114, 632922376, 222257295, 690155293, 112677673, 679580077, + 337406589, 290818316, 877337160, 901728858, 679284947, 688210097, 692137887, 718203285, 629455728, + 941802184 }, 823855818)); } - public static int minEatingSpeed(int[] piles, int h) { - int left = 1, right = 1000000000 + 1; - while (left <= right) { - int mid = left + (right - left) / 2; - if (fun(piles, mid) == h) { - right = mid - 1; - } else if (fun(piles, mid) < h) { - right = mid - 1; - } else if (fun(piles, mid) > h) { - left = mid + 1; + static class Solution { + + public int minEatingSpeed(int[] piles, int h) { + final int rightBound = 1_000_000_001; + int left = 1, right = rightBound; + while (left < right) { + int mid = left + (right - left) / 2; + if (f(piles, mid) == h) { + // 搜索左侧边界,则需要收缩右侧边界 + right = mid ; + } else if (f(piles, mid) < h) { + // 需要让 f(x) 的返回值大一些 + right = mid ; + } else if (f(piles, mid) > h) { + // 需要让 f(x) 的返回值小一些 + left = mid + 1; + } } + if (left < 0 || left > rightBound) { return -1; } + return left; } - return left; - } - public static long fun(int[] piles, int speed) { - long hour = 0L; - for (int pile : piles) { - if (pile <= speed) { - hour++; - } else { - hour += pile / speed; - if (pile % speed != 0) { - hour++; + public int f(int[] nums, int x) { + int res = 0; + for (int num : nums) { + if (num <= x) { + res++; + } else { + res += num / x; + if (num % x != 0) { + res++; + } } } + return res; } - return hour; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\273\237\350\256\241\347\233\256\346\240\207\346\210\220\347\273\251\347\232\204\345\207\272\347\216\260\346\254\241\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\273\237\350\256\241\347\233\256\346\240\207\346\210\220\347\273\251\347\232\204\345\207\272\347\216\260\346\254\241\346\225\260.java" index e00d4db..c0266ae 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\273\237\350\256\241\347\233\256\346\240\207\346\210\220\347\273\251\347\232\204\345\207\272\347\216\260\346\254\241\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\273\237\350\256\241\347\233\256\346\240\207\346\210\220\347\273\251\347\232\204\345\207\272\347\216\260\346\254\241\346\225\260.java" @@ -11,37 +11,42 @@ public class 统计目标成绩的出现次数 { public static void main(String[] args) { - Assertions.assertEquals(3, countTarget(new int[] { 2, 2, 3, 4, 4, 4, 5, 6, 6, 8 }, 4)); - Assertions.assertEquals(0, countTarget(new int[] { 1, 2, 3, 5, 7, 9 }, 6)); + Solution s = new Solution(); + Assertions.assertEquals(3, s.countTarget(new int[] { 2, 2, 3, 4, 4, 4, 5, 6, 6, 8 }, 4)); + Assertions.assertEquals(0, s.countTarget(new int[] { 1, 2, 3, 5, 7, 9 }, 6)); } - public static int countTarget(int[] scores, int target) { - int result = search(scores, 0, scores.length - 1, target); - return result == -1 ? 0 : result; - } + static class Solution { - static int search(int[] scores, int left, int right, int target) { - if (left > right) { - return -1; - } - int mid = left + (right - left) / 2; - if (scores[mid] == target) { - int lcnt = search(scores, left, mid - 1, target); - int rcnt = search(scores, mid + 1, right, target); + public int countTarget(int[] scores, int target) { + int leftBound = searchLeft(scores, target); + if (leftBound == -1) { return 0; } int cnt = 1; - if (lcnt > 0) { - cnt += lcnt; - } - if (rcnt > 0) { - cnt += rcnt; + for (int i = leftBound + 1; i < scores.length; i++) { + if (scores[i] == target) { + cnt++; + } } return cnt; - } else if (scores[mid] < target) { - return search(scores, mid + 1, right, target); - } else if (scores[mid] > target) { - return search(scores, left, mid - 1, target); } - return -1; + + public int searchLeft(int[] nums, int target) { + int res = -1; + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + if (nums[mid] < target) { + left = mid + 1; + } else if (nums[mid] > target) { + right = mid - 1; + } else if (nums[mid] == target) { + right = mid - 1; + res = mid; + } + } + return res; + } + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\2652.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\2652.java" index a9de77a..785f236 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\2652.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\2652.java" @@ -3,7 +3,7 @@ import org.junit.jupiter.api.Assertions; /** - * 54. 螺旋矩阵 + * 54. 螺旋矩阵 * * @author Zhang Peng * @since 2018-11-04 @@ -21,35 +21,42 @@ public static void main(String[] args) { static class Solution { public int[][] generateMatrix(int n) { - int cnt = 0; - int up = 0, down = n - 1; - int left = 0, right = n - 1; int[][] res = new int[n][n]; + int left = 0, right = n - 1, top = 0, bottom = n - 1; while (cnt < n * n) { + // 向右 - for (int i = left; i <= right; i++) { - res[up][i] = ++cnt; + if (top <= bottom) { + for (int i = left; i <= right; i++) { + res[top][i] = ++cnt; + } + top++; } - up++; // 向下 - for (int i = up; i <= down; i++) { - res[i][right] = ++cnt; + if (left <= right) { + for (int i = top; i <= bottom; i++) { + res[i][right] = ++cnt; + } + right--; } - right--; // 向左 - for (int i = right; i >= left; i--) { - res[down][i] = ++cnt; + if (top <= bottom) { + for (int i = right; i >= left; i--) { + res[bottom][i] = ++cnt; + } + bottom--; } - down--; // 向上 - for (int i = down; i >= up; i--) { - res[i][left] = ++cnt; + if (left <= right) { + for (int i = bottom; i >= top; i--) { + res[i][left] = ++cnt; + } + left++; } - left++; } return res; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" index 252a99f..ff5a6dd 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" @@ -11,64 +11,80 @@ public class 拼车 { public static void main(String[] args) { - int[][] bookings = { { 2, 1, 5 }, { 3, 3, 7 } }; - Assertions.assertFalse(carPooling(bookings, 4)); - - int[][] bookings2 = { { 1, 2, 10 }, { 2, 2, 15 } }; - Assertions.assertTrue(carPooling(bookings2, 5)); + Solution s = new Solution(); + int[][] input = { { 2, 1, 5 }, { 3, 3, 7 } }; + Assertions.assertFalse(s.carPooling(input, 3)); + int[][] input2 = { { 1, 2, 10 }, { 2, 2, 15 } }; + Assertions.assertTrue(s.carPooling(input2, 5)); } - public static boolean carPooling(int[][] trips, int capacity) { - int[] nums = new int[1001]; - Difference df = new Difference(nums); - for (int[] trip : trips) { - // 乘客数量 - int val = trip[0]; - // 第 trip[1] 站乘客上车 - int i = trip[1]; - // 第 trip[2] 站乘客已经下车, - // 即乘客在车上的区间是 [trip[1], trip[2] - 1] - int j = trip[2] - 1; - // 进行区间操作 - df.increase(i, j, val); - } - int[] result = df.result(); + static class Solution { + + public boolean carPooling(int[][] trips, int capacity) { + // 最多有 1000 个车站 + int[] nums = new int[1001]; + // 构造差分解法 + Difference df = new Difference(nums); + + for (int[] trip : trips) { + // 乘客数量 + int val = trip[0]; + // 第 trip[1] 站乘客上车 + int i = trip[1]; + // 第 trip[2] 站乘客已经下车, + // 即乘客在车上的区间是 [trip[1], trip[2] - 1] + int j = trip[2] - 1; + // 进行区间操作 + df.increment(i, j, val); + } - // 客车自始至终都不应该超载 - for (int res : result) { - if (capacity < res) { - return false; + int[] res = df.result(); + + // 客车自始至终都不应该超载 + for (int i = 0; i < res.length; i++) { + if (capacity < res[i]) { + return false; + } } + return true; } - return true; - } - static class Difference { + // 差分数组工具类 + static class Difference { - private int[] diff; + // 差分数组 + private final int[] diff; - public Difference(int[] nums) { - diff = new int[nums.length]; - diff[0] = nums[0]; - for (int i = 1; i < diff.length; i++) { - diff[i] = nums[i] - nums[i - 1]; + // 输入一个初始数组,区间操作将在这个数组上进行 + public Difference(int[] nums) { + assert nums.length > 0; + diff = new int[nums.length]; + // 根据初始数组构造差分数组 + diff[0] = nums[0]; + for (int i = 1; i < nums.length; i++) { + diff[i] = nums[i] - nums[i - 1]; + } } - } - public void increase(int left, int right, int val) { - diff[left - 1] += val; - if (right < diff.length) { - diff[right] -= val; + // 给闭区间 [i, j] 增加 val(可以是负数) + public void increment(int i, int j, int val) { + diff[i] += val; + if (j + 1 < diff.length) { + diff[j + 1] -= val; + } } - } - public int[] result() { - int[] result = new int[diff.length]; - result[0] = diff[0]; - for (int i = 1; i < diff.length; i++) { - result[i] = result[i - 1] + diff[i]; + // 返回结果数组 + public int[] result() { + int[] res = new int[diff.length]; + // 根据差分数组构造结果数组 + res[0] = diff[0]; + for (int i = 1; i < diff.length; i++) { + res[i] = res[i - 1] + diff[i]; + } + return res; } - return result; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" index 5ff7556..3ed6404 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" @@ -1,6 +1,5 @@ package io.github.dunwu.algorithm.array.range; -import cn.hutool.json.JSONUtil; import org.junit.jupiter.api.Assertions; /** @@ -12,30 +11,74 @@ public class 航班预订统计 { public static void main(String[] args) { + + Solution s = new Solution(); + int[][] bookings = { { 1, 2, 10 }, { 2, 3, 20 }, { 2, 5, 25 } }; - Assertions.assertArrayEquals(new int[] { 10, 55, 45, 25, 25 }, corpFlightBookings(bookings, 5)); + Assertions.assertArrayEquals(new int[] { 10, 55, 45, 25, 25 }, s.corpFlightBookings(bookings, 5)); int[][] bookings2 = { { 1, 2, 10 }, { 2, 2, 15 } }; - Assertions.assertArrayEquals(new int[] { 10, 25 }, corpFlightBookings(bookings2, 2)); + Assertions.assertArrayEquals(new int[] { 10, 25 }, s.corpFlightBookings(bookings2, 2)); } - public static int[] corpFlightBookings(int[][] bookings, int n) { - int[] array = new int[n]; - for (int[] order : bookings) { - int left = order[0], right = order[1], num = order[2]; - array[left - 1] += num; - if (right < n) { - array[right] -= num; + static class Solution { + + public int[] corpFlightBookings(int[][] bookings, int n) { + // nums 初始化为全 0 + int[] nums = new int[n]; + // 构造差分解法 + Difference df = new Difference(nums); + + for (int[] booking : bookings) { + // 注意转成数组索引要减一哦 + int i = booking[0] - 1; + int j = booking[1] - 1; + int val = booking[2]; + // 对区间 nums[i..j] 增加 val + df.increment(i, j, val); } - // System.out.println("array: " + JSONUtil.toJsonStr(array)); + // 返回最终的结果数组 + return df.result(); } - int[] result = new int[n]; - result[0] = array[0]; - for (int i = 1; i < n; i++) { - result[i] = array[i] + result[i - 1]; + + // 差分数组工具类 + static class Difference { + + // 差分数组 + private final int[] diff; + + // 输入一个初始数组,区间操作将在这个数组上进行 + public Difference(int[] nums) { + assert nums.length > 0; + diff = new int[nums.length]; + // 根据初始数组构造差分数组 + diff[0] = nums[0]; + for (int i = 1; i < nums.length; i++) { + diff[i] = nums[i] - nums[i - 1]; + } + } + + // 给闭区间 [i, j] 增加 val(可以是负数) + public void increment(int i, int j, int val) { + diff[i] += val; + if (j + 1 < diff.length) { + diff[j + 1] -= val; + } + } + + // 返回结果数组 + public int[] result() { + int[] res = new int[diff.length]; + // 根据差分数组构造结果数组 + res[0] = diff[0]; + for (int i = 1; i < diff.length; i++) { + res[i] = res[i - 1] + diff[i]; + } + return res; + } + } - // System.out.println("result: " + JSONUtil.toJsonStr(result)); - return result; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" similarity index 95% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" index d59ac4e..7c37f55 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.array.range; +package io.github.dunwu.algorithm.array.template; /** * 前缀和数组代码模板 @@ -14,7 +14,7 @@ public class 前缀和数组代码模板 { static class NumArray { // 前缀和数组 - private int[] preSum; + private final int[] preSum; // 输入一个数组,构造前缀和 public NumArray(int[] nums) { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" similarity index 93% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" index 76d7295..bb6a01c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.array.range; +package io.github.dunwu.algorithm.array.template; /** * 差分数组代码模板 @@ -12,7 +12,7 @@ public class 差分数组代码模板 { static class Difference { // 差分数组 - private int[] diff; + private final int[] diff; // 输入一个初始数组,区间操作将在这个数组上进行 public Difference(int[] nums) { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" index 9ab9ae6..1e7c9e1 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" @@ -1,6 +1,5 @@ package io.github.dunwu.algorithm.array.two_pointer; -import cn.hutool.json.JSONUtil; import org.junit.jupiter.api.Assertions; import java.util.ArrayList; @@ -39,6 +38,10 @@ public static void main(String[] args) { Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, res3.get(0).toArray(new Integer[0])); Assertions.assertArrayEquals(new Integer[] { 4, 5, 6 }, res3.get(1).toArray(new Integer[0])); Assertions.assertArrayEquals(new Integer[] { 7, 8, 9 }, res3.get(2).toArray(new Integer[0])); + + int[][] grid4 = new int[][] { { 1 }, { 2 }, { 3 }, { 4 }, { 7 }, { 6 }, { 5 } }; + List> res4 = s.shiftGrid(grid4, 23); + Assertions.assertNotNull(res4); } static class Solution { @@ -46,15 +49,16 @@ static class Solution { public List> shiftGrid(int[][] grid, int k) { for (int i = 0; i < k; i++) { shift(grid); - // System.out.println("grid = " + JSONUtil.toJsonPrettyStr(grid)); } + + int m = grid.length, n = grid[0].length; List> res = new ArrayList<>(); - for (int i = 0; i < grid.length; i++) { + for (int i = 0; i < m; i++) { List list = new ArrayList<>(); - for (int j = 0; j < grid[0].length; j++) { + res.add(list); + for (int j = 0; j < n; j++) { list.add(grid[i][j]); } - res.add(list); } return res; } @@ -69,18 +73,18 @@ public void shift(int[][] grid) { set(grid, 0, last); } - public void set(int[][] grid, int index, int val) { - int m = grid.length, n = grid[0].length; + public int get(int[][] grid, int index) { + int n = grid[0].length; int i = index / n; int j = index % n; - grid[i][j] = val; + return grid[i][j]; } - public int get(int[][] grid, int index) { - int m = grid.length, n = grid[0].length; + public void set(int[][] grid, int index, int val) { + int n = grid[0].length; int i = index / n; int j = index % n; - return grid[i][j]; + grid[i][j] = val; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" index 74eef85..4914245 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" @@ -11,31 +11,39 @@ public class 乘积小于K的子数组 { public static void main(String[] args) { - Assertions.assertEquals(8, numSubarrayProductLessThanK(new int[] { 10, 5, 2, 6 }, 100)); - Assertions.assertEquals(0, numSubarrayProductLessThanK(new int[] { 1, 2, 3 }, 0)); + Solution s = new Solution(); + Assertions.assertEquals(8, s.numSubarrayProductLessThanK(new int[] { 10, 5, 2, 6 }, 100)); + Assertions.assertEquals(0, s.numSubarrayProductLessThanK(new int[] { 1, 2, 3 }, 0)); } - public static int numSubarrayProductLessThanK(int[] nums, int k) { - if (k <= 1) return 0; - - // 窗口游标 - int left = 0, right = 0; - // 窗口乘积 - int multi = 1; - // 符合要求的结果 - int result = 0; - while (right < nums.length) { - // 扩大窗口 - multi *= nums[right++]; - - while (multi >= k && left < right) { - multi = multi / nums[left++]; + static class Solution { + + public int numSubarrayProductLessThanK(int[] nums, int k) { + int left = 0, right = 0; + // 滑动窗口,初始化为乘法单位元 + int windowProduct = 1; + // 记录符合条件的子数组个数 + int count = 0; + + while (right < nums.length) { + // 扩大窗口,并更新窗口数据 + windowProduct = windowProduct * nums[right]; + right++; + + while (left < right && windowProduct >= k) { + // 缩小窗口,并更新窗口数据 + windowProduct = windowProduct / nums[left]; + left++; + } + // 现在必然是一个合法的窗口,但注意思考这个窗口中的子数组个数怎么计算: + // 比方说 left = 1, right = 4 划定了 [1, 2, 3] 这个窗口(right 是开区间) + // 但不止 [left..right] 是合法的子数组,[left+1..right], [left+2..right] 等都是合法子数组 + // 所以我们需要把 [3], [2,3], [1,2,3] 这 right - left 个子数组都加上 + count += right - left; } - - result += right - left; - // System.out.format("left: %d, right: %d\n", left, right); + return count; } - return result; + } -} +} \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" index 71601db..8bf319d 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" @@ -14,22 +14,25 @@ public class 存在重复元素 { public static void main(String[] args) { - Assertions.assertTrue(containsDuplicate(new int[] { 1, 2, 3, 1 })); - Assertions.assertFalse(containsDuplicate(new int[] { 1, 2, 3, 4 })); - Assertions.assertTrue(containsDuplicate(new int[] { 1, 1, 1, 3, 3, 4, 3, 2, 4, 2 })); + Solution s = new Solution(); + Assertions.assertTrue(s.containsDuplicate(new int[] { 1, 2, 3, 1 })); + Assertions.assertFalse(s.containsDuplicate(new int[] { 1, 2, 3, 4 })); + Assertions.assertTrue(s.containsDuplicate(new int[] { 1, 1, 1, 3, 3, 4, 3, 2, 4, 2 })); } - public static boolean containsDuplicate(int[] nums) { - if (nums == null || nums.length <= 1) { - return false; - } - Set set = new HashSet<>(); - for (int num : nums) { - if (!set.add(num)) { - return true; + static class Solution { + + public boolean containsDuplicate(int[] nums) { + Set set = new HashSet<>(); + for (int num : nums) { + if (set.contains(num)) { + return true; + } + set.add(num); } + return false; } - return false; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2402.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2402.java" new file mode 100644 index 0000000..067485a --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2402.java" @@ -0,0 +1,46 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashSet; +import java.util.Set; + +/** + * 219. 存在重复元素 II + * + * @author Zhang Peng + * @date 2025-10-15 + */ +public class 存在重复元素2 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.containsNearbyDuplicate(new int[] { 1, 2, 3, 1 }, 3)); + Assertions.assertTrue(s.containsNearbyDuplicate(new int[] { 1, 0, 1, 1 }, 1)); + Assertions.assertFalse(s.containsNearbyDuplicate(new int[] { 1, 2, 3, 1, 2, 3 }, 2)); + Assertions.assertTrue(s.containsNearbyDuplicate(new int[] { 99, 99 }, 2)); + } + + static class Solution { + + public boolean containsNearbyDuplicate(int[] nums, int k) { + int left = 0, right = 0; + Set set = new HashSet<>(); + while (right < nums.length) { + if (set.contains(nums[right])) { + return true; + } + set.add(nums[right]); + right++; + + if (right - left > k) { + set.remove(nums[left]); + left++; + } + } + return false; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2403.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2403.java" new file mode 100644 index 0000000..8265957 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2403.java" @@ -0,0 +1,55 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +import java.util.TreeSet; + +/** + * 220. 存在重复元素 III + * + * @author Zhang Peng + * @date 2025-10-15 + */ +public class 存在重复元素3 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.containsNearbyAlmostDuplicate(new int[] { 1, 2, 3, 1 }, 3, 0)); + Assertions.assertFalse(s.containsNearbyAlmostDuplicate(new int[] { 1, 5, 9, 1, 5, 9 }, 2, 3)); + Assertions.assertTrue(s.containsNearbyAlmostDuplicate(new int[] { 1, 2, 2, 3, 4, 5 }, 3, 0)); + } + + static class Solution { + + public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { + TreeSet window = new TreeSet<>(); + int left = 0, right = 0; + while (right < nums.length) { + // 为了防止 i == j,所以在扩大窗口之前先判断是否有符合题意的索引对 (i, j) + // 查找略大于 nums[right] 的那个元素 + Integer ceiling = window.ceiling(nums[right]); + if (ceiling != null && (long) ceiling - nums[right] <= t) { + return true; + } + // 查找略小于 nums[right] 的那个元素 + Integer floor = window.floor(nums[right]); + if (floor != null && (long) nums[right] - floor <= t) { + return true; + } + + // 扩大窗口 + window.add(nums[right]); + right++; + + if (right - left > k) { + // 缩小窗口 + window.remove(nums[left]); + left++; + } + } + return false; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240II.java" deleted file mode 100644 index 0791392..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240II.java" +++ /dev/null @@ -1,56 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashSet; -import java.util.Set; - -/** - * 219. 存在重复元素 II - * - * @author Zhang Peng - * @date 2025-10-15 - */ -public class 存在重复元素II { - - public static void main(String[] args) { - Assertions.assertTrue(containsNearbyDuplicate(new int[] { 1, 2, 3, 1 }, 3)); - Assertions.assertTrue(containsNearbyDuplicate(new int[] { 1, 0, 1, 1 }, 1)); - Assertions.assertFalse(containsNearbyDuplicate(new int[] { 1, 2, 3, 1, 2, 3 }, 2)); - Assertions.assertTrue(containsNearbyDuplicate(new int[] { 99, 99 }, 2)); - } - - public static boolean containsNearbyDuplicate(int[] nums, int k) { - if (nums == null || nums.length < 2) return false; - int left = 0, right = 0; - Set set = new HashSet<>(); - while (right < nums.length) { - if (!set.add(nums[right])) { - return true; - } - right++; - - if (right - left > k) { - set.remove(nums[left]); - left++; - } - } - return false; - } - - /** - * 效率为 O(N^2) - */ - public static boolean containsNearbyDuplicate2(int[] nums, int k) { - if (nums == null || nums.length < 2) return false; - for (int i = 0; i < nums.length; i++) { - for (int j = i + 1; j < nums.length; j++) { - if (nums[i] == nums[j] && Math.abs(j - i) <= k) { - return true; - } - } - } - return false; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240III.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240III.java" deleted file mode 100644 index 1ea0044..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240III.java" +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -import java.util.TreeSet; - -/** - * 220. 存在重复元素 III - * - * @author Zhang Peng - * @date 2025-10-15 - */ -public class 存在重复元素III { - - public static void main(String[] args) { - Assertions.assertTrue(containsNearbyAlmostDuplicate(new int[] { 1, 2, 3, 1 }, 3, 0)); - Assertions.assertFalse(containsNearbyAlmostDuplicate(new int[] { 1, 5, 9, 1, 5, 9 }, 2, 3)); - Assertions.assertTrue(containsNearbyAlmostDuplicate(new int[] { 1, 2, 2, 3, 4, 5 }, 3, 0)); - } - - public static boolean containsNearbyAlmostDuplicate(int[] nums, int indexDiff, int valueDiff) { - TreeSet window = new TreeSet<>(); - int left = 0, right = 0; - while (right < nums.length) { - - // 窗口大小小于等于 indexDiff,且窗口中存在两个不同元素之差小于 valueDiff - - // 为了防止 i == j,所以在扩大窗口之前先判断是否有符合题意的索引对 (i, j) - // 查找略大于 nums[right] 的那个元素 - Integer ceiling = window.ceiling(nums[right]); - if (ceiling != null && Math.abs(ceiling - nums[right]) <= valueDiff) { - return true; - } - // 查找略小于 nums[right] 的那个元素 - Integer floor = window.floor(nums[right]); - if (floor != null && Math.abs(floor - nums[right]) <= valueDiff) { - return true; - } - - // 当窗口大小小于等于 indexDiff 时,扩大窗口 - window.add(nums[right++]); - - // 当窗口大小大于 indexDiff 时,缩小窗口 - while (right - left > indexDiff) { - // 缩小窗口 - window.remove(nums[left++]); - } - } - return false; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" index ebf048c..e03b04f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" @@ -21,8 +21,8 @@ static class Solution { public int minOperations(int[] nums, int x) { int n = nums.length, sum = 0; - for (int num : nums) { - sum += num; + for (int i = 0; i < n; i++) { + sum += nums[i]; } // 滑动窗口需要寻找的子数组目标和 int target = sum - x; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" index 68c8a3a..aeef632 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" @@ -2,8 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.HashMap; - /** * 424. 替换后的最长重复字符 * @@ -13,32 +11,37 @@ public class 替换后的最长重复字符 { public static void main(String[] args) { - Assertions.assertEquals(4, characterReplacement("ABAB", 2)); - Assertions.assertEquals(4, characterReplacement("AABABBA", 1)); - Assertions.assertEquals(4, characterReplacement("AAAA", 2)); + Solution s = new Solution(); + Assertions.assertEquals(4, s.characterReplacement("ABAB", 2)); + Assertions.assertEquals(4, s.characterReplacement("AABABBA", 1)); + Assertions.assertEquals(4, s.characterReplacement("AAAA", 2)); } - public static int characterReplacement(String s, int k) { - int result = 0; - int left = 0, right = 0; - int windowMaxCnt = 0; - HashMap map = new HashMap<>(26); - while (right < s.length()) { - char r = s.charAt(right); - right++; + static class Solution { + + public int characterReplacement(String s, int k) { - map.put(r, map.getOrDefault(r, 0) + 1); - windowMaxCnt = Math.max(windowMaxCnt, map.get(r)); + int res = 0; + int windowMaxCount = 0; + int left = 0, right = 0; + int[] windowCount = new int[26]; + while (right < s.length()) { + int c = s.charAt(right) - 'A'; + windowCount[c]++; + windowMaxCount = Math.max(windowMaxCount, windowCount[c]); + right++; - while (right - left - windowMaxCnt > k) { - char l = s.charAt(left); - left++; + while (right - left - windowMaxCount > k) { + int d = s.charAt(left) - 'A'; + windowCount[d]--; + left++; + } - map.put(l, map.get(l) - 1); + res = Math.max(res, right - left); } - result = Math.max(result, right - left); + return res; } - return result; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\2603.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\2603.java" new file mode 100644 index 0000000..531e688 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\2603.java" @@ -0,0 +1,40 @@ +package io.github.dunwu.algorithm.array.window; + +import org.junit.jupiter.api.Assertions; + +/** + * 1004. 最大连续1的个数 III + * + * @author Zhang Peng + * @date 2025-10-14 + */ +public class 最大连续1的个数3 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(6, s.longestOnes(new int[] { 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0 }, 2)); + Assertions.assertEquals(10, + s.longestOnes(new int[] { 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1 }, 3)); + } + + static class Solution { + + public int longestOnes(int[] nums, int k) { + int cnt = 0, len = 0; + int left = 0, right = 0; + while (right < nums.length) { + if (nums[right] == 0) { cnt++; } + right++; + + while (cnt > k) { + if (nums[left] == 0) { cnt--; } + left++; + } + len = Math.max(len, right - left); + } + return len; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260III.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260III.java" deleted file mode 100644 index 0a2fe04..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260III.java" +++ /dev/null @@ -1,39 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -/** - * 1004. 最大连续1的个数 III - * - * @author Zhang Peng - * @date 2025-10-14 - */ -public class 最大连续1的个数III { - - public static void main(String[] args) { - Assertions.assertEquals(6, longestOnes(new int[] { 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0 }, 2)); - Assertions.assertEquals(10, - longestOnes(new int[] { 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1 }, 3)); - } - - public static int longestOnes(int[] nums, int k) { - int max = 0; - int zeroCnt = 0; - int left = 0, right = 0; - while (right < nums.length) { - int r = nums[right]; - right++; - if (r == 0) zeroCnt++; - - while (zeroCnt > k) { - int l = nums[left]; - left++; - if (l == 0) zeroCnt--; - } - - max = Math.max(max, right - left); - } - return max; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" index f96bd68..3fbba47 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" @@ -12,68 +12,74 @@ public class 至少有K个重复字符的最长子串 { public static void main(String[] args) { - Assertions.assertEquals(3, longestSubstring("aaabb", 3)); - Assertions.assertEquals(5, longestSubstring("ababbc", 2)); + Solution s = new Solution(); + Assertions.assertEquals(3, s.longestSubstring("aaabb", 3)); + Assertions.assertEquals(5, s.longestSubstring("ababbc", 2)); + Assertions.assertEquals(6, s.longestSubstring("aaabbb", 3)); } - public static int longestSubstring(String s, int k) { - int len = 0; - for (int i = 1; i <= 26; i++) { - // 限制窗口中只能有 i 种不同字符 - len = Math.max(len, kLetterLongestSubstring(s, k, i)); - } - return len; - } + public static class Solution { - // 寻找 s 中含有 count 种字符,且每种字符出现次数都大于 k 的子串 - static int kLetterLongestSubstring(String s, int k, int count) { - // 记录答案 - int res = 0; - // 快慢指针维护滑动窗口,左闭右开区间 - int left = 0, right = 0; - // 题目说 s 中只有小写字母,所以用大小 26 的数组记录窗口中字符出现的次数 - int[] windowCount = new int[26]; - // 记录窗口中存在几种不同的字符(字符种类) - int windowUniqueCount = 0; - // 记录窗口中有几种字符的出现次数达标(大于等于 k) - int windowValidCount = 0; - // 滑动窗口代码模板 - while (right < s.length()) { - // 移入字符,扩大窗口 - char c = s.charAt(right); - if (windowCount[c - 'a'] == 0) { - // 窗口中新增了一种字符 - windowUniqueCount++; - } - windowCount[c - 'a']++; - if (windowCount[c - 'a'] == k) { - // 窗口中新增了一种达标的字符 - windowValidCount++; + public int longestSubstring(String s, int k) { + int len = 0; + for (int i = 1; i <= 26; i++) { + // 限制窗口中只能有 i 种不同字符 + len = Math.max(len, logestKLetterSubstr(s, k, i)); } - right++; + return len; + } - // 当窗口中字符种类大于 count 时,缩小窗口 - while (windowUniqueCount > count) { - // 移出字符,缩小窗口 - char d = s.charAt(left); - if (windowCount[d - 'a'] == k) { - // 窗口中减少了一种达标的字符 - windowValidCount--; + // 寻找 s 中含有 count 种字符,且每种字符出现次数都大于 k 的子串 + int logestKLetterSubstr(String s, int k, int count) { + // 记录答案 + int res = 0; + // 快慢指针维护滑动窗口,左闭右开区间 + int left = 0, right = 0; + // 题目说 s 中只有小写字母,所以用大小 26 的数组记录窗口中字符出现的次数 + int[] windowCount = new int[26]; + // 记录窗口中存在几种不同的字符(字符种类) + int windowUniqueCount = 0; + // 记录窗口中有几种字符的出现次数达标(大于等于 k) + int windowValidCount = 0; + // 滑动窗口代码模板 + while (right < s.length()) { + // 移入字符,扩大窗口 + char c = s.charAt(right); + if (windowCount[c - 'a'] == 0) { + // 窗口中新增了一种字符 + windowUniqueCount++; } - windowCount[d - 'a']--; - if (windowCount[d - 'a'] == 0) { - // 窗口中减少了一种字符 - windowUniqueCount--; + windowCount[c - 'a']++; + if (windowCount[c - 'a'] == k) { + // 窗口中新增了一种达标的字符 + windowValidCount++; } - left++; - } + right++; - // 当窗口中字符种类为 count 且每个字符出现次数都满足 k 时,更新答案 - if (windowValidCount == count) { - res = Math.max(res, right - left); + // 当窗口中字符种类大于 count 时,缩小窗口 + while (windowUniqueCount > count) { + // 移出字符,缩小窗口 + char d = s.charAt(left); + if (windowCount[d - 'a'] == k) { + // 窗口中减少了一种达标的字符 + windowValidCount--; + } + windowCount[d - 'a']--; + if (windowCount[d - 'a'] == 0) { + // 窗口中减少了一种字符 + windowUniqueCount--; + } + left++; + } + + // 当窗口中字符种类为 count 且每个字符出现次数都满足 k 时,更新答案 + if (windowValidCount == count) { + res = Math.max(res, right - left); + } } + return res; } - return res; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" index 2baccd8..b636134 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" @@ -11,32 +11,34 @@ public class 长度最小的子数组 { public static void main(String[] args) { - Assertions.assertEquals(2, minSubArrayLen(7, new int[] { 2, 3, 1, 2, 4, 3 })); - Assertions.assertEquals(1, minSubArrayLen(4, new int[] { 1, 4, 4 })); - Assertions.assertEquals(0, minSubArrayLen(11, new int[] { 1, 1, 1, 1, 1, 1, 1, 1 })); + Solution s = new Solution(); + Assertions.assertEquals(2, s.minSubArrayLen(7, new int[] { 2, 3, 1, 2, 4, 3 })); + Assertions.assertEquals(1, s.minSubArrayLen(4, new int[] { 1, 4, 4 })); + Assertions.assertEquals(0, s.minSubArrayLen(11, new int[] { 1, 1, 1, 1, 1, 1, 1, 1 })); } - public static int minSubArrayLen(int target, int[] nums) { - // System.out.println("================================"); - int sum = 0; - int minSize = Integer.MAX_VALUE; - int left = 0, right = 0; - while (right < nums.length) { - - // sum 小于 target 扩大窗口 - sum += nums[right++]; - - // sum 大于等于 target 扩大窗口 - while (sum >= target) { - minSize = Math.min(minSize, right - left); - // System.out.format("left: %d, right: %d, minSize: %d, sum: %d\n", - // left, right, minSize, sum); - - sum -= nums[left]; - left++; + public static class Solution { + + public int minSubArrayLen(int target, int[] nums) { + int left = 0, right = 0; + // 维护窗口内元素之和 + int windowSum = 0; + int res = Integer.MAX_VALUE; + + while (right < nums.length) { + // 扩大窗口 + windowSum += nums[right]; + right++; + while (windowSum >= target && left < right) { + // 已经达到 target,缩小窗口,同时更新答案 + res = Math.min(res, right - left); + windowSum -= nums[left]; + left++; + } } + return res == Integer.MAX_VALUE ? 0 : res; } - return minSize == Integer.MAX_VALUE ? 0 : minSize; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" index b38cb51..b11e735 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" @@ -1,11 +1,8 @@ package io.github.dunwu.algorithm.bfs; -import org.junit.jupiter.api.Assertions; - import java.util.Arrays; import java.util.LinkedList; import java.util.List; -import java.util.Queue; /** * 721. 账户合并 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" index aa8556c..99ead5c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" @@ -2,9 +2,7 @@ import org.junit.jupiter.api.Assertions; -import java.util.HashSet; import java.util.LinkedList; -import java.util.Set; /** * 1926. 迷宫中离入口最近的出口 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/LRU\347\274\223\345\255\230.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/LRU\347\274\223\345\255\230.java" similarity index 97% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/LRU\347\274\223\345\255\230.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/LRU\347\274\223\345\255\230.java" index f716636..7d4ebd1 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/LRU\347\274\223\345\255\230.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/LRU\347\274\223\345\255\230.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.data_structure; +package io.github.dunwu.algorithm.design; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" similarity index 98% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" index bf9bc63..67de9b1 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue_and_stack; +package io.github.dunwu.algorithm.design; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" similarity index 94% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" index 04461e7..6fe15e1 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" @@ -1,6 +1,5 @@ -package io.github.dunwu.algorithm.queue_and_stack; +package io.github.dunwu.algorithm.design; -import io.github.dunwu.algorithm.queue_and_stack.stack.GenericStack; import org.junit.jupiter.api.Assertions; import java.util.Stack; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" similarity index 95% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" index 6ffed58..58424c4 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.data_structure; +package io.github.dunwu.algorithm.design; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" similarity index 95% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" index 3c5631d..e1f68e8 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.data_structure; +package io.github.dunwu.algorithm.design; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" similarity index 95% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" index dce18d0..2f0b46d 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" @@ -1,8 +1,7 @@ -package io.github.dunwu.algorithm.data_structure; +package io.github.dunwu.algorithm.design; import org.junit.jupiter.api.Assertions; -import java.util.Arrays; import java.util.LinkedList; /** diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\350\256\241\347\256\227\345\231\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\350\256\241\347\256\227\345\231\250.java" similarity index 92% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\350\256\241\347\256\227\345\231\250.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\350\256\241\347\256\227\345\231\250.java" index 51b5b65..5e32109 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/data_structure/\350\256\241\347\256\227\345\231\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\350\256\241\347\256\227\345\231\250.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.data_structure; +package io.github.dunwu.algorithm.design; import java.util.Arrays; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/recursive/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" similarity index 95% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/recursive/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" index 06cd60a..9799f09 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/recursive/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.recursive; +package io.github.dunwu.algorithm.dfs; import org.junit.jupiter.api.Assertions; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" index 046d441..b20d79b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" @@ -2,8 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.Arrays; - /** * 64. 最小路径和 * diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204\345\222\214.java" index c606944..e7af1a6 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204\345\222\214.java" @@ -2,8 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.Arrays; - /** * 53. 最大子数组和 * diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\2422.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\2422.java" index 079c629..c0b0b76 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\2422.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\2422.java" @@ -2,8 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.Arrays; - /** * 518. 零钱兑换 II * diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" index 20e419f..80aec10 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" @@ -1,7 +1,7 @@ package io.github.dunwu.algorithm.graph.template; -import io.github.dunwu.algorithm.tree.Node; import io.github.dunwu.algorithm.graph.Vertex; +import io.github.dunwu.algorithm.tree.Node; /** * DFS遍历图的所有边 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" index ad8e078..4324c62 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" @@ -2,10 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - /** * 785. 判断二分图 * diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hashtable/JewelsAndStones.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/JewelsAndStones.java similarity index 96% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/hashtable/JewelsAndStones.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/JewelsAndStones.java index 788329f..57f5933 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hashtable/JewelsAndStones.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/JewelsAndStones.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.hashtable; +package io.github.dunwu.algorithm.hash; import java.util.HashSet; diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hashtable/SubdomainVisitCount.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/SubdomainVisitCount.java similarity index 98% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/hashtable/SubdomainVisitCount.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/SubdomainVisitCount.java index 2497364..7d7f733 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hashtable/SubdomainVisitCount.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/SubdomainVisitCount.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.hashtable; +package io.github.dunwu.algorithm.hash; import java.util.ArrayList; import java.util.HashMap; diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hashtable/ToLowerCase.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/ToLowerCase.java similarity index 95% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/hashtable/ToLowerCase.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/ToLowerCase.java index 885f1df..97af3d7 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hashtable/ToLowerCase.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/ToLowerCase.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.hashtable; +package io.github.dunwu.algorithm.hash; /* https://leetcode.com/problems/to-lower-case/ diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" index 7c45670..2f2e6e7 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" @@ -13,33 +13,48 @@ public class 回文链表 { public static void main(String[] args) { + Solution s = new Solution(); ListNode head = ListNode.buildList(1, 2, 2, 1); - Assertions.assertTrue(isPalindrome(head)); + Assertions.assertTrue(s.isPalindrome(head)); - head = ListNode.buildList(1, 2); - Assertions.assertFalse(isPalindrome(head)); + ListNode input2 = ListNode.buildList(1, 2); + Assertions.assertFalse(s.isPalindrome(input2)); } - public static boolean isPalindrome(ListNode list) { - ListNode rlist = reverse(list); - ListNode p = list, q = rlist; - while (p != null && q != null) { - if (p.val != q.val) { - return false; + static class Solution { + + public boolean isPalindrome(ListNode head) { + ListNode slow, fast; + slow = fast = head; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + } + + if (fast != null) { slow = slow.next; } + + ListNode left = head; + ListNode right = reverse(slow); + while (right != null) { + if (left.val != right.val) { return false; } + left = left.next; + right = right.next; } - p = p.next; - q = q.next; + + return true; } - return true; - } - static ListNode reverse(ListNode head) { - if (head == null || head.next == null) return head; + ListNode reverse(ListNode head) { + ListNode pre = null, cur = head; + while (cur != null) { + ListNode next = cur.next; + cur.next = pre; + pre = cur; + cur = next; + } + return pre; + } - ListNode last = reverse(head.next); - head.next.next = head; - head.next = null; - return last; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\2502.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\2502.java" index 286c941..74aca5d 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\2502.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\2502.java" @@ -21,36 +21,40 @@ public static void main(String[] args) { static class Solution { - public ListNode reverseBetween(ListNode head, int left, int right) { - if (left == 1) { - return reverseN(head, right); + public ListNode reverseBetween(ListNode head, int m, int n) { + if (m == 1) { + return reverseN(head, n); } - - // 找到第 left 个节点的前驱 + // 找到第 m 个节点的前驱 ListNode pre = head; - for (int i = 1; i < left - 1; i++) { + for (int i = 1; i < m - 1; i++) { pre = pre.next; } - - // 从第 left 个节点开始反转 - int len = right - left + 1; - pre.next = reverseN(pre.next, len); - return pre; + // 从第 m 个节点开始反转 + pre.next = reverseN(pre.next, n - m + 1); + return head; } - private ListNode reverseN(ListNode head, int len) { - if (head == null || head.next == null) { return head; } - ListNode pre = null, cur = head, next = cur.next; - while (len-- > 0) { + ListNode reverseN(ListNode head, int n) { + if (head == null || head.next == null) { + return head; + } + ListNode pre, cur, nxt; + pre = null; + cur = head; + nxt = head.next; + while (n > 0) { cur.next = pre; pre = cur; - cur = next; - if (next != null) { - next = next.next; + cur = nxt; + if (nxt != null) { + nxt = nxt.next; } + n--; } // 此时的 cur 是第 n + 1 个节点,head 是反转后的尾结点 head.next = cur; + // 此时的 pre 是反转后的头结点 return pre; } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/GenericQueue.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/GenericQueue.java similarity index 95% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/GenericQueue.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/GenericQueue.java index 9f63e2d..f75c96b 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/GenericQueue.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/GenericQueue.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue_and_stack.queue; +package io.github.dunwu.algorithm.queue; /** * @author Zhang Peng diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" index eb5fed7..f476f99 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue_and_stack.queue; +package io.github.dunwu.algorithm.queue.demo; import java.util.Arrays; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" index 83d7a97..0e321f7 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue_and_stack.queue; +package io.github.dunwu.algorithm.queue.demo; /** * 用数组实现的队列 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" index 3df21c2..3117ad2 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue_and_stack.queue; +package io.github.dunwu.algorithm.queue.demo; /** * 基于链表实现的队列 diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/MonotonicQueue.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/MonotonicQueue.java new file mode 100644 index 0000000..a13cdb2 --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/MonotonicQueue.java @@ -0,0 +1,66 @@ +package io.github.dunwu.algorithm.queue.monotonic; + +import java.util.LinkedList; + +// 单调队列的实现,可以高效维护最大值和最小值 +class MonotonicQueue> { + + // 常规队列,存储所有元素 + LinkedList q = new LinkedList<>(); + // 元素降序排列的单调队列,头部是最大值 + LinkedList maxq = new LinkedList<>(); + // 元素升序排列的单调队列,头部是最小值 + LinkedList minq = new LinkedList<>(); + + public void push(E elem) { + // 维护常规队列,直接在队尾插入元素 + q.addLast(elem); + + // 维护 maxq,将小于 elem 的元素全部删除 + while (!maxq.isEmpty() && maxq.getLast().compareTo(elem) < 0) { + maxq.pollLast(); + } + maxq.addLast(elem); + + // 维护 minq,将大于 elem 的元素全部删除 + while (!minq.isEmpty() && minq.getLast().compareTo(elem) > 0) { + minq.pollLast(); + } + minq.addLast(elem); + } + + public E max() { + // maxq 的头部是最大元素 + return maxq.getFirst(); + } + + public E min() { + // minq 的头部是最大元素 + return minq.getFirst(); + } + + public E pop() { + // 从标准队列头部弹出需要删除的元素 + E deleteVal = q.pollFirst(); + assert deleteVal != null; + + // 由于 push 的时候会删除元素,deleteVal 可能已经被删掉了 + if (deleteVal.equals(maxq.getFirst())) { + maxq.pollFirst(); + } + if (deleteVal.equals(minq.getFirst())) { + minq.pollFirst(); + } + return deleteVal; + } + + public int size() { + // 标准队列的大小即是当前队列的大小 + return q.size(); + } + + public boolean isEmpty() { + return q.isEmpty(); + } + +} \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/\346\273\221\345\212\250\347\252\227\345\217\243\346\234\200\345\244\247\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/\346\273\221\345\212\250\347\252\227\345\217\243\346\234\200\345\244\247\345\200\274.java" new file mode 100644 index 0000000..3b9aaf2 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/\346\273\221\345\212\250\347\252\227\345\217\243\346\234\200\345\244\247\345\200\274.java" @@ -0,0 +1,74 @@ +package io.github.dunwu.algorithm.queue.monotonic; + +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * 239. 滑动窗口最大值 + * + * @author Zhang Peng + * @date 2025-11-26 + */ +public class 滑动窗口最大值 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new int[] { 3, 3, 5, 5, 6, 7 }, + s.maxSlidingWindow(new int[] { 1, 3, -1, -3, 5, 3, 6, 7 }, 3)); + Assertions.assertArrayEquals(new int[] { 1 }, s.maxSlidingWindow(new int[] { 1 }, 1)); + } + + static class Solution { + + public int[] maxSlidingWindow(int[] nums, int k) { + MonotonicQueue window = new MonotonicQueue(); + List res = new ArrayList<>(); + + for (int i = 0; i < nums.length; i++) { + if (i < k - 1) { + window.push(nums[i]); + } else { + window.push(nums[i]); + res.add(window.max()); + window.pop(nums[i - (k - 1)]); + } + } + + int[] arr = new int[res.size()]; + for (int i = 0; i < res.size(); i++) { + arr[i] = res.get(i); + } + return arr; + } + + static class MonotonicQueue { + + LinkedList q = new LinkedList<>(); + + public void push(int n) { + // 将小于 n 的元素全部删除 + while (!q.isEmpty() && q.getLast() < n) { + q.pollLast(); + } + // 然后将 n 加入尾部 + q.addLast(n); + } + + public int max() { + return q.getFirst(); + } + + public void pop(int n) { + if (n == q.getFirst()) { + q.pollFirst(); + } + } + + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/\350\256\276\350\256\241\350\207\252\345\212\251\347\273\223\347\256\227\347\263\273\347\273\237.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/\350\256\276\350\256\241\350\207\252\345\212\251\347\273\223\347\256\227\347\263\273\347\273\237.java" new file mode 100644 index 0000000..69586cd --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/\350\256\276\350\256\241\350\207\252\345\212\251\347\273\223\347\256\227\347\263\273\347\273\237.java" @@ -0,0 +1,44 @@ +package io.github.dunwu.algorithm.queue.monotonic; + +import org.junit.jupiter.api.Assertions; + +/** + * 739. 每日温度 + * + * @author Zhang Peng + * @date 2025-11-26 + */ +public class 设计自助结算系统 { + + public static void main(String[] args) { + Checkout c = new Checkout(); + c.add(4); + c.add(7); + Assertions.assertEquals(7, c.get_max()); + Assertions.assertEquals(4, c.remove()); + Assertions.assertEquals(7, c.get_max()); + } + + static class Checkout { + + private MonotonicQueue q; + public Checkout() { + q = new MonotonicQueue<>(); + } + + public int get_max() { + return q.isEmpty() ? -1 : q.max(); + } + + public void add(int value) { + q.push(value); + } + + public int remove() { + if (q.isEmpty()) { return -1; } + return q.pop(); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\344\271\260\347\245\250\351\234\200\350\246\201\347\232\204\346\227\266\351\227\264.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\344\271\260\347\245\250\351\234\200\350\246\201\347\232\204\346\227\266\351\227\264.java" new file mode 100644 index 0000000..e350c5c --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\344\271\260\347\245\250\351\234\200\350\246\201\347\232\204\346\227\266\351\227\264.java" @@ -0,0 +1,36 @@ +package io.github.dunwu.algorithm.queue; + +import org.junit.jupiter.api.Assertions; + +/** + * 2073. 买票需要的时间 + * + * @author Zhang Peng + * @since 2025-11-26 + */ +public class 买票需要的时间 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(6, s.timeRequiredToBuy(new int[] { 2, 3, 2 }, 2)); + Assertions.assertEquals(8, s.timeRequiredToBuy(new int[] { 5, 1, 1, 1 }, 0)); + } + + static class Solution { + + public int timeRequiredToBuy(int[] tickets, int k) { + int i = 0; + int seconds = 0; + while (tickets[k] != 0) { + if (tickets[i] != 0) { + tickets[i]--; + seconds++; + } + i = (i + 1) % tickets.length; + } + return seconds; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" similarity index 86% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" index 97ed853..00e74d9 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue_and_stack.queue; +package io.github.dunwu.algorithm.queue; import java.util.LinkedList; import java.util.Queue; @@ -21,7 +21,11 @@ public static void main(String[] args) { static class RecentCounter { - Queue queue = new LinkedList<>(); + private Queue queue; + + public RecentCounter() { + queue = new LinkedList<>(); + } public int ping(int t) { queue.offer(t); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" similarity index 96% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" index e5b036f..7628222 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue_and_stack; +package io.github.dunwu.algorithm.queue; import org.junit.jupiter.api.Assertions; diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/MyCircularDeque.java "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\256\276\350\256\241\345\276\252\347\216\257\345\217\214\347\253\257\351\230\237\345\210\227.java" similarity index 91% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/MyCircularDeque.java rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\256\276\350\256\241\345\276\252\347\216\257\345\217\214\347\253\257\351\230\237\345\210\227.java" index da96c42..1db2d49 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/queue/MyCircularDeque.java +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\256\276\350\256\241\345\276\252\347\216\257\345\217\214\347\253\257\351\230\237\345\210\227.java" @@ -1,14 +1,15 @@ -package io.github.dunwu.algorithm.queue_and_stack.queue; +package io.github.dunwu.algorithm.queue; /** + * 641. 设计循环双端队列 + * * @author Zhang Peng - * @see 641. 设计循环双端队列 * @since 2020-06-10 */ -public class MyCircularDeque { +public class 设计循环双端队列 { public static void main(String[] args) { - MyCircularDeque queue = new MyCircularDeque(3); + 设计循环双端队列 queue = new 设计循环双端队列(3); queue.insertFront(1); queue.insertFront(2); queue.insertFront(3); @@ -43,7 +44,7 @@ public static void main(String[] args) { private int capacity; /** Initialize your data structure here. Set the size of the deque to be k. */ - public MyCircularDeque(int k) { + public 设计循环双端队列(int k) { this.capacity = k + 1; this.data = new int[this.capacity]; } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/StackBasedOnLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/StackBasedOnLinkedList.java deleted file mode 100644 index 8f4ece3..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/StackBasedOnLinkedList.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.github.dunwu.algorithm.queue_and_stack; - -/** - * 基于链表实现的栈。 - *

- * Author: Zheng - */ -public class StackBasedOnLinkedList { - - public static void main(String[] args) { - StackBasedOnLinkedList stack = new StackBasedOnLinkedList(); - stack.push(1); - stack.push(2); - stack.push(3); - stack.printAll(); - System.out.println("pop " + stack.pop()); - System.out.println("pop " + stack.pop()); - System.out.println("pop " + stack.pop()); - } - - private Node top = null; - - public void push(int value) { - Node node = new Node(value, null); - if (top == null) { - top = node; - } else { - node.next = top; - top = node; - } - } - - /** - * 我用-1表示栈中没有数据。 - */ - public int pop() { - if (top == null) return -1; - int val = top.data; - top = top.next; - return val; - } - - public void printAll() { - Node p = top; - while (p != null) { - System.out.print(p.data + " "); - p = p.next; - } - System.out.println(); - } - - private static class Node { - - private int data; - private Node next; - - public Node(int data, Node next) { - this.data = data; - this.next = next; - } - - public int getData() { - return data; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" deleted file mode 100644 index 3486bc7..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" +++ /dev/null @@ -1,47 +0,0 @@ -package io.github.dunwu.algorithm.queue_and_stack.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Deque; -import java.util.LinkedList; -import java.util.Stack; - -/** - * 150. 逆波兰表达式求值 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 文件的最长绝对路径 { - - public static void main(String[] args) { - Assertions.assertEquals(20, lengthLongestPath("dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext")); - Assertions.assertEquals(32, lengthLongestPath( - "dir\\n\\tsubdir1\\n\\t\\tfile1.ext\\n\\t\\tsubsubdir1\\n\\tsubdir2\\n\\t\\tsubsubdir2\\n\\t\\t\\tfile2.ext")); - Assertions.assertEquals(0, lengthLongestPath("a")); - Assertions.assertEquals(12, lengthLongestPath("file1.txt\\nfile2.txt\\nlongfile.txt")); - } - - public static int lengthLongestPath(String input) { - // 这个栈存储之前的父路径。实际上这里只用存父路径的长度就够了,这个优化留给你吧 - Deque stack = new LinkedList<>(); - int maxLen = 0; - for (String part : input.split("\n")) { - int level = part.lastIndexOf("\t") + 1; - // 让栈中只保留当前目录的父路径 - while (level < stack.size()) { - stack.removeLast(); - } - stack.addLast(part.substring(level)); - // 如果是文件,就计算路径长度 - if (part.contains(".")) { - int sum = stack.stream().mapToInt(String::length).sum(); - // 加上父路径的分隔符 - sum += stack.size() - 1; - maxLen = Math.max(maxLen, sum); - } - } - return maxLen; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" deleted file mode 100644 index 1cdba8d..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" +++ /dev/null @@ -1,54 +0,0 @@ -package io.github.dunwu.algorithm.queue_and_stack.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 20. 有效的括号 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 有效的括号 { - - public static void main(String[] args) { - Assertions.assertTrue(isValid("()")); - Assertions.assertTrue(isValid("{[]}")); - Assertions.assertFalse(isValid("([)]")); - Assertions.assertFalse(isValid("([)")); - Assertions.assertFalse(isValid("((")); - Assertions.assertTrue(isValid("(())")); - } - - public static boolean isValid(String s) { - if (s == null || s.length() <= 1) { return false; } - Stack left = new Stack<>(); - for (char c : s.toCharArray()) { - if (c == '(' || c == '{' || c == '[') { - // 字符 c 是左括号,入栈 - left.push(c); - } else { - // 字符 c 是右括号 - if (!left.isEmpty() && left.peek() == leftChar(c)) { - left.pop(); - } else { - // 和最近的左括号不匹配 - return false; - } - } - } - // 是否还有左括号未匹配 - return left.isEmpty(); - } - - public static char leftChar(char c) { - if (c == ')') { - return '('; - } else if (c == '}') { - return '{'; - } - return '['; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" deleted file mode 100644 index 9bbf399..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" +++ /dev/null @@ -1,46 +0,0 @@ -package io.github.dunwu.algorithm.queue_and_stack.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 71. 简化路径 - * - * @author Zhang Peng - * @since 2025-08-08 - */ -public class 简化路径 { - - public static void main(String[] args) { - Assertions.assertEquals("/home", simplifyPath("/home/")); - Assertions.assertEquals("/home/foo", simplifyPath("/home//foo/")); - Assertions.assertEquals("/home/user/Pictures", simplifyPath("/home/user/Documents/../Pictures")); - Assertions.assertEquals("/", simplifyPath("/../")); - Assertions.assertEquals("/.../b/d", simplifyPath("/.../a/../b/c/../d/./")); - } - - public static String simplifyPath(String path) { - Stack s1 = new Stack<>(); - for (String str : path.split("/")) { - switch (str) { - case "": - case ".": - break; - case "..": - if (!s1.isEmpty()) s1.pop(); - break; - default: - s1.push(str); - break; - } - } - - StringBuilder result = new StringBuilder(); - while (!s1.isEmpty()) { - result.insert(0, "/" + s1.pop()); - } - return result.toString().equals("") ? "/" : result.toString(); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" deleted file mode 100644 index 7be3e73..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" +++ /dev/null @@ -1,50 +0,0 @@ -package io.github.dunwu.algorithm.queue_and_stack.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 150. 逆波兰表达式求值 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 逆波兰表达式求值 { - - public static void main(String[] args) { - Assertions.assertEquals(9, evalRPN(new String[] { "2", "1", "+", "3", "*" })); - Assertions.assertEquals(6, evalRPN(new String[] { "4", "13", "5", "/", "+" })); - Assertions.assertEquals(22, - evalRPN(new String[] { "10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+" })); - } - - public static int evalRPN(String[] tokens) { - if (tokens == null || tokens.length == 0) return 0; - Stack stack = new Stack<>(); - for (String token : tokens) { - if ("+-*/".contains(token)) { - Integer op2 = stack.pop(); - Integer op1 = stack.pop(); - switch (token) { - case "+": - stack.push(op1 + op2); - break; - case "-": - stack.push(op1 - op2); - break; - case "*": - stack.push(op1 * op2); - break; - default: - stack.push(op1 / op2); - break; - } - } else { - stack.push(Integer.parseInt(token)); - } - } - return stack.pop(); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" deleted file mode 100644 index 46f389d..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" +++ /dev/null @@ -1,60 +0,0 @@ -package io.github.dunwu.algorithm.queue_and_stack.stack; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -import java.util.List; -import java.util.Stack; - -/** - * 143. 重排链表 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 重排链表 { - - public static void main(String[] args) { - ListNode input = ListNode.buildList(1, 2, 3, 4); - reorderList(input); - List list = ListNode.toList(input); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 1, 4, 2, 3 }, list.toArray()); - - ListNode input2 = ListNode.buildList(1, 2, 3, 4, 5); - reorderList(input2); - List list2 = ListNode.toList(input2); - System.out.println(list2); - Assertions.assertArrayEquals(new Integer[] { 1, 5, 2, 4, 3 }, list2.toArray()); - } - - public static void reorderList(ListNode head) { - - if (head == null || head.next == null) { - return; - } - - ListNode p = head; - int total = 0; - Stack stack = new Stack<>(); - while (p != null) { - stack.push(p); - total++; - p = p.next; - } - - p = head; - int cnt = 0; - while (p != null && cnt < total) { - if (cnt % 2 == 0) { - ListNode node = stack.pop(); - node.next = p.next; - p.next = node; - } - p = p.next; - cnt++; - } - p.next = null; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\211\345\220\210\344\270\200.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\211\345\220\210\344\270\200.java" deleted file mode 100644 index c4379a9..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\211\345\220\210\344\270\200.java" +++ /dev/null @@ -1,56 +0,0 @@ -package io.github.dunwu.algorithm.queue_and_stack; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -/** - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 三合一 { - - int stackSize; - List> stacks; - - public 三合一(int stackSize) { - this.stackSize = stackSize; - this.stacks = new ArrayList<>(); - for (int i = 0; i < 3; i++) { - LinkedList list = new LinkedList<>(); - this.stacks.add(list); - } - } - - public void push(int stackNum, int value) { - LinkedList list = stacks.get(stackNum); - if (list.size() < stackSize) { - list.addLast(value); - } - } - - public int pop(int stackNum) { - LinkedList list = stacks.get(stackNum); - int value = -1; - if (list.size() > 0) { - value = list.getLast(); - list.removeLast(); - } - return value; - } - - public int peek(int stackNum) { - LinkedList list = stacks.get(stackNum); - int value = -1; - if (list.size() > 0) { - value = list.getLast(); - } - return value; - } - - public boolean isEmpty(int stackNum) { - LinkedList list = stacks.get(stackNum); - return list.size() <= 0; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" deleted file mode 100644 index 4b7ae2c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240I.java" +++ /dev/null @@ -1,81 +0,0 @@ -package io.github.dunwu.algorithm.queue_and_stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 496. 下一个更大元素 I - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 下一个更大元素I { - - public static void main(String[] args) { - int[] output1 = nextGreaterElement(new int[] { 4, 1, 2 }, new int[] { 1, 3, 4, 2 }); - int[] expect1 = new int[] { -1, 3, -1 }; - Assertions.assertArrayEquals(expect1, output1); - - int[] output2 = nextGreaterElement(new int[] { 2, 4 }, new int[] { 1, 2, 3, 4 }); - int[] expect2 = new int[] { 3, -1 }; - Assertions.assertArrayEquals(expect2, output2); - } - - public static int[] nextGreaterElement(int[] nums1, int[] nums2) { - int[] result = new int[nums1.length]; - for (int i = 0; i < nums1.length; i++) { - int val = nums1[i]; - int pos = Integer.MAX_VALUE; - result[i] = -1; - for (int j = 0; j < nums2.length; j++) { - if (val == nums2[j]) { - pos = j; - continue; - } - if (pos < j && val < nums2[j]) { - result[i] = nums2[j]; - break; - } - } - } - return result; - } - - public static int[] nextGreaterElement2(int[] nums1, int[] nums2) { - int[] result = new int[nums1.length]; - for (int i = 0; i < nums1.length; i++) { - int val = nums1[i]; - int pos = Integer.MAX_VALUE; - result[i] = -1; - for (int j = 0; j < nums2.length; j++) { - if (val == nums2[j]) { - pos = j; - continue; - } - if (pos < j && val < nums2[j]) { - result[i] = nums2[j]; - break; - } - } - } - return result; - } - - // 计算 nums 中每个元素的下一个更大元素 - public static int[] nextGreaterElement(int[] nums) { - int n = nums.length; - int[] res = new int[n]; - Stack s = new Stack<>(); - for (int i = n - 1; i >= 0; i--) { - while (!s.isEmpty() && s.peek() > nums[i]) { - s.pop(); - } - // nums[i] 身后的下一个更大元素 - res[i] = s.isEmpty() ? -1 : s.peek(); - s.push(nums[i]); - } - return res; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\240\210\346\216\222\345\272\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\240\210\346\216\222\345\272\217.java" deleted file mode 100644 index 86ee967..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\240\210\346\216\222\345\272\217.java" +++ /dev/null @@ -1,73 +0,0 @@ -package io.github.dunwu.algorithm.queue_and_stack; - -import java.util.LinkedList; - -/** - * @see 面试题 03.05. 栈排序 - */ -public class 栈排序 { - - public static void main(String[] args) { - 栈排序 demo = new 栈排序(); - demo.push(1); - System.out.println(demo.stack1); - demo.push(2); - System.out.println(demo.stack1); - } - - public LinkedList stack1; - public LinkedList stack2; - - public 栈排序() { - stack1 = new LinkedList<>(); - stack2 = new LinkedList<>(); - } - - public void push(int val) { - if (isEmpty()) { - stack1.push(val); - return; - } - - if (!stack1.isEmpty()) { - move(val); - } - - stack1.push(val); - while (!stack2.isEmpty()) { - Integer top = stack2.pop(); - stack1.push(top); - } - } - - private void move(int val) { - if (stack1.isEmpty()) { - return; - } - - int top = peek(); - if (top < val) { - stack2.push(stack1.pop()); - move(val); - } - } - - public int pop() { - if (stack1.isEmpty()) { - return -1; - } - return stack1.pop(); - } - - public int peek() { - if (stack1.isEmpty()) { - return -1; - } - return stack1.peek(); - } - - public boolean isEmpty() { - return stack1.isEmpty() && stack2.isEmpty(); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" deleted file mode 100644 index ad3b205..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" +++ /dev/null @@ -1,44 +0,0 @@ -package io.github.dunwu.algorithm.queue_and_stack; - -import io.github.dunwu.algorithm.queue_and_stack.stack.GenericStack; - -/** - * @author Zhang Peng - * @see 682. 棒球比赛 - * @since 2020-06-09 - */ -public class 棒球比赛 { - - public static void main(String[] args) { - System.out.println(calPoints("5", "2", "C", "D", "+")); - System.out.println(calPoints("5", "-2", "4", "C", "D", "9", "+", "+")); - } - - public static int calPoints(String... ops) { - int total = 0; - GenericStack stack = new GenericStack<>(); - for (String s : ops) { - if (s.equals("+")) { - int num1 = stack.pop(); - int num2 = stack.pop(); - int num = num1 + num2; - stack.push(num2); - stack.push(num1); - stack.push(num); - } else if (s.equals("D")) { - stack.push(stack.peek() * 2); - } else if (s.equals("C")) { - stack.pop(); - } else { - stack.push(Integer.valueOf(s)); - } - } - - while (stack.getSize() != 0) { - total += stack.pop(); - } - - return total; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" deleted file mode 100644 index fcb066a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" +++ /dev/null @@ -1,42 +0,0 @@ -package io.github.dunwu.algorithm.queue_and_stack; - -import io.github.dunwu.algorithm.queue_and_stack.stack.GenericStack; -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @see 844. 比较含退格的字符串 - * @since 2020-06-09 - */ -public class 比较含退格的字符串 { - - public static void main(String[] args) { - Assertions.assertTrue(backspaceCompare("ab#c", "ad#c")); - Assertions.assertTrue(backspaceCompare("ab##", "c#d#")); - Assertions.assertTrue(backspaceCompare("a##c", "#a#c")); - Assertions.assertFalse(backspaceCompare("a#c", "b")); - } - - public static boolean backspaceCompare(String S, String T) { - return getFinalStr(S).equals(getFinalStr(T)); - } - - public static String getFinalStr(String S) { - GenericStack stack = new GenericStack<>(); - for (char c : S.toCharArray()) { - if (c == '#') { - stack.pop(); - } else { - stack.push(c); - } - } - - StringBuilder sb = new StringBuilder(); - while (stack.getSize() > 0) { - sb.append(stack.pop()); - } - - return sb.reverse().toString(); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/Sort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/Sort.java index d2c28ca..bfbe8ca 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/Sort.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/Sort.java @@ -1,6 +1,8 @@ package io.github.dunwu.algorithm.sort; /** + * 排序通用泛型接口 + * * @author Zhang Peng */ public interface Sort { diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/SortStrategy.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/SortStrategy.java index 3398632..5e2f7ef 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/SortStrategy.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/SortStrategy.java @@ -1,29 +1,27 @@ package io.github.dunwu.algorithm.sort; import io.github.dunwu.algorithm.util.ArrayUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; /** * 使用策略模式,对算法进行包装 * * @author Zhang Peng */ +@Slf4j public class SortStrategy { - private static final Logger logger = LoggerFactory.getLogger(SortStrategy.class); - - private Sort sort; + private final Sort sort; public SortStrategy(Sort sort) { this.sort = sort; } public void sort(Integer[] list) { - logger.info(this.sort.getClass().getSimpleName() + " 排序开始:"); - logger.info("排序前: {}", ArrayUtil.getArrayString(list, 0, list.length - 1)); + System.out.printf("=================== %s 排序开始 ===================\n", this.sort.getClass().getSimpleName()); + System.out.printf("【排序前】\n%s\n", ArrayUtil.getArrayString(list, 0, list.length - 1)); this.sort.sort(list); - logger.info("排序后: {}", ArrayUtil.getArrayString(list, 0, list.length - 1)); + System.out.printf("【排序后】\n%s\n", ArrayUtil.getArrayString(list, 0, list.length - 1)); } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort.java index be160ef..3c10699 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort.java @@ -23,8 +23,7 @@ public > void sort(T[] list) { list[j] = temp; } } - - ArrayUtil.debugLogArray(list, 0, list.length - 1, String.format("第 %d 趟:", i + 1)); + ArrayUtil.printArray(list, 0, list.length - 1, String.format("第 %02d 趟", i + 1)); } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort2.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort2.java index 6452573..7bebb12 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort2.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort2.java @@ -12,12 +12,11 @@ public class BubbleSort2 implements Sort { @Override public > void sort(T[] list) { - // 交换标志 - boolean bChange = false; // 要遍历的次数 for (int i = 0; i < list.length - 1; i++) { - bChange = false; + // 交换标志 + boolean changed = false; // 从后向前依次的比较相邻两个数的大小,遍历一次后,把数组中第i小的数放在第i个位置上 for (int j = list.length - 1; j > i; j--) { // 比较相邻的元素,如果前面的数大于后面的数,则交换 @@ -25,16 +24,16 @@ public > void sort(T[] list) { T temp = list[j - 1]; list[j - 1] = list[j]; list[j] = temp; - bChange = true; + changed = true; } } // 如果标志为false,说明本轮遍历没有交换,已经是有序数列,可以结束排序 - if (false == bChange) { + if (!changed) { break; } - ArrayUtil.debugLogArray(list, 0, list.length - 1, String.format("第 %d 趟:", i + 1)); + ArrayUtil.printArray(list, 0, list.length - 1, String.format("第 %02d 趟", i + 1)); } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/HeapSort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/HeapSort.java index a5fc017..d403207 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/HeapSort.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/HeapSort.java @@ -27,7 +27,7 @@ public > void sort(T[] list) { // 筛选 R[0] 结点,得到i-1个结点的堆 adjustHeat(list, 0, i); - ArrayUtil.debugLogArray(list, 0, list.length - 1, String.format("第 %d 趟:", list.length - i)); + ArrayUtil.printArray(list, 0, list.length - 1, String.format("第 %02d 趟", list.length - i)); } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/InsertSort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/InsertSort.java index 4847fcb..9d1d49b 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/InsertSort.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/InsertSort.java @@ -12,9 +12,6 @@ public class InsertSort implements Sort { @Override public > void sort(T[] list) { - // 打印第一个元素 - ArrayUtil.debugLogArray(list, 0, 0, String.format("i = %d:\t", 0)); - // 第1个数肯定是有序的,从第2个数开始遍历,依次插入有序序列 for (int i = 1; i < list.length; i++) { int j = 0; @@ -27,7 +24,7 @@ public > void sort(T[] list) { } list[j + 1] = temp; - ArrayUtil.debugLogArray(list, 0, list.length - 1, String.format("i = %d:\t", i)); + ArrayUtil.printArray(list, 0, list.length - 1, String.format("第 %02d 趟", i)); } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/MergeSort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/MergeSort.java index 5ac1e6c..56d36ac 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/MergeSort.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/MergeSort.java @@ -9,7 +9,7 @@ public class MergeSort implements Sort { public > void sort(T[] list) { for (int gap = 1; gap < list.length; gap = 2 * gap) { mergeSort(list, gap, list.length); - ArrayUtil.debugLogArray(list, 0, list.length - 1, String.format("gap = %d", gap)); + ArrayUtil.printArray(list, 0, list.length - 1, String.format("gap = %d", gap)); } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/QuickSort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/QuickSort.java index e821cb6..03ee815 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/QuickSort.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/QuickSort.java @@ -42,7 +42,7 @@ private > void quickSort(T[] list, int left, int right) // 对数组进行分割,取出下次分割的基准标号 int base = division(list, left, right); - ArrayUtil.debugLogArray(list, left, right, String.format("base = %d: ", list[base])); + ArrayUtil.printArray(list, left, right, String.format("base = %d: ", list[base])); // 对“基准标号“左侧的一组数值进行递归的切割,以至于将这些数值完整的排序 quickSort(list, left, base - 1); diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/SelectionSort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/SelectionSort.java index 128b255..319cc81 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/SelectionSort.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/SelectionSort.java @@ -30,7 +30,7 @@ public > void sort(T[] list) { list[index] = list[i]; list[i] = temp; - ArrayUtil.debugLogArray(list, 0, list.length - 1, String.format("第 %d 趟:", i + 1)); + ArrayUtil.printArray(list, 0, list.length - 1, String.format("第 %02d 趟:", i + 1)); } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/ShellSort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/ShellSort.java index 08c9f5f..7b32584 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/ShellSort.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/ShellSort.java @@ -27,7 +27,7 @@ public > void sort(T[] list) { list[j + gap] = temp; } - ArrayUtil.debugLogArray(list, 0, list.length - 1, String.format("gap = %d:", gap)); + ArrayUtil.printArray(list, 0, list.length - 1, String.format("gap = %d:", gap)); // 减小增量 gap = gap / 2; } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/GenericStack.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/GenericStack.java similarity index 95% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/GenericStack.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/GenericStack.java index 1ac2fb0..ac5bd96 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/GenericStack.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/GenericStack.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue_and_stack.stack; +package io.github.dunwu.algorithm.stack; /** * 简化版泛型栈 diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/package-info.java new file mode 100644 index 0000000..667252f --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/package-info.java @@ -0,0 +1,7 @@ +/** + * 单调栈 + * + * @author Zhang Peng + * @date 2025-11-26 + */ +package io.github.dunwu.algorithm.stack.monotonic; \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240.java" new file mode 100644 index 0000000..d7e1501 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240.java" @@ -0,0 +1,47 @@ +package io.github.dunwu.algorithm.stack.monotonic; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; + +/** + * 496. 下一个更大元素 I + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 下一个更大元素 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[] output1 = s.nextGreaterElement(new int[] { 4, 1, 2 }, new int[] { 1, 3, 4, 2 }); + Assertions.assertArrayEquals(new int[] { -1, 3, -1 }, output1); + int[] output2 = s.nextGreaterElement(new int[] { 2, 4 }, new int[] { 1, 2, 3, 4 }); + Assertions.assertArrayEquals(new int[] { 3, -1 }, output2); + } + + static class Solution { + + public int[] nextGreaterElement(int[] nums1, int[] nums2) { + Stack s = new Stack<>(); + Map map = new HashMap<>(); + for (int i = nums2.length - 1; i >= 0; i--) { + while (!s.isEmpty() && s.peek() < nums2[i]) { + s.pop(); + } + map.put(nums2[i], s.empty() ? -1 : s.peek()); + s.push(nums2[i]); + } + + int[] res = new int[nums1.length]; + for (int i = 0; i < nums1.length; i++) { + res[i] = map.getOrDefault(nums1[i], -1); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\2402.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\2402.java" new file mode 100644 index 0000000..88e7608 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\2402.java" @@ -0,0 +1,39 @@ +package io.github.dunwu.algorithm.stack.monotonic; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 503. 下一个更大元素 II + * + * @author Zhang Peng + * @date 2025-11-26 + */ +public class 下一个更大元素2 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new int[] { 2, -1, 2 }, s.nextGreaterElements(new int[] { 1, 2, 1 })); + Assertions.assertArrayEquals(new int[] { 2, 3, 4, -1, 4 }, s.nextGreaterElements(new int[] { 1, 2, 3, 4, 3 })); + } + + static class Solution { + + public int[] nextGreaterElements(int[] nums) { + int[] res = new int[nums.length]; + Stack stack = new Stack<>(); + for (int index = 2 * nums.length - 1; index >= 0; index--) { + int i = index % nums.length; + while (!stack.isEmpty() && stack.peek() <= nums[i]) { + stack.pop(); + } + res[i] = stack.empty() ? -1 : stack.peek(); + stack.push(nums[i]); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\345\225\206\345\223\201\346\212\230\346\211\243\345\220\216\347\232\204\346\234\200\347\273\210\344\273\267\346\240\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\345\225\206\345\223\201\346\212\230\346\211\243\345\220\216\347\232\204\346\234\200\347\273\210\344\273\267\346\240\274.java" new file mode 100644 index 0000000..9243ec1 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\345\225\206\345\223\201\346\212\230\346\211\243\345\220\216\347\232\204\346\234\200\347\273\210\344\273\267\346\240\274.java" @@ -0,0 +1,39 @@ +package io.github.dunwu.algorithm.stack.monotonic; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 1475. 商品折扣后的最终价格 + * + * @author Zhang Peng + * @date 2025-11-26 + */ +public class 商品折扣后的最终价格 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new int[] { 4, 2, 4, 2, 3 }, s.finalPrices(new int[] { 8, 4, 6, 2, 3 })); + Assertions.assertArrayEquals(new int[] { 1, 2, 3, 4, 5 }, s.finalPrices(new int[] { 1, 2, 3, 4, 5 })); + Assertions.assertArrayEquals(new int[] { 9, 0, 1, 6 }, s.finalPrices(new int[] { 10, 1, 1, 6 })); + } + + static class Solution { + + public int[] finalPrices(int[] prices) { + int[] res = new int[prices.length]; + Stack stack = new Stack<>(); + for (int i = prices.length - 1; i >= 0; i--) { + while (!stack.isEmpty() && stack.peek() > prices[i]) { + stack.pop(); + } + res[i] = stack.isEmpty() ? prices[i] : prices[i] - stack.peek(); + stack.push(prices[i]); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\234\200\347\237\255\346\227\240\345\272\217\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\234\200\347\237\255\346\227\240\345\272\217\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204.java" new file mode 100644 index 0000000..853617d --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\234\200\347\237\255\346\227\240\345\272\217\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204.java" @@ -0,0 +1,54 @@ +package io.github.dunwu.algorithm.stack.monotonic; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 581. 最短无序连续子数组 + * + * @author Zhang Peng + * @date 2025-11-26 + */ +public class 最短无序连续子数组 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(5, s.findUnsortedSubarray(new int[] { 2, 6, 4, 8, 10, 9, 15 })); + Assertions.assertEquals(0, s.findUnsortedSubarray(new int[] { 1, 2, 3, 4 })); + Assertions.assertEquals(0, s.findUnsortedSubarray(new int[] { 1 })); + } + + static class Solution { + + public int findUnsortedSubarray(int[] nums) { + int n = nums.length; + int left = Integer.MAX_VALUE, right = Integer.MIN_VALUE; + // 递增栈,存储元素索引 + Stack incrStk = new Stack<>(); + for (int i = 0; i < n; i++) { + while (!incrStk.isEmpty() && nums[incrStk.peek()] > nums[i]) { + // 弹出的元素都是乱序元素,其中最小的索引就是乱序子数组的左边界 + left = Math.min(left, incrStk.pop()); + } + incrStk.push(i); + } + // 递减栈,存储元素索引 + Stack decrStk = new Stack<>(); + for (int i = n - 1; i >= 0; i--) { + while (!decrStk.isEmpty() && nums[decrStk.peek()] < nums[i]) { + // 弹出的元素都是乱序元素,其中最大的索引就是乱序子数组的右边界 + right = Math.max(right, decrStk.pop()); + } + decrStk.push(i); + } + if (left == Integer.MAX_VALUE && right == Integer.MIN_VALUE) { + // 说明单调栈没有弹出任何元素,即 nums 本来就是有序的 + return 0; + } + return right - left + 1; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\257\217\346\227\245\346\270\251\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\257\217\346\227\245\346\270\251\345\272\246.java" new file mode 100644 index 0000000..774fe37 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\257\217\346\227\245\346\270\251\345\272\246.java" @@ -0,0 +1,40 @@ +package io.github.dunwu.algorithm.stack.monotonic; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 739. 每日温度 + * + * @author Zhang Peng + * @date 2025-11-26 + */ +public class 每日温度 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new int[] { 1, 1, 4, 2, 1, 1, 0, 0 }, + s.dailyTemperatures(new int[] { 73, 74, 75, 71, 69, 72, 76, 73 })); + Assertions.assertArrayEquals(new int[] { 1, 1, 1, 0 }, + s.dailyTemperatures(new int[] { 30, 40, 50, 60 })); + } + + static class Solution { + + public int[] dailyTemperatures(int[] t) { + int[] res = new int[t.length]; + Stack s = new Stack<>(); + for (int i = t.length - 1; i >= 0; i--) { + while (!s.isEmpty() && s.peek()[1] <= t[i]) { + s.pop(); + } + res[i] = s.isEmpty() ? 0 : s.peek()[0] - i; + s.push(new int[] { i, t[i] }); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.java" new file mode 100644 index 0000000..0e8c6d5 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.java" @@ -0,0 +1,49 @@ +package io.github.dunwu.algorithm.stack.monotonic; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 402. 移掉 K 位数字 + * + * @author Zhang Peng + * @date 2025-11-26 + */ +public class 移掉K位数字 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals("1219", s.removeKdigits("1432219", 3)); + } + + static class Solution { + + public String removeKdigits(String num, int k) { + Stack stack = new Stack<>(); + for (char c : num.toCharArray()) { + while (!stack.isEmpty() && stack.peek() > c && k > 0) { + stack.pop(); + k--; + } + if (stack.isEmpty() && c == '0') { + continue; + } + stack.push(c); + } + + while (k > 0 && !stack.isEmpty()) { + stack.pop(); + k--; + } + + StringBuilder sb = new StringBuilder(); + while (!stack.isEmpty()) { + sb.append(stack.pop()); + } + return sb.reverse().toString(); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\202\241\347\245\250\344\273\267\346\240\274\350\267\250\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\202\241\347\245\250\344\273\267\346\240\274\350\267\250\345\272\246.java" new file mode 100644 index 0000000..dab708e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\202\241\347\245\250\344\273\267\346\240\274\350\267\250\345\272\246.java" @@ -0,0 +1,46 @@ +package io.github.dunwu.algorithm.stack.monotonic; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 901. 股票价格跨度 + * + * @author Zhang Peng + * @date 2025-11-26 + */ +public class 股票价格跨度 { + + public static void main(String[] args) { + StockSpanner stockSpanner = new StockSpanner(); + Assertions.assertEquals(1, stockSpanner.next(100)); + Assertions.assertEquals(1, stockSpanner.next(80)); + Assertions.assertEquals(1, stockSpanner.next(60)); + Assertions.assertEquals(2, stockSpanner.next(70)); + Assertions.assertEquals(1, stockSpanner.next(60)); + Assertions.assertEquals(4, stockSpanner.next(75)); + Assertions.assertEquals(6, stockSpanner.next(85)); + } + + static class StockSpanner { + + private Stack stack; + + public StockSpanner() { + stack = new Stack<>(); + } + + public int next(int price) { + int count = 1; + while (!stack.isEmpty() && stack.peek()[0] <= price) { + int[] prev = stack.pop(); + count += prev[1]; + } + stack.push(new int[] { price, count }); + return count; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\275\246\344\275\215.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\275\246\344\275\215.java" new file mode 100644 index 0000000..95dabe8 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\275\246\344\275\215.java" @@ -0,0 +1,66 @@ +package io.github.dunwu.algorithm.stack.monotonic; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 853. 车队 + * + * @author Zhang Peng + * @date 2025-11-26 + */ +public class 车位 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(3, s.carFleet(12, new int[] { 10, 8, 0, 5, 3 }, new int[] { 2, 4, 1, 1, 3 })); + Assertions.assertEquals(1, s.carFleet(10, new int[] { 3 }, new int[] { 3 })); + Assertions.assertEquals(1, s.carFleet(100, new int[] { 0, 2, 4 }, new int[] { 4, 2, 1 })); + } + + static class Solution { + + public int carFleet(int target, int[] position, int[] speed) { + int n = position.length; + int[][] cars = new int[n][2]; + for (int i = 0; i < n; i++) { + cars[i][0] = position[i]; + cars[i][1] = speed[i]; + } + // 按照初始位置,从小到大排序 + Arrays.sort(cars, (int[] a, int[] b) -> { + return Integer.compare(a[0], b[0]); + }); + // 计算每辆车到达终点的时间 + double[] time = new double[n]; + for (int i = 0; i < n; i++) { + int[] car = cars[i]; + time[i] = (double) (target - car[0]) / car[1]; + } + + // 使用单调栈计算车队的数量 + // Stack stk = new Stack<>(); + // for (double t : time) { + // while (!stk.isEmpty() && t >= stk.peek()) { + // stk.pop(); + // } + // stk.push(t); + // } + // return stk.size(); + + // 避免使用栈模拟,倒序遍历取递增序列就是答案 + int res = 0; + double maxTime = 0; + for (int i = n - 1; i >= 0; i--) { + if (time[i] > maxTime) { + maxTime = time[i]; + res++; + } + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\351\223\276\350\241\250\344\270\255\347\232\204\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\351\223\276\350\241\250\344\270\255\347\232\204\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\350\212\202\347\202\271.java" new file mode 100644 index 0000000..cd746cc --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\351\223\276\350\241\250\344\270\255\347\232\204\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\350\212\202\347\202\271.java" @@ -0,0 +1,53 @@ +package io.github.dunwu.algorithm.stack.monotonic; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.Stack; + +/** + * 1019. 链表中的下一个更大节点 + * + * @author Zhang Peng + * @date 2025-11-26 + */ +public class 链表中的下一个更大节点 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new int[] { 5, 5, 0 }, + s.nextLargerNodes(ListNode.buildList(2, 1, 5))); + Assertions.assertArrayEquals(new int[] { 7, 0, 5, 5, 0 }, + s.nextLargerNodes(ListNode.buildList(2, 7, 4, 3, 5))); + } + + static class Solution { + + public int[] nextLargerNodes(ListNode head) { + // 把单链表转化成数组,方便通过索引访问 + ArrayList nums = new ArrayList<>(); + ListNode p = head; + while (p != null) { + nums.add(p.val); + p = p.next; + } + + // 存放答案的数组 + int[] res = new int[nums.size()]; + Stack stack = new Stack<>(); + // 单调栈模板,求下一个更大元素,从后往前遍历 + for (int i = nums.size() - 1; i >= 0; i--) { + while (!stack.isEmpty() && stack.peek() <= nums.get(i)) { + stack.pop(); + } + // 本题要求没有下一个更大元素时返回 0 + res[i] = stack.isEmpty() ? 0 : stack.peek(); + stack.push(nums.get(i)); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" new file mode 100644 index 0000000..e0bde55 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" @@ -0,0 +1,51 @@ +package io.github.dunwu.algorithm.stack; + +import org.junit.jupiter.api.Assertions; + +import java.util.Deque; +import java.util.LinkedList; + +/** + * 150. 逆波兰表达式求值 + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 文件的最长绝对路径 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(20, s.lengthLongestPath("dir\\n\\tsubdir1\\n\\tsubdir2\\n\\t\\tfile.ext")); + Assertions.assertEquals(32, s.lengthLongestPath( + "dir\\n\\tsubdir1\\n\\t\\tfile1.ext\\n\\t\\tsubsubdir1\\n\\tsubdir2\\n\\t\\tsubsubdir2\\n\\t\\t\\tfile2.ext")); + Assertions.assertEquals(0, s.lengthLongestPath("a")); + Assertions.assertEquals(12, s.lengthLongestPath("file1.txt\\nfile2.txt\\nlongfile.txt")); + } + + static class Solution { + + public int lengthLongestPath(String input) { + // 这个栈存储之前的父路径。实际上这里只用存父路径的长度就够了,这个优化留给你吧 + Deque stack = new LinkedList<>(); + int maxLen = 0; + for (String part : input.split("\n")) { + int level = part.lastIndexOf("\t") + 1; + // 让栈中只保留当前目录的父路径 + while (level < stack.size()) { + stack.removeLast(); + } + stack.addLast(part.substring(level)); + // 如果是文件,就计算路径长度 + if (part.contains(".")) { + int sum = stack.stream().mapToInt(String::length).sum(); + // 加上父路径的分隔符 + sum += stack.size() - 1; + maxLen = Math.max(maxLen, sum); + } + } + return maxLen; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" similarity index 63% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" index 01d98a8..9f6ec25 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue_and_stack.stack; +package io.github.dunwu.algorithm.stack; import org.junit.jupiter.api.Assertions; @@ -30,30 +30,28 @@ public static void main(String[] args) { static class FreqStack { - int maxFreq = 0; - HashMap valToFreq = new HashMap<>(); - TreeMap> freqToVal = new TreeMap<>(); + private HashMap valToFreq; + private TreeMap> freqToValStack; public FreqStack() { + valToFreq = new HashMap<>(); + freqToValStack = new TreeMap<>(); } public void push(int val) { - int freq = valToFreq.getOrDefault(val, 0) + 1; - valToFreq.put(val, freq); - freqToVal.putIfAbsent(freq, new Stack<>()); - freqToVal.get(freq).add(val); - maxFreq = Math.max(maxFreq, freq); + valToFreq.put(val, valToFreq.getOrDefault(val, 0) + 1); + Integer freq = this.valToFreq.get(val); + freqToValStack.putIfAbsent(freq, new Stack<>()); + freqToValStack.get(freq).push(val); } public int pop() { - Stack vals = freqToVal.get(maxFreq); - int v = vals.pop(); - int freq = valToFreq.get(v) - 1; - valToFreq.put(v, freq); - if (vals.isEmpty()) { - maxFreq--; - } - return v; + Integer maxFreq = freqToValStack.lastKey(); + Stack stack = freqToValStack.get(maxFreq); + Integer val = stack.pop(); + if (stack.empty()) { freqToValStack.remove(maxFreq); } + valToFreq.put(val, valToFreq.getOrDefault(val, 0) - 1); + return val; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\260\217\346\240\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" similarity index 87% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\260\217\346\240\210.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" index 44783f6..6775a69 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/stack/\346\234\200\345\260\217\346\240\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue_and_stack.stack; +package io.github.dunwu.algorithm.stack; import org.junit.jupiter.api.Assertions; @@ -25,9 +25,7 @@ public static void main(String[] args) { static class MinStack { - // 记录栈中的所有元素 Stack stack; - // 阶段性记录栈中的最小元素 Stack minStack; public MinStack() { @@ -40,13 +38,13 @@ public void push(int val) { if (minStack.isEmpty() || val < minStack.peek()) { minStack.push(val); } else { - minStack.push(minStack.peek()); + minStack.push(minStack.peek());; } } public void pop() { - minStack.pop(); stack.pop(); + minStack.pop(); } public int top() { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" new file mode 100644 index 0000000..1601e5f --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" @@ -0,0 +1,53 @@ +package io.github.dunwu.algorithm.stack; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 20. 有效的括号 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 有效的括号 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.isValid("()")); + Assertions.assertTrue(s.isValid("{[]}")); + Assertions.assertFalse(s.isValid("([)]")); + Assertions.assertFalse(s.isValid("([)")); + Assertions.assertFalse(s.isValid("((")); + Assertions.assertTrue(s.isValid("(())")); + } + + static class Solution { + + public boolean isValid(String s) { + Stack stack = new Stack<>(); + for (char c : s.toCharArray()) { + switch (c) { + case ')': + if (stack.isEmpty()) { return false; } + if (stack.pop() != '(') { return false; } + break; + case ']': + if (stack.isEmpty()) { return false; } + if (stack.pop() != '[') { return false; } + break; + case '}': + if (stack.isEmpty()) { return false; } + if (stack.pop() != '{') { return false; } + break; + default: + stack.push(c); + break; + } + } + return stack.isEmpty(); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\240\210\346\216\222\345\272\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\240\210\346\216\222\345\272\217.java" new file mode 100644 index 0000000..40e5a99 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\240\210\346\216\222\345\272\217.java" @@ -0,0 +1,71 @@ +package io.github.dunwu.algorithm.stack; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 面试题 03.05. 栈排序 + * + * @author Zhang Peng + * @date 2025-11-26 + */ +public class 栈排序 { + + public static void main(String[] args) { + SortedStack s = new SortedStack(); + s.push(1); + s.push(2); + Assertions.assertEquals(1, s.peek()); + s.pop(); + Assertions.assertEquals(2, s.peek()); + + SortedStack s2 = new SortedStack(); + s2.pop(); + s2.pop(); + s2.push(1); + s2.pop(); + Assertions.assertTrue(s2.isEmpty()); + } + + static class SortedStack { + + private Stack s; + private Stack t; + + public SortedStack() { + s = new Stack<>(); + t = new Stack<>(); + } + + public void push(int val) { + if (s.isEmpty()) { + s.push(val); + return; + } + while (!s.isEmpty() && s.peek() < val) { + t.push(s.pop()); + } + s.push(val); + while (!t.isEmpty()) { + s.push(t.pop()); + } + } + + public void pop() { + if (!s.isEmpty()) { + s.pop(); + } + } + + public int peek() { + return s.isEmpty() ? -1 : s.peek(); + } + + public boolean isEmpty() { + return s.isEmpty(); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" new file mode 100644 index 0000000..3ae17cf --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" @@ -0,0 +1,56 @@ +package io.github.dunwu.algorithm.stack; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 682. 棒球比赛 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 棒球比赛 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(30, s.calPoints(new String[] { "5", "2", "C", "D", "+" })); + Assertions.assertEquals(27, s.calPoints(new String[] { "5", "-2", "4", "C", "D", "9", "+", "+" })); + } + + static class Solution { + + public int calPoints(String[] operations) { + Stack stack = new Stack<>(); + for (String op : operations) { + switch (op) { + case "C": + stack.pop(); + break; + case "D": + stack.push(stack.peek() * 2); + break; + case "+": + int cur = stack.pop(); + int prev = stack.pop(); + int next = prev + cur; + stack.push(prev); + stack.push(cur); + stack.push(next); + break; + default: + stack.push(Integer.valueOf(op)); + break; + } + } + + int res = 0; + while (!stack.isEmpty()) { + res += stack.pop(); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" new file mode 100644 index 0000000..5fee00b --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" @@ -0,0 +1,52 @@ +package io.github.dunwu.algorithm.stack; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 844. 比较含退格的字符串 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 比较含退格的字符串 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.backspaceCompare("ab#c", "ad#c")); + Assertions.assertTrue(s.backspaceCompare("ab##", "c#d#")); + Assertions.assertTrue(s.backspaceCompare("a##c", "#a#c")); + Assertions.assertFalse(s.backspaceCompare("a#c", "b")); + } + + static class Solution { + + public boolean backspaceCompare(String s, String t) { + Stack a = new Stack<>(); + Stack b = new Stack<>(); + for (char c : s.toCharArray()) { + if (c == '#') { + if (!a.isEmpty()) { a.pop(); } + } else { + a.push(c); + } + } + for (char c : t.toCharArray()) { + if (c == '#') { + if (!b.isEmpty()) { b.pop(); } + } else { + b.push(c); + } + } + + if (a.size() != b.size()) { return false; } + while (!a.isEmpty()) { + if (a.pop() != b.pop()) { return false; } + } + return true; + } + + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/SampleBrowser.java "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\346\265\217\350\247\210\345\231\250\347\232\204\345\211\215\350\277\233\345\220\216\351\200\200.java" similarity index 95% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/SampleBrowser.java rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\346\265\217\350\247\210\345\231\250\347\232\204\345\211\215\350\277\233\345\220\216\351\200\200.java" index 50e679a..c12f789 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/SampleBrowser.java +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\346\265\217\350\247\210\345\231\250\347\232\204\345\211\215\350\277\233\345\220\216\351\200\200.java" @@ -1,14 +1,14 @@ -package io.github.dunwu.algorithm.queue_and_stack; +package io.github.dunwu.algorithm.stack; /** * 使用前后栈实现浏览器的前进后退。 * * @author chinalwb */ -public class SampleBrowser { +public class 用栈实现浏览器的前进后退 { public static void main(String[] args) { - SampleBrowser browser = new SampleBrowser(); + 用栈实现浏览器的前进后退 browser = new 用栈实现浏览器的前进后退(); browser.open("http://www.baidu.com"); browser.open("http://news.baidu.com/"); browser.open("http://news.baidu.com/ent"); @@ -30,7 +30,7 @@ public static void main(String[] args) { private LinkedListBasedStack backStack; private LinkedListBasedStack forwardStack; - public SampleBrowser() { + public 用栈实现浏览器的前进后退() { this.backStack = new LinkedListBasedStack(); this.forwardStack = new LinkedListBasedStack(); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" similarity index 78% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" index ff3d6ad..3051ecf 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue_and_stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.queue_and_stack; +package io.github.dunwu.algorithm.stack; import org.junit.jupiter.api.Assertions; @@ -14,14 +14,14 @@ public class 用栈实现队列 { public static void main(String[] args) { - // MyQueue q1 = new MyQueue(); - // q1.push(1); // queue is: [1] - // q1.push(2); // queue is: [1, 2] (leftmost is front of the queue) - // Assertions.assertEquals(1, q1.peek()); - // Assertions.assertEquals(1, q1.pop()); - // Assertions.assertFalse(q1.empty()); - // Assertions.assertEquals(2, q1.pop()); - // Assertions.assertTrue(q1.empty()); + MyQueue q1 = new MyQueue(); + q1.push(1); // queue is: [1] + q1.push(2); // queue is: [1, 2] (leftmost is front of the queue) + Assertions.assertEquals(1, q1.peek()); + Assertions.assertEquals(1, q1.pop()); + Assertions.assertFalse(q1.empty()); + Assertions.assertEquals(2, q1.pop()); + Assertions.assertTrue(q1.empty()); MyQueue q2 = new MyQueue(); q2.push(1); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" new file mode 100644 index 0000000..aa7357b --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" @@ -0,0 +1,50 @@ +package io.github.dunwu.algorithm.stack; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 71. 简化路径 + * + * @author Zhang Peng + * @since 2025-08-08 + */ +public class 简化路径 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals("/home", s.simplifyPath("/home/")); + Assertions.assertEquals("/home/foo", s.simplifyPath("/home//foo/")); + Assertions.assertEquals("/home/user/Pictures", s.simplifyPath("/home/user/Documents/../Pictures")); + Assertions.assertEquals("/", s.simplifyPath("/../")); + Assertions.assertEquals("/.../b/d", s.simplifyPath("/.../a/../b/c/../d/./")); + } + + static class Solution { + + public String simplifyPath(String path) { + String[] parts = path.split("/"); + Stack stk = new Stack<>(); + // 借助栈计算最终的文件夹路径 + for (String part : parts) { + if (part.isEmpty() || part.equals(".")) { + continue; + } + if (part.equals("..")) { + if (!stk.isEmpty()) stk.pop(); + continue; + } + stk.push(part); + } + // 栈中存储的文件夹组成路径 + String res = ""; + while (!stk.isEmpty()) { + res = "/" + stk.pop() + res; + } + return res.isEmpty() ? "/" : res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" new file mode 100644 index 0000000..e83ae8f --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" @@ -0,0 +1,53 @@ +package io.github.dunwu.algorithm.stack; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 150. 逆波兰表达式求值 + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 逆波兰表达式求值 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(9, s.evalRPN(new String[] { "2", "1", "+", "3", "*" })); + Assertions.assertEquals(6, s.evalRPN(new String[] { "4", "13", "5", "/", "+" })); + Assertions.assertEquals(22, + s.evalRPN(new String[] { "10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+" })); + } + + static class Solution { + + public int evalRPN(String[] tokens) { + Stack stack = new Stack<>(); + for (String token : tokens) { + if ("+".equals(token)) { + Integer numB = stack.pop(); + Integer numA = stack.pop(); + stack.push(numA + numB); + } else if ("-".equals(token)) { + Integer numB = stack.pop(); + Integer numA = stack.pop(); + stack.push(numA - numB); + } else if ("*".equals(token)) { + Integer numB = stack.pop(); + Integer numA = stack.pop(); + stack.push(numA * numB); + } else if ("/".equals(token)) { + Integer numB = stack.pop(); + Integer numA = stack.pop(); + stack.push(numA / numB); + } else { + stack.push(Integer.parseInt(token)); + } + } + return stack.pop(); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" new file mode 100644 index 0000000..48cdd0e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" @@ -0,0 +1,60 @@ +package io.github.dunwu.algorithm.stack; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +import java.util.List; +import java.util.Stack; + +/** + * 143. 重排链表 + * + * @author Zhang Peng + * @date 2025-08-11 + */ +public class 重排链表 { + + public static void main(String[] args) { + + Solution s = new Solution(); + ListNode input = ListNode.buildList(1, 2, 3, 4); + s.reorderList(input); + List list = ListNode.toList(input); + Assertions.assertArrayEquals(new Integer[] { 1, 4, 2, 3 }, list.toArray()); + + ListNode input2 = ListNode.buildList(1, 2, 3, 4, 5); + s.reorderList(input2); + List list2 = ListNode.toList(input2); + Assertions.assertArrayEquals(new Integer[] { 1, 5, 2, 4, 3 }, list2.toArray()); + } + + static class Solution { + + public void reorderList(ListNode head) { + Stack stack = new Stack<>(); + // 先把所有节点装进栈里,得到倒序结果 + ListNode p = head; + while (p != null) { + stack.push(p); + p = p.next; + } + + p = head; + while (p != null) { + // 链表尾部的节点 + ListNode last = stack.pop(); + ListNode next = p.next; + if (last == next || last.next == next) { + // 结束条件,链表节点数为奇数或偶数时均适用 + last.next = null; + break; + } + p.next = last; + last.next = next; + p = next; + } + } + + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/StringAlgorithm.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/StringAlgorithm.java index ade2285..b0a3d12 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/StringAlgorithm.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/StringAlgorithm.java @@ -1,226 +1,293 @@ package io.github.dunwu.algorithm.str; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; -import java.util.HashSet; +import java.util.List; import java.util.Map; -import java.util.Set; /** * @author Zhang Peng - * @since 2020-05-12 + * @since 2020-01-18 */ public class StringAlgorithm { /** - * @see 01. 判定字符是否唯一 + * 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 + *

+ * 示例 1: + *

+ * 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 示例 2: + *

+ * 输入: "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 示例 3: + *

+ * 输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 + *

+ * 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。 + * + * @see 无重复字符的最长子串 */ - public static boolean isUnique(String str) { - if (str == null || str.length() <= 1) { return true; } - Set set = new HashSet<>(); - for (char c : str.toCharArray()) { - if (set.contains(c)) { - return false; + public static int lengthOfLongestSubstring(String s) { + if (null == s || s.length() == 0) { + return 0; + } + + int max = 0; + int left = 0; + Map map = new HashMap<>(); + for (int i = 0; i < s.length(); i++) { + if (map.containsKey(s.charAt(i))) { + left = Math.max(left, map.get(s.charAt(i)) + 1); } - set.add(c); + map.put(s.charAt(i), i); + max = Math.max(max, i - left + 1); } - return true; + return max; } /** - * @see 02. 判定是否互为字符重排 + * 编写一个函数来查找字符串数组中的最长公共前缀。 + *

+ * 如果不存在公共前缀,返回空字符串 ""。 + *

+ * 示例 1: + *

+ * 输入: ["flower","flow","flight"] 输出: "fl" 示例 2: + *

+ * 输入: ["dog","racecar","car"] 输出: "" 解释: 输入不存在公共前缀。 说明: + *

+ * 所有输入只包含小写字母 a-z 。 + * + * @see 最长公共前缀 */ - public static boolean checkPermutation(String s1, String s2) { - if (!(s1 != null && s2 != null)) { - return false; + public static String longestCommonPrefix(String[] array) { + if (array == null || array.length == 0) { + return ""; + } else if (array.length == 1) { + return array[0]; + } else { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < array[0].length(); i++) { + char c = array[0].charAt(i); + boolean end = false; + for (int index = 1; index < array.length; index++) { + if (array[index].length() - 1 < i) { + end = true; + break; + } + + if (array[index].charAt(i) != c) { + end = true; + break; + } + } + if (end) { + break; + } else { + sb.append(c); + } + } + return sb.toString(); } + } - if (s1.length() != s2.length()) { + /** + * 给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。 + *

+ * 换句话说,第一个字符串的排列之一是第二个字符串的子串。 + *

+ * 示例1: 输入: s1 = "ab" s2 = "eidbaooo" 输出: True 解释: s2 包含 s1 的排列之一 ("ba"). + *

+ * 示例2: 输入: s1= "ab" s2 = "eidboaoo" 输出: False + *

+ * 注意:输入的字符串只包含小写字母,两个字符串的长度都在 [1, 10,000] 之间 + * + * @see 字符串的排列 + */ + public static boolean checkInclusion(String s1, String s2) { + if (s1 == null || s1.length() == 0 || s2 == null || s2.length() == 0) { return false; } - Map countMap1 = new HashMap<>(); - Map countMap2 = new HashMap<>(); - for (char c : s1.toCharArray()) { - if (countMap1.containsKey(c)) { - Integer cnt = countMap1.get(c); - cnt++; - } else { - countMap1.put(c, 1); - } - } - for (char c : s2.toCharArray()) { - if (countMap2.containsKey(c)) { - Integer cnt = countMap2.get(c); - cnt++; - } else { - countMap2.put(c, 1); - } - } + int len1 = s1.length(); + int len2 = s2.length(); - Set keySet1 = countMap1.keySet(); - Set keySet2 = countMap2.keySet(); - if (keySet1.size() != keySet2.size()) { - return false; + // 字母命中数统计 + int[] count1 = new int[26]; + int[] count2 = new int[26]; + + for (char c : s1.toCharArray()) { + count1[c - 'a']++; } - for (Character key : keySet1) { - if (!countMap2.containsKey(key)) { - return false; + for (int i = 0; i < len2; i++) { + if (i >= len1) { + count2[s2.charAt(i - len1) - 'a']--; } - if (countMap2.get(key).intValue() != countMap1.get(key).intValue()) { - return false; + count2[s2.charAt(i) - 'a']++; + if (Arrays.equals(count1, count2)) { + return true; } } - return true; + return false; } /** - * @see 03. URL化 + * 给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。 + *

+ * 示例 1: + *

+ * 输入: num1 = "2", num2 = "3" 输出: "6" 示例 2: + *

+ * 输入: num1 = "123", num2 = "456" 输出: "56088" + *

+ * 说明:num1 和 num2 的长度小于110。 num1 和 num2 只包含数字 0-9。 num1 和 num2 均不以零开头,除非是数字 0 本身。 + *

+ * 不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。 + * + * @see 字符串相乘 */ - public static String replaceSpaces(String str, int length) { - int realLength = str.length(); - int min = Math.min(length, realLength); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < min; i++) { - char c = str.charAt(i); - if (str.charAt(i) == ' ') { - sb.append("%20"); - } else { - sb.append(c); - } + public static String multiply(String num1, String num2) { + if (num1.equals("0") || num2.equals("0")) { + return "0"; } - return sb.toString(); - } - /** - * @see 04. 回文排列 - */ - public static boolean canPermutePalindrome(String s) { - int length = s.length(); - boolean isEven = (length % 2) == 0; - Map map = new HashMap<>(length); - for (char c : s.toCharArray()) { - if (map.containsKey(c)) { - Integer cnt = map.get(c); - cnt++; - map.put(c, cnt); - } else { - map.put(c, 1); - } - } + String result = "0"; + for (int i = num1.length() - 1; i >= 0; i--) { - int oddCount = 0; - for (char c : map.keySet()) { - int count = map.get(c); + int carry = 0; - if (isEven && (count % 2) != 0) { return false; } - if (!isEven && (count % 2) != 0) { - if (oddCount > 1) { - return false; - } - oddCount++; + StringBuilder tempBuilder = new StringBuilder(); + int value1 = num1.charAt(i) - '0'; + + for (int temp = i; temp < num1.length() - 1; temp++) { + tempBuilder.append("0"); } - } - return true; - } - /** - * @see 05. 一次编辑 - */ - public static boolean oneEditAway(String first, String second) { - if (first == null || second == null) { - return false; - } - int len1 = first.length(); - int len2 = second.length(); - if (Math.abs(len1 - len2) > 1) { - return false; - } - if (len2 > len1) { return oneEditAway(second, first); } + for (int j = num2.length() - 1; j >= 0; j--) { + int value2 = num2.charAt(j) - '0'; + int value = value1 * value2 + carry; + int current = value % 10; + carry = value / 10; + tempBuilder.append(current); + } - for (int i = 0; i < len2; i++) { - if (first.charAt(i) != second.charAt(i)) { - return first.substring(i + 1).equals(second.substring(len1 == len2 ? i + 1 : i)); + if (carry > 0) { + tempBuilder.append(carry); } + + result = add(result, tempBuilder.reverse().toString()); } - return true; + + return result; } - /** - * @see 06. 字符串压缩 - */ - public static String compressString(String str) { - if (str == null) { return null; } + public static String add(String num1, String num2) { + StringBuilder builder = new StringBuilder(); + int carry = 0; - int originLen = str.length(); - if (str.length() <= 1) { - return str; - } + for (int i = num1.length() - 1, j = num2.length() - 1; + i >= 0 || j >= 0; + i--, j--) { - int cnt = 0; - char mark = str.charAt(0); - StringBuilder sb = new StringBuilder(); - for (char c : str.toCharArray()) { - if (mark == c) { - cnt++; - } else { - sb.append(mark).append(cnt); - // 设置新字符 - mark = c; - cnt = 1; + int result = carry; + if (i >= 0) { + result += num1.charAt(i) - '0'; + } + if (j >= 0) { + result += num2.charAt(j) - '0'; } + carry = result / 10; + int current = result % 10; + builder.append(current); } - sb.append(mark).append(cnt); - - String newStr = sb.toString(); - if (newStr.length() >= originLen) { - return str; - } else { - return newStr; + if (carry > 0) { + builder.append(carry); } + return builder.reverse().toString(); } /** - * @see 09. 字符串轮转 + * 给定一个字符串,逐个翻转字符串中的每个单词。 + *

+ * 示例 1: 输入: "the sky is blue" 输出: "blue is sky the" + *

+ * 示例 2: 输入: " hello world! " 输出: "world! hello" 解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 + *

+ * 示例 3: 输入: "a good example" 输出: "example good a" 解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 + *

+ * 说明: 无空格字符构成一个单词。 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 + *

+ * 进阶: 请选用 C 语言的用户尝试使用 O(1) 额外空间复杂度的原地解法。 + * + * @see 翻转字符串里的单词 */ - public static boolean isFlipedString(String s1, String s2) { - if (s1 == null || s2 == null) { return false; } - - int len1 = s1.length(), len2 = s2.length(); - if (len1 != len2) { - return false; + public static String reverseWords(String s) { + StringBuilder builder = new StringBuilder(); + List list = new ArrayList<>(); + for (char c : s.toCharArray()) { + if (c != ' ') { + builder.append(c); + } else { + if (!builder.toString().equals("")) { + list.add(builder.toString()); + } + builder = new StringBuilder(); + } } - - if (s1.equals(s2)) { - return true; + if (!builder.toString().equals("")) { + list.add(builder.toString()); } - if (len1 == 1) { - return false; - } + builder = new StringBuilder(); + for (int i = list.size() - 1; i >= 0; i--) { - int begin = s1.indexOf(s2.charAt(0)) - 1; - for (int i = begin; i < len2 - 1; i++) { - String temp = leftMove(s1, i + 1); - if (s2.equals(temp)) { - return true; + builder.append(list.get(i)); + if (i != 0) { + builder.append(" "); } } - return false; + return builder.toString(); } /** - * 字符串整体向左偏移 + * 以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。 + *

+ * 在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。更多信息请参阅:Linux / Unix中的绝对路径 vs + * 相对路径 + *

+ * 请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。 + *

+ * 示例 1: 输入:"/home/" 输出:"/home" 解释:注意,最后一个目录名后面没有斜杠。 + *

+ * 示例 2: 输入:"/../" 输出:"/" 解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级。 + *

+ * 示例 3: 输入:"/home//foo/" 输出:"/home/foo" 解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。 + *

+ * 示例 4: 输入:"/a/./b/../../c/" 输出:"/c" + *

+ * 示例 5: 输入:"/a/../../b/../c//.//" 输出:"/c" + *

+ * 示例 6: 输入:"/a//b////c/d//././/.." 输出:"/a/b/c" + * + * @see 简化路径 */ - private static String leftMove(String str, int pos) { - if (str == null || str.length() <= 1 || pos <= 0) { - return str; + public static String simplifyPath(String path) { + if (path.equals("/")) { + return path; + } + + if (path.endsWith("/")) { + path = path.substring(0, path.length() - 1); + } + + if (path.startsWith("/../")) { + path = path.replaceFirst("/../", "/"); } - String temp = str.substring(pos); - temp = temp + str.substring(0, pos); - return temp; + path = path.replaceAll("//", "/"); + return path; } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/ValidAnagram.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ValidAnagram.java similarity index 98% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/ValidAnagram.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ValidAnagram.java index 60dc9fc..1dd91de 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/ValidAnagram.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ValidAnagram.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.string; +package io.github.dunwu.algorithm.str; import java.util.HashMap; import java.util.Map; diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/StringAlgorithm.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/StringAlgorithm.java deleted file mode 100644 index b02ed5b..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/StringAlgorithm.java +++ /dev/null @@ -1,289 +0,0 @@ -package io.github.dunwu.algorithm.string; - -import java.util.*; - -/** - * @author Zhang Peng - * @since 2020-01-18 - */ -public class StringAlgorithm { - - /** - * 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 - *

- * 示例 1: - *

- * 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 示例 2: - *

- * 输入: "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 示例 3: - *

- * 输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 - *

- * 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。 - * - * @see 无重复字符的最长子串 - */ - public static int lengthOfLongestSubstring(String s) { - if (null == s || s.length() == 0) { - return 0; - } - - int max = 0; - int left = 0; - Map map = new HashMap<>(); - for (int i = 0; i < s.length(); i++) { - if (map.containsKey(s.charAt(i))) { - left = Math.max(left, map.get(s.charAt(i)) + 1); - } - map.put(s.charAt(i), i); - max = Math.max(max, i - left + 1); - } - return max; - } - - /** - * 编写一个函数来查找字符串数组中的最长公共前缀。 - *

- * 如果不存在公共前缀,返回空字符串 ""。 - *

- * 示例 1: - *

- * 输入: ["flower","flow","flight"] 输出: "fl" 示例 2: - *

- * 输入: ["dog","racecar","car"] 输出: "" 解释: 输入不存在公共前缀。 说明: - *

- * 所有输入只包含小写字母 a-z 。 - * - * @see 最长公共前缀 - */ - public static String longestCommonPrefix(String[] array) { - if (array == null || array.length == 0) { - return ""; - } else if (array.length == 1) { - return array[0]; - } else { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < array[0].length(); i++) { - char c = array[0].charAt(i); - boolean end = false; - for (int index = 1; index < array.length; index++) { - if (array[index].length() - 1 < i) { - end = true; - break; - } - - if (array[index].charAt(i) != c) { - end = true; - break; - } - } - if (end) { - break; - } else { - sb.append(c); - } - } - return sb.toString(); - } - } - - /** - * 给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。 - *

- * 换句话说,第一个字符串的排列之一是第二个字符串的子串。 - *

- * 示例1: 输入: s1 = "ab" s2 = "eidbaooo" 输出: True 解释: s2 包含 s1 的排列之一 ("ba"). - *

- * 示例2: 输入: s1= "ab" s2 = "eidboaoo" 输出: False - *

- * 注意:输入的字符串只包含小写字母,两个字符串的长度都在 [1, 10,000] 之间 - * - * @see 字符串的排列 - */ - public static boolean checkInclusion(String s1, String s2) { - if (s1 == null || s1.length() == 0 || s2 == null || s2.length() == 0) { - return false; - } - - int len1 = s1.length(); - int len2 = s2.length(); - - // 字母命中数统计 - int[] count1 = new int[26]; - int[] count2 = new int[26]; - - for (char c : s1.toCharArray()) { - count1[c - 'a']++; - } - - for (int i = 0; i < len2; i++) { - if (i >= len1) { - count2[s2.charAt(i - len1) - 'a']--; - } - - count2[s2.charAt(i) - 'a']++; - if (Arrays.equals(count1, count2)) { - return true; - } - } - return false; - } - - /** - * 给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。 - *

- * 示例 1: - *

- * 输入: num1 = "2", num2 = "3" 输出: "6" 示例 2: - *

- * 输入: num1 = "123", num2 = "456" 输出: "56088" - *

- * 说明:num1 和 num2 的长度小于110。 num1 和 num2 只包含数字 0-9。 num1 和 num2 均不以零开头,除非是数字 0 本身。 - *

- * 不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。 - * - * @see 字符串相乘 - */ - public static String multiply(String num1, String num2) { - if (num1.equals("0") || num2.equals("0")) { - return "0"; - } - - String result = "0"; - for (int i = num1.length() - 1; i >= 0; i--) { - - int carry = 0; - - StringBuilder tempBuilder = new StringBuilder(); - int value1 = num1.charAt(i) - '0'; - - for (int temp = i; temp < num1.length() - 1; temp++) { - tempBuilder.append("0"); - } - - for (int j = num2.length() - 1; j >= 0; j--) { - int value2 = num2.charAt(j) - '0'; - int value = value1 * value2 + carry; - int current = value % 10; - carry = value / 10; - tempBuilder.append(current); - } - - if (carry > 0) { - tempBuilder.append(carry); - } - - result = add(result, tempBuilder.reverse().toString()); - } - - return result; - } - - public static String add(String num1, String num2) { - StringBuilder builder = new StringBuilder(); - int carry = 0; - - for (int i = num1.length() - 1, j = num2.length() - 1; - i >= 0 || j >= 0; - i--, j--) { - - int result = carry; - if (i >= 0) { - result += num1.charAt(i) - '0'; - } - if (j >= 0) { - result += num2.charAt(j) - '0'; - } - carry = result / 10; - int current = result % 10; - builder.append(current); - } - if (carry > 0) { - builder.append(carry); - } - return builder.reverse().toString(); - } - - /** - * 给定一个字符串,逐个翻转字符串中的每个单词。 - *

- * 示例 1: 输入: "the sky is blue" 输出: "blue is sky the" - *

- * 示例 2: 输入: " hello world! " 输出: "world! hello" 解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 - *

- * 示例 3: 输入: "a good example" 输出: "example good a" 解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 - *

- * 说明: 无空格字符构成一个单词。 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 - *

- * 进阶: 请选用 C 语言的用户尝试使用 O(1) 额外空间复杂度的原地解法。 - * - * @see 翻转字符串里的单词 - */ - public static String reverseWords(String s) { - StringBuilder builder = new StringBuilder(); - List list = new ArrayList<>(); - for (char c : s.toCharArray()) { - if (c != ' ') { - builder.append(c); - } else { - if (!builder.toString().equals("")) { - list.add(builder.toString()); - } - builder = new StringBuilder(); - } - } - if (!builder.toString().equals("")) { - list.add(builder.toString()); - } - - builder = new StringBuilder(); - for (int i = list.size() - 1; i >= 0; i--) { - - builder.append(list.get(i)); - if (i != 0) { - builder.append(" "); - } - } - return builder.toString(); - } - - /** - * 以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。 - *

- * 在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。更多信息请参阅:Linux / Unix中的绝对路径 vs - * 相对路径 - *

- * 请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。 - *

- * 示例 1: 输入:"/home/" 输出:"/home" 解释:注意,最后一个目录名后面没有斜杠。 - *

- * 示例 2: 输入:"/../" 输出:"/" 解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级。 - *

- * 示例 3: 输入:"/home//foo/" 输出:"/home/foo" 解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。 - *

- * 示例 4: 输入:"/a/./b/../../c/" 输出:"/c" - *

- * 示例 5: 输入:"/a/../../b/../c//.//" 输出:"/c" - *

- * 示例 6: 输入:"/a//b////c/d//././/.." 输出:"/a/b/c" - * - * @see 简化路径 - */ - public static String simplifyPath(String path) { - if (path.equals("/")) { - return path; - } - - if (path.endsWith("/")) { - path = path.substring(0, path.length() - 1); - } - - if (path.startsWith("/../")) { - path = path.replaceFirst("/../", "/"); - } - - path = path.replaceAll("//", "/"); - return path; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" index 7fb7546..b4121a7 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" @@ -1,10 +1,8 @@ package io.github.dunwu.algorithm.tree.bstree; -import cn.hutool.json.JSONUtil; import io.github.dunwu.algorithm.tree.TreeNode; import org.junit.jupiter.api.Assertions; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" index 6929f65..47bedb7 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" @@ -3,10 +3,6 @@ import io.github.dunwu.algorithm.tree.TreeNode; import org.junit.jupiter.api.Assertions; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - /** * 二叉搜索树结点最小距离 * diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" index 37b294f..860155a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" @@ -1,7 +1,6 @@ package io.github.dunwu.algorithm.tree.btree.bfs; import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; import java.util.LinkedList; import java.util.Queue; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\225.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\225.java" index e09b2d4..37abde6 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\225.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\225.java" @@ -4,10 +4,7 @@ import org.junit.jupiter.api.Assertions; import java.util.ArrayList; -import java.util.Arrays; import java.util.LinkedList; -import java.util.List; -import java.util.Queue; /** * LCR 149. 彩灯装饰记录 I diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" index f4a79ee..e8adf03 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" @@ -6,7 +6,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Map; /** * 508. 出现次数最多的子树元素和 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" index 075881f..c97a2f8 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" @@ -4,13 +4,10 @@ import org.junit.jupiter.api.Assertions; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; -import java.util.stream.Stream; /** * 1110. 删点成林 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" index 5ac28da..90fb4f9 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" @@ -3,8 +3,6 @@ import io.github.dunwu.algorithm.tree.TreeNode; import org.junit.jupiter.api.Assertions; -import java.util.List; - /** * 998. 最大二叉树 II * diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" index 3c76bba..190a86a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" @@ -1,6 +1,5 @@ package io.github.dunwu.algorithm.tree.btree.divide; -import io.github.dunwu.algorithm.tree.TreeNode; import org.junit.jupiter.api.Assertions; import java.util.Arrays; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" index 3ac124c..908fd91 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" @@ -3,10 +3,6 @@ import io.github.dunwu.algorithm.tree.TreeNode; import org.junit.jupiter.api.Assertions; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; - /** * 1457. 二叉树中的伪回文路径 * diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" index 844aeac..58ab169 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" @@ -3,8 +3,6 @@ import io.github.dunwu.algorithm.tree.TreeNode; import org.junit.jupiter.api.Assertions; -import java.util.ArrayList; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" index a29aa65..7eb9b65 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" @@ -32,19 +32,15 @@ public static void main(String[] args) { static class Solution { public void flatten(TreeNode root) { - - // 【校验】 + // base case if (root == null) { return; } - // 【前序】 - // 左子树展开为链表 + // 利用定义,把左右子树拉平 flatten(root.left); - // 【中序】 - // 右子树展开为链表 flatten(root.right); - // 【后序】 - // 1. 此时,左右子树已展开为链表 + // *** 后序遍历位置 *** + // 1、左右子树已经被拉平成一条链表 TreeNode left = root.left; TreeNode right = root.right; @@ -52,7 +48,7 @@ public void flatten(TreeNode root) { root.left = null; root.right = left; - // 3. 将旧右子树接到新右子树末端 + // 3、将原先的右子树接到当前右子树的末端 TreeNode p = root; while (p.right != null) { p = p.right; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" index 3bede39..4eac5e3 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" @@ -3,7 +3,6 @@ import io.github.dunwu.algorithm.tree.TreeNode; import org.junit.jupiter.api.Assertions; -import java.util.Arrays; import java.util.LinkedList; /** @@ -33,36 +32,54 @@ static class Solution { public static final String SEP = ","; public static final String NULL = "null"; + // 主函数,将二叉树序列化为字符串 public String serialize(TreeNode root) { StringBuilder sb = new StringBuilder(); serialize(root, sb); return sb.toString(); } + // 辅助函数,将二叉树存入 StringBuilder void serialize(TreeNode root, StringBuilder sb) { if (root == null) { sb.append(NULL).append(SEP); return; } + + // ****** 前序位置 ******** sb.append(root.val).append(SEP); + + // *********************** + serialize(root.left, sb); serialize(root.right, sb); } + // 主函数,将字符串反序列化为二叉树结构 public TreeNode deserialize(String data) { - LinkedList values = new LinkedList<>(Arrays.asList(data.split(SEP))); - return deserialize(values); + // 将字符串转化成列表 + LinkedList nodes = new LinkedList<>(); + for (String s : data.split(SEP)) { + nodes.addLast(s); + } + return deserialize(nodes); } - public TreeNode deserialize(LinkedList values) { - if (values == null || values.isEmpty()) { return null; } - String val = values.removeFirst(); - if (val.equals(NULL)) { - return null; - } - TreeNode root = new TreeNode(Integer.parseInt(val)); - root.left = deserialize(values); - root.right = deserialize(values); + // 辅助函数,通过 nodes 列表构造二叉树 + TreeNode deserialize(LinkedList nodes) { + if (nodes.isEmpty()) return null; + + // ****** 前序位置 ******** + // 列表最左侧就是根节点 + String first = nodes.removeFirst(); + if (first.equals(NULL)) return null; + TreeNode root = new TreeNode(Integer.parseInt(first)); + + // ********************* + + root.left = deserialize(nodes); + root.right = deserialize(nodes); + return root; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" index de506ae..2c934ef 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" @@ -21,31 +21,20 @@ public static void main(String[] args) { static class Solution { - int max = 0; + int res = 0; public int diameterOfBinaryTree(TreeNode root) { - max = 0; - traverse(root); - return max; + res = 0; + dfs(root); + return res; } - public void traverse(TreeNode root) { - if (root == null) { return; } - - traverse(root.left); - traverse(root.right); - - int left = maxDepth(root.left); - int right = maxDepth(root.right); - max = Math.max(max, left + right); - } - - public int maxDepth(TreeNode root) { - if (root == null) { return 0; } - if (root.left == null && root.right == null) { return 1; } - int left = maxDepth(root.left); - int right = maxDepth(root.right); - return Math.max(left, right) + 1; + public int dfs(TreeNode root) { + if (root == null) { return -1; } + int left = dfs(root.left) + 1; + int right = dfs(root.right) + 1; + res = Math.max(res, left + right); + return Math.max(left, right); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" index 1012c25..9ac1276 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" @@ -3,8 +3,6 @@ import io.github.dunwu.algorithm.tree.TreeNode; import org.junit.jupiter.api.Assertions; -import java.util.List; - /** * 654. 最大二叉树 * @@ -16,34 +14,30 @@ public class 最大二叉树 { public static void main(String[] args) { Solution s = new Solution(); TreeNode output = s.constructMaximumBinaryTree(new int[] { 3, 2, 1, 6, 0, 5 }); - List outputList = TreeNode.toValueList(output); - Assertions.assertArrayEquals(new Integer[] { 6, 3, 5, null, 2, 0, null, null, 1 }, outputList.toArray()); - - TreeNode root = s.constructMaximumBinaryTree(new int[] { 3, 2, 1 }); - List list = TreeNode.toValueList(root); - Assertions.assertArrayEquals(new Integer[] { 3, null, 2, null, 1 }, list.toArray()); + Assertions.assertEquals(TreeNode.buildTree(6, 3, 5, null, 2, 0, null, null, 1), output); + TreeNode output2 = s.constructMaximumBinaryTree(new int[] { 3, 2, 1 }); + Assertions.assertEquals(TreeNode.buildTree(3, null, 2, null, 1), output2); } static class Solution { public TreeNode constructMaximumBinaryTree(int[] nums) { - if (nums == null || nums.length == 0) { return null; } - return build(nums, 0, nums.length - 1); + return dfs(nums, 0, nums.length - 1); } - public TreeNode build(int[] nums, int low, int high) { - if (low > high) { return null; } - int mid = 0; - int max = Integer.MIN_VALUE; - for (int i = low; i <= high; i++) { + public TreeNode dfs(int[] nums, int start, int end) { + if (start > end) { return null; } + int max = -1; + int maxIndex = start; + for (int i = start; i <= end; i++) { if (nums[i] > max) { + maxIndex = i; max = nums[i]; - mid = i; } } - TreeNode root = new TreeNode(max); - root.left = build(nums, low, mid - 1); - root.right = build(nums, mid + 1, high); + TreeNode root = new TreeNode(nums[maxIndex]); + root.left = dfs(nums, start, maxIndex - 1); + root.right = dfs(nums, maxIndex + 1, end); return root; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\345\215\225\350\257\215\346\220\234\347\264\242II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\345\215\225\350\257\215\346\220\234\347\264\242II.java" index 2f9d3d1..3ad1f6e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\345\215\225\350\257\215\346\220\234\347\264\242II.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\345\215\225\350\257\215\346\220\234\347\264\242II.java" @@ -2,7 +2,11 @@ import org.junit.jupiter.api.Assertions; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * @author Zhang Peng diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java index 53b5d8a..2a581a3 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java @@ -1,8 +1,6 @@ package io.github.dunwu.algorithm.util; import lombok.extern.slf4j.Slf4j; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; @@ -38,49 +36,24 @@ public static int[][] toMatrixArray(List> listlist) { return arr; } - public static void debugLogArray(T[] list, int begin, int end, String tip) { - String content = tip + getArrayString(list, begin, end); - if (log.isDebugEnabled()) { - log.debug(content); - } + public static void printArray(T[] arr, int begin, int end, String tip) { + System.out.printf("%s -> %s\n", tip, getArrayString(arr, begin, end)); } - public static String getArrayString(T[] list) { - return getArrayString(list, 0, list.length); + public static String getArrayString(T[] arr) { + return getArrayString(arr, 0, arr.length); } - public static String getArrayString(T[] list, int begin, int end) { + public static String getArrayString(T[] arr, int begin, int end) { StringBuilder sb = new StringBuilder(); - sb.append("\n"); - for (int i = 0; i < begin; i++) { - sb.append("\t"); - } int count = 0; for (int i = begin; i <= end; i++) { - sb.append(list[i] + "\t"); - if (++count == 10) { - sb.append("\n"); - count = 0; - } - } - - return sb.toString(); - } - - public static String getArrayString(int[] list, int begin, int end) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < begin; i++) { - sb.append("\t"); - } - int count = 0; - for (int i = begin; i < end; i++) { - sb.append(list[i] + "\t"); - if (++count == 10) { + if (count != 0 && count % 10 == 0) { sb.append("\n"); - count = 0; } + sb.append("\t" + arr[i]); + count++; } - sb.append(list[end]); return sb.toString(); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/\346\213\254\345\217\267\347\224\237\346\210\220.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/\346\213\254\345\217\267\347\224\237\346\210\220.java" deleted file mode 100644 index 0b79ae4..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/\346\213\254\345\217\267\347\224\237\346\210\220.java" +++ /dev/null @@ -1,42 +0,0 @@ -package io.github.dunwu.algorithm; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * @author Zhang Peng - * @since 2020-07-03 - */ -public class 括号生成 { - - public static void main(String[] args) { - List list1 = Collections.singletonList("()"); - List list2 = new ArrayList<>(); - list2.add("(())"); - list2.add("()()"); - Assertions.assertArrayEquals(list1.toArray(), generateParenthesis(1).toArray()); - Assertions.assertArrayEquals(list2.toArray(), generateParenthesis(2).toArray()); - } - - public static List generateParenthesis(int n) { - List list = new ArrayList<>(); - generateOneByOne(list, 0, 0, n, ""); - return list; - } - - private static void generateOneByOne(List list, int left, int right, int n, String str) { - // 因为括号必然成对出现,所以左括号数和右括号都等于 N,即符合条件 - if (left == n && right == n) { - list.add(str); - return; - } - // 左括号数小于 N,就累加,将其 ( 加入字符串 - if (left < n) generateOneByOne(list, left + 1, right, n, str + "("); - // 右括号数小于 N 并且小于左括号数(右括号数多于左括号数,则语义不合法),就累加,将其 ) 加入字符串 - if (right < n && right < left) generateOneByOne(list, left, right + 1, n, str + ")"); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java index d1a04f4..2783f81 100644 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java +++ b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java @@ -1,6 +1,13 @@ package io.github.dunwu.algorithm.sort; -import io.github.dunwu.algorithm.sort.strategy.*; +import io.github.dunwu.algorithm.sort.strategy.BubbleSort; +import io.github.dunwu.algorithm.sort.strategy.BubbleSort2; +import io.github.dunwu.algorithm.sort.strategy.HeapSort; +import io.github.dunwu.algorithm.sort.strategy.InsertSort; +import io.github.dunwu.algorithm.sort.strategy.MergeSort; +import io.github.dunwu.algorithm.sort.strategy.QuickSort; +import io.github.dunwu.algorithm.sort.strategy.SelectionSort; +import io.github.dunwu.algorithm.sort.strategy.ShellSort; import io.github.dunwu.algorithm.util.ArrayUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; @@ -21,29 +28,23 @@ public class SortStrategyTest { /** * 随机样本一 */ - private static Integer[] origin01; - - private static Integer[] target01; - - private static Integer[] expected01; + private static Integer[] s1; + private static Integer[] t1; + private static Integer[] e1; /** * 随机样本二 */ - private static Integer[] origin02; - - private static Integer[] target02; - - private static Integer[] expected02; + private static Integer[] s2; + private static Integer[] t2; + private static Integer[] e2; /** * 随机样本三 */ - private static Integer[] origin03; - - private static Integer[] target03; - - private static Integer[] expected03; + private static Integer[] s3; + private static Integer[] t3; + private static Integer[] e3; /** * 生成随机数组样本,并调用 JDK api 生成期望的有序数组 @@ -51,19 +52,31 @@ public class SortStrategyTest { @BeforeAll public static void beforeClass() { // 在 [0, 100] 间生成长度为 10 的存在重复的随机数组 - origin01 = ArrayUtil.randomRepeatIntegerArray(0, 10, 9); - expected01 = Arrays.copyOf(origin01, origin01.length); - Arrays.sort(expected01); + s1 = ArrayUtil.randomRepeatIntegerArray(0, 10, 5); + e1 = Arrays.copyOf(s1, s1.length); + Arrays.sort(e1); // 在 [0, 100] 间生成长度为 17 的不重复的随机数组 - origin02 = ArrayUtil.randomNoRepeatIntegerArray(0, 100, 17); - expected02 = Arrays.copyOf(origin02, origin02.length); - Arrays.sort(expected02); + s2 = ArrayUtil.randomNoRepeatIntegerArray(0, 100, 10); + e2 = Arrays.copyOf(s2, s2.length); + Arrays.sort(e2); // 在 [0, 100] 间生成长度为 100 的不重复的随机数组 - origin03 = ArrayUtil.randomNoRepeatIntegerArray(0, 100, 100); - expected03 = Arrays.copyOf(origin03, origin03.length); - Arrays.sort(expected03); + s3 = ArrayUtil.randomNoRepeatIntegerArray(0, 100, 30); + e3 = Arrays.copyOf(s3, s3.length); + Arrays.sort(e3); + } + + /** + * 注入 SortStrategy,执行对三个样本的排序测试 + */ + private void executeSort(SortStrategy strategy) { + strategy.sort(t1); + Assertions.assertArrayEquals(e1, t1); + strategy.sort(t2); + Assertions.assertArrayEquals(e2, t2); + strategy.sort(t3); + Assertions.assertArrayEquals(e3, t3); } /** @@ -71,9 +84,9 @@ public static void beforeClass() { */ @BeforeEach public void before() { - target01 = Arrays.copyOf(origin01, origin01.length); - target02 = Arrays.copyOf(origin02, origin02.length); - target03 = Arrays.copyOf(origin03, origin03.length); + t1 = Arrays.copyOf(s1, s1.length); + t2 = Arrays.copyOf(s2, s2.length); + t3 = Arrays.copyOf(s3, s3.length); } @Test @@ -82,18 +95,6 @@ public void testBubbleSort() { executeSort(strategy); } - /** - * 注入 SortStrategy,执行对三个样本的排序测试 - */ - private void executeSort(SortStrategy strategy) { - strategy.sort(target01); - Assertions.assertArrayEquals(expected01, target01); - strategy.sort(target02); - Assertions.assertArrayEquals(expected02, target02); - strategy.sort(target03); - Assertions.assertArrayEquals(expected03, target03); - } - @Test public void testBubbleSort2() { SortStrategy strategy = new SortStrategy(new BubbleSort2()); diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/StringAlgorithmTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/StringAlgorithmTest.java deleted file mode 100644 index b68a837..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/StringAlgorithmTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package io.github.dunwu.algorithm.str; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * @author Zhang Peng - * @since 2020-05-12 - */ -public class StringAlgorithmTest { - - @Test - public void isUniqueTest() { - Assertions.assertTrue(StringAlgorithm.isUnique("")); - Assertions.assertTrue(StringAlgorithm.isUnique("abc")); - Assertions.assertFalse(StringAlgorithm.isUnique("leetcode")); - } - - @Test - public void checkPermutationTest() { - Assertions.assertTrue(StringAlgorithm.checkPermutation("abc", "bca")); - Assertions.assertFalse(StringAlgorithm.checkPermutation("abc", "bad")); - Assertions.assertFalse(StringAlgorithm.checkPermutation( - "krqdpwdvgfuogtobtyylexrebrwzynzlpkotoqmokfpqeibbhzdjcwpgprzpqersmmdxdmwssfbfwmmvrxkjyjteirloxpbiopso", - "pyymgxtdqzqxxkmirptmbewjobpslwkbmmzfbwzmltowevsofkydrejdpcoripjlewoqzgusvypotrdkepbqspxdmoyrfnyrbrof")); - Assertions.assertFalse(StringAlgorithm.checkPermutation( - "jzvthzihsvghjhbrpfhdwixmyaxjrdzfvnhpmyrbqjpdffykqgahgzpjwvouurr", - "hhqhxjyrghjjsmduaxppwrqkikqnfdrzjowapehtbyrgrfyprrfrebzduxvvhhu")); - } - - @Test - public void replaceSpacesTest() { - Assertions.assertEquals("Mr%20John%20Smith", StringAlgorithm.replaceSpaces("Mr John Smith ", 13)); - } - - @Test - public void canPermutePalindromeTest() { - Assertions.assertTrue(StringAlgorithm.canPermutePalindrome("tactcoa")); - } - - @Test - public void oneEditAwayTest() { - Assertions.assertTrue(StringAlgorithm.oneEditAway("pale", "ple")); - Assertions.assertFalse(StringAlgorithm.oneEditAway("pales", "pal")); - } - - @Test - public void compressStringTest() { - Assertions.assertEquals("a2b1c5a3", StringAlgorithm.compressString("aabcccccaaa")); - Assertions.assertEquals("abbccd", StringAlgorithm.compressString("abbccd")); - } - - @Test - public void isFlipedStringTest() { - Assertions.assertTrue(StringAlgorithm.isFlipedString("waterbottle", "erbottlewat")); - Assertions.assertTrue(StringAlgorithm.isFlipedString("ab", "ba")); - Assertions.assertFalse(StringAlgorithm.isFlipedString("aa", "aba")); - Assertions.assertTrue(StringAlgorithm.isFlipedString( - "LmMoLrUxaeSgUhqFsicojxzsbbBobkzkigNyzreunviUECVpPaWKUTMfgskTiirzDkLQFQcTmvdeKpeAvypDMTJTGZRcGOlbJDVFlXNmORIJjhhGyMdGnGpefjLinqwESmCexewgloibkZxeTydRnyFRyDPMyPumFjhjuGnNmCKhOnWPYfUBmlppeBcqhoggzPqXcpYRYIuFbCuxpbaScUGYZWZVQxnOChBPIbozFagLalTGGjjAJJnPiMPcMJMxlYfBJBqtejxqXqgHgcoLGqqIaORJrEQMbqlbzddjOWJOyFkksYvdxUBPbzYVrxMKOYPigNwtXWGBqtXxUOCuIpGigRErIkkYbdDKuXmHoIXXWIiisBLwWqdKporlfbcHZicevgpAUOkeiFIeaSoaeXlXGfHFzImzCYunHleAEkzfmAirrMeUGczkBfzHBnrrBoiXVXELXMjOEXkQYJWkzRfTMeAyEKJstkUAuwkywhpDreIfrwQJLWLdAmaSlCLKdGcCjbaPPyHcGNbskyZgRahgieOqmztbakPRBOUHLRSfquGjUtlfbRJfMlOiFKFQcYDJaMgOGlnEQmHtaYDRpcGamZlZqLrAIDdMRPvelfBykZWNCCspjmLPczMQuTSxviiLtOMvdmLXDsffTAYMeVQReYRGoNVViteGksLdYyWLOxTpwqknfysBLASGgPoyGSRsAdXIXmKuWYIUjZeeRKfarTRTFlQDwvzFPFpcEMCxRMWyuySyMPCFFmAnCONFxTsIzQIMhApfVifcxlUTXdCKEKdDeJCfPnmRXTsNoCllqjRMtXBISwfeUMzeLwQwgQbbXvMzGctiBIQciIljKIkzMmnedtLCxaVnfBXEimIlrBqmsvWDEIoWiUFSMxeVgzqkqFJLdywojNkLwWVkIrzneqSPIsIPvwNaXbUfpxegkVhhIKOAdCtmmesmyYGhfJtqadOsGQIBuTOZxHINAMwKuBWikjwEdFDTksuICVTCDHEqvrUWOpgNONVkNkERATbHBonoAbjPFkthfgOTffCzgQrcaEYEkKyFNbBNmwljQFeKIyEPSiHZhlFUaEdYGDcYJgIYpwrevmFKEoqNtRhKSFrQNRJNkNOqjgKCMGYCCbDMMgerlvjanGrovokGfUUWDINbGCsPNINPBFygvDoynpxDZHQVbsXLFNjKmuFlYOhstBGdTsNSgsZVRXUQKrLqSTMCMHobsTZGVYOfGxkVPGbtaiAJostQbRctXJgysaWQuSfvYxwidQuLbkxIaJXIzbWvNDphIbeYBRBGlChLmxVpTezcjYmBkBslMqkEaPYrLROcZrxXiEDiBuLRcqlyNZAfVTlQawPVcqxadDcWKGXuDJUBxsRqoXXqqkzchsqgrguPpJDXrcrbXLIfmucbgWaIwqxwZNyuKJrqcEisRpVeuEdznTJsbQimFLfUQriOYYqaychChJogAZjvLjuDPONzyNzGnnaFyhCVLsxTmRMVVOpfhQqgPArwwOSOIdeiroBBhWUFWvTsdRZYWzTrXpRIWGFgKMaODDnOtLMZmzwxOJfoBlTmngxpBhsDYzUqpMtpknioFZeSBYqiSAVkZqifBQyqYuFoOPUIqdTWtQsotGLhVWKhesGgTVJPXmXqUeFpIpFeVVyOUmJxjiQfppSUKLdwNSoWVPIdzHXbIQvzyhiTUGomjTcVWgxSXyEznahWANjwhalYNnchohNAkAXWkWIVdiKPaAPnkWprRIHmqWfnLnOgUfNhThPmwJymURQHejsnqgdWKRUJZqEwfVnSDMyuHWKTPoNNnTrQhytdYWBsiKfAqWUfgjGQyxpQsRZxuUyaXerBDsJANuEhpNNejoaXrkVDqGrkQMbTogtdHsOHrhmIZajoMZjNwYGlBXrkTOphhvNWArIeyEMYrEkGofZIKQkaMyTLrpuWpjClEsbCEVjmwCEPmdDfFELazsIDopLmsrmXgEROgitmYUDqWqrpNtnhtEcxKsccAYKlhFGtzqwLSxgfXCQykyUEpIqpoVwPizirScwwQSbnhfBDYzVriWYpKZhxLwrHBtrcXsiJgTvRRNIkwJfIRfqZramufpeCQxMTZAhGrQLelrJQhScdqPyKUdNVZTCMdwZzydnInkQgyOiMxkAGqJfKakOOwsbNvIffJxFuGbtIyonefNHCCPAonrPaZihkEeMGZyTembSLsBpLeERBFFwnPhrTXTVvoNRTOwDwIKoBrMAGwPvhHOWlVkZcvSIjjUTuArbxnjkCnqmyQpIxqMqLlXxTKMztlQFxUDWhbpYCexaSyVvtGfwbCMcZgovtHslmazhQJTNQpmomjPYzrRiPGpodFHTiFSjQijeXEeBUEVaggRjTdAyMViqcwKDkUxXtSXuXOKRkYHTgZKyRqBJAcmmhXVyiBvceeOyfGauHXnnPAWOrNylLbPBbuxRfVTwOXJxQslgmldRKAICHRgOxvuaAPOtgDYBWFXABExfUyvuuxpMBWHFSyWCLzWcKQfntdciWKBfLTxYxWtVVYoNiJbFOawEEJChUCEoWLkXQCjEnXmOYOBTnXNxgCBcyKUuftmPyQgByuuDSOUMSbQFjuYOrQmLRVqYODLxhJyuhJnoM", - "xzsbbBobkzkigNyzreunviUECVpPaWKUTMfgskTiirzDkLQFQcTmvdeKpeAvypDMTJTGZRcGOlbJDVFlXNmORIJjhhGyMdGnGpefjLinqwESmCexewgloibkZxeTydRnyFRyDPMyPumFjhjuGnNmCKhOnWPYfUBmlppeBcqhoggzPqXcpYRYIuFbCuxpbaScUGYZWZVQxnOChBPIbozFagLalTGGjjAJJnPiMPcMJMxlYfBJBqtejxqXqgHgcoLGqqIaORJrEQMbqlbzddjOWJOyFkksYvdxUBPbzYVrxMKOYPigNwtXWGBqtXxUOCuIpGigRErIkkYbdDKuXmHoIXXWIiisBLwWqdKporlfbcHZicevgpAUOkeiFIeaSoaeXlXGfHFzImzCYunHleAEkzfmAirrMeUGczkBfzHBnrrBoiXVXELXMjOEXkQYJWkzRfTMeAyEKJstkUAuwkywhpDreIfrwQJLWLdAmaSlCLKdGcCjbaPPyHcGNbskyZgRahgieOqmztbakPRBOUHLRSfquGjUtlfbRJfMlOiFKFQcYDJaMgOGlnEQmHtaYDRpcGamZlZqLrAIDdMRPvelfBykZWNCCspjmLPczMQuTSxviiLtOMvdmLXDsffTAYMeVQReYRGoNVViteGksLdYyWLOxTpwqknfysBLASGgPoyGSRsAdXIXmKuWYIUjZeeRKfarTRTFlQDwvzFPFpcEMCxRMWyuySyMPCFFmAnCONFxTsIzQIMhApfVifcxlUTXdCKEKdDeJCfPnmRXTsNoCllqjRMtXBISwfeUMzeLwQwgQbbXvMzGctiBIQciIljKIkzMmnedtLCxaVnfBXEimIlrBqmsvWDEIoWiUFSMxeVgzqkqFJLdywojNkLwWVkIrzneqSPIsIPvwNaXbUfpxegkVhhIKOAdCtmmesmyYGhfJtqadOsGQIBuTOZxHINAMwKuBWikjwEdFDTksuICVTCDHEqvrUWOpgNONVkNkERATbHBonoAbjPFkthfgOTffCzgQrcaEYEkKyFNbBNmwljQFeKIyEPSiHZhlFUaEdYGDcYJgIYpwrevmFKEoqNtRhKSFrQNRJNkNOqjgKCMGYCCbDMMgerlvjanGrovokGfUUWDINbGCsPNINPBFygvDoynpxDZHQVbsXLFNjKmuFlYOhstBGdTsNSgsZVRXUQKrLqSTMCMHobsTZGVYOfGxkVPGbtaiAJostQbRctXJgysaWQuSfvYxwidQuLbkxIaJXIzbWvNDphIbeYBRBGlChLmxVpTezcjYmBkBslMqkEaPYrLROcZrxXiEDiBuLRcqlyNZAfVTlQawPVcqxadDcWKGXuDJUBxsRqoXXqqkzchsqgrguPpJDXrcrbXLIfmucbgWaIwqxwZNyuKJrqcEisRpVeuEdznTJsbQimFLfUQriOYYqaychChJogAZjvLjuDPONzyNzGnnaFyhCVLsxTmRMVVOpfhQqgPArwwOSOIdeiroBBhWUFWvTsdRZYWzTrXpRIWGFgKMaODDnOtLMZmzwxOJfoBlTmngxpBhsDYzUqpMtpknioFZeSBYqiSAVkZqifBQyqYuFoOPUIqdTWtQsotGLhVWKhesGgTVJPXmXqUeFpIpFeVVyOUmJxjiQfppSUKLdwNSoWVPIdzHXbIQvzyhiTUGomjTcVWgxSXyEznahWANjwhalYNnchohNAkAXWkWIVdiKPaAPnkWprRIHmqWfnLnOgUfNhThPmwJymURQHejsnqgdWKRUJZqEwfVnSDMyuHWKTPoNNnTrQhytdYWBsiKfAqWUfgjGQyxpQsRZxuUyaXerBDsJANuEhpNNejoaXrkVDqGrkQMbTogtdHsOHrhmIZajoMZjNwYGlBXrkTOphhvNWArIeyEMYrEkGofZIKQkaMyTLrpuWpjClEsbCEVjmwCEPmdDfFELazsIDopLmsrmXgEROgitmYUDqWqrpNtnhtEcxKsccAYKlhFGtzqwLSxgfXCQykyUEpIqpoVwPizirScwwQSbnhfBDYzVriWYpKZhxLwrHBtrcXsiJgTvRRNIkwJfIRfqZramufpeCQxMTZAhGrQLelrJQhScdqPyKUdNVZTCMdwZzydnInkQgyOiMxkAGqJfKakOOwsbNvIffJxFuGbtIyonefNHCCPAonrPaZihkEeMGZyTembSLsBpLeERBFFwnPhrTXTVvoNRTOwDwIKoBrMAGwPvhHOWlVkZcvSIjjUTuArbxnjkCnqmyQpIxqMqLlXxTKMztlQFxUDWhbpYCexaSyVvtGfwbCMcZgovtHslmazhQJTNQpmomjPYzrRiPGpodFHTiFSjQijeXEeBUEVaggRjTdAyMViqcwKDkUxXtSXuXOKRkYHTgZKyRqBJAcmmhXVyiBvceeOyfGauHXnnPAWOrNylLbPBbuxRfVTwOXJxQslgmldRKAICHRgOxvuaAPOtgDYBWFXABExfUyvuuxpMBWHFSyWCLzWcKQfntdciWKBfLTxYxWtVVYoNiJbFOawEEJChUCEoWLkXQCjEnXmOYOBTnXNxgCBcyKUuftmPyQgByuuDSOUMSbQFjuYOrQmLRVqYODLxhJyuhJnoMLmMoLrUxaeSgUhqFsicoj")); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/string/StringAlgorithmTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/string/StringAlgorithmTest.java index dcb56d4..7aa1f30 100644 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/string/StringAlgorithmTest.java +++ b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/string/StringAlgorithmTest.java @@ -1,5 +1,6 @@ package io.github.dunwu.algorithm.string; +import io.github.dunwu.algorithm.str.StringAlgorithm; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; From e2b71d43a78c5778e5bec1daf50af668ea0fc73f Mon Sep 17 00:00:00 2001 From: dunwu Date: Tue, 2 Dec 2025 22:26:31 +0800 Subject: [PATCH 17/21] =?UTF-8?q?feat:=20leetcode=20=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 214 ++++++----- ...\347\232\204\350\267\257\345\276\204.java" | 27 +- ...\346\234\211\350\212\202\347\202\271.java" | 28 +- ...\346\234\211\350\267\257\345\276\204.java" | 64 ++++ ...\346\211\200\346\234\211\350\276\271.java" | 38 +- ...\345\256\236\347\216\260\345\233\276.java" | 40 +- ...\350\257\276\347\250\213\350\241\250.java" | 92 +++++ ...\350\275\254\346\225\264\346\225\260.java" | 34 ++ .../{ => demo}/DoublyLinkedList.java | 2 +- .../{ => demo}/LRUBaseLinkedList.java | 2 +- .../linkedlist/{ => demo}/LRUBasedArray.java | 2 +- .../linkedlist/{ => demo}/MyLinkedList.java | 2 +- .../{ => demo}/SinglyLinkedList.java | 2 +- ...\350\241\250\347\244\272\344\276\213.java" | 2 +- ...\350\241\250\347\244\272\344\276\213.java" | 2 +- ...\345\272\217\351\223\276\350\241\250.java" | 72 ++++ ...\346\226\207\351\223\276\350\241\250.java" | 45 +-- ...\350\275\254\351\223\276\350\241\250.java" | 10 +- ...\345\201\266\351\223\276\350\241\250.java" | 46 +++ ...\345\244\215\350\212\202\347\202\271.java" | 45 +++ ...\350\241\250\345\205\203\347\264\240.java" | 40 ++ ...\350\275\254\346\225\264\346\225\260.java" | 89 ----- ...\345\244\215\345\205\203\347\264\240.java" | 94 ----- ...\345\201\266\351\223\276\350\241\250.java" | 33 -- ...\345\272\217\351\223\276\350\241\250.java" | 96 ----- ...\345\244\215\350\212\202\347\202\271.java" | 63 ---- ...\350\241\250\345\205\203\347\264\240.java" | 81 ---- ...\350\256\241\351\223\276\350\241\250.java" | 132 ------- .../io/github/dunwu/algorithm/tree/BTree.java | 350 +++++++++++------- .../github/dunwu/algorithm/tree/BaseCase.java | 2 +- .../github/dunwu/algorithm/tree/IntBTree.java | 175 --------- .../tree/{NAryTree.java => NTree.java} | 8 +- .../io/github/dunwu/algorithm/tree/Node.java | 16 + ...\345\244\247\346\267\261\345\272\246.java" | 55 --- ...\346\220\234\347\264\242\346\240\221.java" | 29 +- ...346\220\234\347\264\242\346\240\2212.java" | 25 +- ...\351\224\256\345\200\274\345\222\214.java" | 77 ++++ ...\345\205\261\347\245\226\345\205\210.java" | 18 +- ...\345\260\217\350\267\235\347\246\273.java" | 47 ++- ...\345\244\247\345\222\214\346\240\221.java" | 47 +++ ...\347\232\204\350\212\202\347\202\271.java" | 28 +- ...\346\220\234\347\264\242\346\240\221.java" | 42 +-- ...\346\220\234\347\264\242\346\240\221.java" | 13 +- ...\347\232\204\347\273\223\347\202\271.java" | 87 +++++ ...\346\217\222\345\205\245\345\231\250.java" | 77 ++-- ...\346\240\221\345\211\252\346\236\235.java" | 4 +- ...\345\205\203\347\264\240\345\222\214.java" | 29 +- ...\347\202\271\346\210\220\346\236\227.java" | 33 +- ...\344\272\214\345\217\211\346\240\221.java" | 7 +- ...\345\272\217\345\210\227\345\214\226.java" | 36 +- ...\347\232\204\347\233\264\345\276\204.java" | 21 +- ...\345\272\217\351\201\215\345\216\206.java" | 47 +++ ...\345\272\217\351\201\215\345\216\206.java" | 47 +++ ...\345\272\217\351\201\215\345\216\206.java" | 49 +-- ...\345\244\247\346\267\261\345\272\246.java" | 49 +++ .../algorithm/list/DoubleLinkListTests.java | 2 +- .../algorithm/list/SingleLinkListTests.java | 2 +- .../dunwu/algorithm/tree/BTreeDemoTests.java | 75 ---- .../dunwu/algorithm/tree/BTreeTests.java | 20 +- 59 files changed, 1479 insertions(+), 1435 deletions(-) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/dfs/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" (67%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/base/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/{ => demo}/DoublyLinkedList.java (99%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/{ => demo}/LRUBaseLinkedList.java (98%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/{ => demo}/LRUBasedArray.java (98%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/{ => demo}/MyLinkedList.java (99%) rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/{ => demo}/SinglyLinkedList.java (99%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" (98%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" (98%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/divide/\346\216\222\345\272\217\351\223\276\350\241\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\245\207\345\201\266\351\223\276\350\241\250.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\245\207\345\201\266\351\223\276\350\241\250.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\346\216\222\345\272\217\351\223\276\350\241\250.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\350\256\276\350\256\241\351\223\276\350\241\250.java" delete mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/IntBTree.java rename codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/{NAryTree.java => NTree.java} (75%) delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/N\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\345\255\220\346\240\221\347\232\204\346\234\200\345\244\247\351\224\256\345\200\274\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\273\216\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\345\210\260\346\233\264\345\244\247\345\222\214\346\240\221.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\344\270\255\346\211\200\346\234\211\350\267\235\347\246\273\344\270\272K\347\232\204\347\273\223\347\202\271.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" (56%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" delete mode 100644 codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BTreeDemoTests.java diff --git a/README.md b/README.md index ceb1146..954d5c9 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,12 @@ ### 链表 +#### 基础操作 + +| 题目 | 难度 | 掌握度 | +| --------------------------------------------------------------------------------------------------------- | ---- | ------ | +| [1290. 二进制链表转整数](https://leetcode.cn/problems/convert-binary-number-in-a-linked-list-to-integer/) | 💚 | ✔️ | + #### 双指针技巧 | 题目 | 难度 | 掌握度 | @@ -73,6 +79,9 @@ | [86. 分隔链表](https://leetcode.cn/problems/partition-list/) | 💛 | ✔️ | | [876. 链表的中间结点](https://leetcode.cn/problems/middle-of-the-linked-list/) | 💚 | ✔️ | | [面试题 02. 返回倒数第 k 个节点](https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/) | 💚 | ✔️ | +| [面试题 02.01. 移除重复节点](https://leetcode.cn/problems/remove-duplicate-node-lcci/) | 💚 | ✔️ | +| [203. 移除链表元素](https://leetcode.cn/problems/remove-linked-list-elements/) | 💚 | ✔️ | +| [328. 奇偶链表](https://leetcode.cn/problems/odd-even-linked-list/) | 💛 | ✔️ | | [82. 删除排序链表中的重复元素 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/) | 💛 | ✔️ | | [2. 两数相加](https://leetcode.cn/problems/add-two-numbers/) | 💛 | ✔️ | | [445. 两数相加 II](https://leetcode.cn/problems/add-two-numbers-ii/) | 💛 | ✔️ | @@ -86,11 +95,17 @@ | [92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/) | 💛 | ✔️ | | [25. K 个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group/) | ❤️ | ❗ | +#### 分治 + +| 题目 | 难度 | 掌握度 | +| -------------------------------------------------------- | ---- | ------ | +| [148. 排序链表](https://leetcode.cn/problems/sort-list/) | 💛 | ❌ | + #### 回文链表 | 题目 | 难度 | 掌握度 | | --------------------------------------------------------------------- | ---- | ------ | -| [234. 回文链表](https://leetcode.cn/problems/palindrome-linked-list/) | 💚 | ❌ | +| [234. 回文链表](https://leetcode.cn/problems/palindrome-linked-list/) | 💚 | ✔️ | ### 数组 @@ -206,13 +221,13 @@ | [496. 下一个更大元素 I](https://leetcode.cn/problems/next-greater-element-i/) | 💚 | ❗ | | [503. 下一个更大元素 II](https://leetcode.cn/problems/next-greater-element-ii/) | 💛 | ❗ | | [739. 每日温度](https://leetcode.cn/problems/daily-temperatures/)
[剑指 Offer II 038. 每日温度](https://leetcode.cn/problems/iIQa4I/) | 💛 | ✔️ | -| [1019. 链表中的下一个更大节点](https://leetcode.cn/problems/next-greater-node-in-linked-list/) | 💛 | ✔️ | +| [1019. 链表中的下一个更大节点](https://leetcode.cn/problems/next-greater-node-in-linked-list/) | 💛 | ✔️ | | [1944. 队列中可以看到的人数](https://leetcode.cn/problems/number-of-visible-people-in-a-queue/) | ❤️ | | -| [1475. 商品折扣后的最终价格](https://leetcode.cn/problems/final-prices-with-a-special-discount-in-a-shop/) | 💛 | ✔️ | -| [901. 股票价格跨度](https://leetcode.cn/problems/online-stock-span/) | 💛 | ❌ | -| [402. 移掉 K 位数字](https://leetcode.cn/problems/remove-k-digits/) | 💛 | ❌ | -| [853. 车队](https://leetcode.cn/problems/car-fleet/) | 💛 | ❌ | -| [581. 最短无序连续子数组](https://leetcode.cn/problems/shortest-unsorted-continuous-subarray/) | 💛 | ❌ | +| [1475. 商品折扣后的最终价格](https://leetcode.cn/problems/final-prices-with-a-special-discount-in-a-shop/) | 💛 | ✔️ | +| [901. 股票价格跨度](https://leetcode.cn/problems/online-stock-span/) | 💛 | ❌ | +| [402. 移掉 K 位数字](https://leetcode.cn/problems/remove-k-digits/) | 💛 | ❌ | +| [853. 车队](https://leetcode.cn/problems/car-fleet/) | 💛 | ❌ | +| [581. 最短无序连续子数组](https://leetcode.cn/problems/shortest-unsorted-continuous-subarray/) | 💛 | ❌ | #### 单调队列 @@ -224,123 +239,134 @@ | [862. 和至少为 K 的最短子数组](https://leetcode.cn/problems/shortest-subarray-with-sum-at-least-k/) | ❤️ | | | [918. 环形子数组的最大和](https://labuladong.online/algo/problem-set/monotonic-queue/#slug_maximum-sum-circular-subarray) | 💛 | | -### 二叉树 +### 树 -#### 基础 +#### 二叉树 | 题目 | 难度 | 掌握度 | -| ---------------------------------------------------------------------------------------------------- | ------ | ------ | +| ---------------------------------------------------------------------------------------------------- | ---- | ------ | | [104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) | 💚 | ✔️ | | [111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/) | 💚 | ✔️ | -| [543. 二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree/) | 💚 | ❌ | -| [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/) | 💛 | ✔️ | +| [543. 二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree/) | 💚 | ✔️ | +| [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/) | 💛 | ✔️ | | [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/) | 💚 | ✔️ | | [654. 最大二叉树](https://leetcode.cn/problems/maximum-binary-tree/) | 💛 | ✔️ | -| [297. 二叉树的序列化与反序列化](https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/) | ❤️ | ❗ | +| [297. 二叉树的序列化与反序列化](https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/) | ❤️ | ❗ | | [222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/) | 💚 | ✔️ | #### DFS -| 题目 | 掌握度 | -| -------------------------------------------------------------------------------------- | ------ | -| [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/) | ✔️ | -| [94. 二叉树的中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal/) | ✔️ | -| [145. 二叉树的后序遍历](https://leetcode.cn/problems/binary-tree-postorder-traversal/) | ✔️ | -| [872. 叶子相似的树](https://leetcode.cn/problems/leaf-similar-trees/) | ✔️ | +| 题目 | 难度 | 掌握度 | +| -------------------------------------------------------------------------------------- | ---- | ------ | +| [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/) | 💚 | ✔️ | +| [94. 二叉树的中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal/) | 💚 | ✔️ | +| [145. 二叉树的后序遍历](https://leetcode.cn/problems/binary-tree-postorder-traversal/) | 💚 | ✔️ | +| [872. 叶子相似的树](https://leetcode.cn/problems/leaf-similar-trees/) | 💚 | ✔️ | #### 用「遍历」思维解题 -| 题目 | 掌握度 | -| ----------------------------------------------------------------------------------------------------- | ------ | -| [257. 二叉树的所有路径](https://leetcode.cn/problems/binary-tree-paths/) | ✔️ | -| [129. 求根节点到叶节点数字之和](https://leetcode.cn/problems/sum-root-to-leaf-numbers/) | ✔️ | -| [199. 二叉树的右视图](https://leetcode.cn/problems/binary-tree-right-side-view/) | ✔️ | -| [988. 从叶结点开始的最小字符串](https://leetcode.cn/problems/smallest-string-starting-from-leaf/) | ✔️ | -| [1022. 从根到叶的二进制数之和](https://leetcode.cn/problems/sum-of-root-to-leaf-binary-numbers/) | ✔️ | -| [1457. 二叉树中的伪回文路径](https://leetcode.cn/problems/pseudo-palindromic-paths-in-a-binary-tree/) | ✔️ | -| [404. 左叶子之和](https://leetcode.cn/problems/sum-of-left-leaves/) | ✔️ | -| [623. 在二叉树中增加一行](https://leetcode.cn/problems/add-one-row-to-tree/) | ✔️ | -| [508. 出现次数最多的子树元素和](https://leetcode.cn/problems/most-frequent-subtree-sum/) | ❌ | -| [563. 二叉树的坡度](https://leetcode.cn/problems/binary-tree-tilt/) | ❗ | -| [814. 二叉树剪枝](https://leetcode.cn/problems/binary-tree-pruning/) | ❌ | -| [1325. 删除给定值的叶子节点](https://leetcode.cn/problems/delete-leaves-with-a-given-value/) | ✔️ | +| 题目 | 难度 | 掌握度 | +| ----------------------------------------------------------------------------------------------------- | ---- | ------ | +| [257. 二叉树的所有路径](https://leetcode.cn/problems/binary-tree-paths/) | 💚 | ✔️ | +| [129. 求根节点到叶节点数字之和](https://leetcode.cn/problems/sum-root-to-leaf-numbers/) | 💛 | ✔️ | +| [199. 二叉树的右视图](https://leetcode.cn/problems/binary-tree-right-side-view/) | 💛 | ✔️ | +| [988. 从叶结点开始的最小字符串](https://leetcode.cn/problems/smallest-string-starting-from-leaf/) | 💛 | ✔️ | +| [1022. 从根到叶的二进制数之和](https://leetcode.cn/problems/sum-of-root-to-leaf-binary-numbers/) | 💚 | ✔️ | +| [1457. 二叉树中的伪回文路径](https://leetcode.cn/problems/pseudo-palindromic-paths-in-a-binary-tree/) | 💛 | ✔️ | +| [404. 左叶子之和](https://leetcode.cn/problems/sum-of-left-leaves/) | 💚 | ✔️ | +| [623. 在二叉树中增加一行](https://leetcode.cn/problems/add-one-row-to-tree/) | 💛 | ✔️ | +| [508. 出现次数最多的子树元素和](https://leetcode.cn/problems/most-frequent-subtree-sum/) | 💛 | ✔️ | +| [563. 二叉树的坡度](https://leetcode.cn/problems/binary-tree-tilt/) | 💚 | ✔️ | +| [814. 二叉树剪枝](https://leetcode.cn/problems/binary-tree-pruning/) | 💛 | ✔️ | +| [1325. 删除给定值的叶子节点](https://leetcode.cn/problems/delete-leaves-with-a-given-value/) | 💛 | ✔️ | #### 用「分解」思维解题 -| 题目 | 掌握度 | -| ------------------------------------------------------------------------------------------------------------------------------- | ------ | -| [105. 从前序与中序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) | ✔️ | -| [106. 从中序与后序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) | ✔️ | -| [889. 根据前序和后序遍历构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-postorder-traversal/) | ✔️ | -| [331. 验证二叉树的前序序列化](https://leetcode.cn/problems/verify-preorder-serialization-of-a-binary-tree/) | ❌ | -| [894. 所有可能的真二叉树](https://leetcode.cn/problems/all-possible-full-binary-trees/) | ❌ | -| [998. 最大二叉树 II](https://leetcode.cn/problems/maximum-binary-tree-ii/) | ❌ | -| [1110. 删点成林](https://leetcode.cn/problems/delete-nodes-and-return-forest/) | ❌ | -| [100. 相同的树](https://leetcode.cn/problems/same-tree/) | ✔️ | -| [101. 对称二叉树](https://leetcode.cn/problems/symmetric-tree/) | ✔️ | -| [951. 翻转等价二叉树](https://leetcode.cn/problems/flip-equivalent-binary-trees/) | ❌ | -| [124. 二叉树中的最大路径和](https://leetcode.cn/problems/binary-tree-maximum-path-sum/) | | +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | +| [105. 从前序与中序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) | 💛 | ✔️ | +| [106. 从中序与后序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) | 💛 | ✔️ | +| [889. 根据前序和后序遍历构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-postorder-traversal/) | 💛 | ✔️ | +| [331. 验证二叉树的前序序列化](https://leetcode.cn/problems/verify-preorder-serialization-of-a-binary-tree/) | 💛 | ❌ | +| [894. 所有可能的真二叉树](https://leetcode.cn/problems/all-possible-full-binary-trees/) | 💛 | ❌ | +| [998. 最大二叉树 II](https://leetcode.cn/problems/maximum-binary-tree-ii/) | 💛 | ❌ | +| [1110. 删点成林](https://leetcode.cn/problems/delete-nodes-and-return-forest/) | 💛 | ❌ | +| [100. 相同的树](https://leetcode.cn/problems/same-tree/) | 💛 | ✔️ | +| [101. 对称二叉树](https://leetcode.cn/problems/symmetric-tree/) | 💛 | ✔️ | +| [951. 翻转等价二叉树](https://leetcode.cn/problems/flip-equivalent-binary-trees/) | 💛 | ❌ | +| [124. 二叉树中的最大路径和](https://leetcode.cn/problems/binary-tree-maximum-path-sum/) | ❤️ | ❌ | #### 用「层序遍历」思维解题 -| 题目 | 掌握度 | -| ------------------------------------------------------------------------------------------------------------------------ | ------ | -| [102. 二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal/) | ✔️ | -| [107. 二叉树的层序遍历 II](https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/) | ✔️ | -| [103. 二叉树的锯齿形层序遍历](https://leetcode.cn/problems/binary-tree-zigzag-level-order-traversal/) | ✔️ | -| [116. 填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) | ✔️ | -| [117. 填充每个节点的下一个右侧节点指针 II](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/) | ✔️ | -| [662. 二叉树最大宽度](https://leetcode.cn/problems/maximum-width-of-binary-tree/) | ✔️ | -| [515. 在每个树行中找最大值](https://leetcode.cn/problems/find-largest-value-in-each-tree-row/) | ✔️ | -| [637. 二叉树的层平均值](https://leetcode.cn/problems/average-of-levels-in-binary-tree/) | ✔️ | -| [958. 二叉树的完全性检验](https://leetcode.cn/problems/check-completeness-of-a-binary-tree/) | ✔️ | -| [1161. 最大层内元素和](https://leetcode.cn/problems/maximum-level-sum-of-a-binary-tree/) | ✔️ | -| [1302. 层数最深叶子节点的和](https://leetcode.cn/problems/deepest-leaves-sum/) | ✔️ | -| [1609. 奇偶树](https://leetcode.cn/problems/even-odd-tree/) | ✔️ | -| [429. N 叉树的层序遍历](https://leetcode.cn/problems/n-ary-tree-level-order-traversal/) | ✔️ | -| [919. 完全二叉树插入器](https://leetcode.cn/problems/complete-binary-tree-inserter/) | ❌ | -| [863. 二叉树中所有距离为 K 的结点](https://leetcode.cn/problems/all-nodes-distance-k-in-binary-tree/) | ❌ | -| [LCR 149. 彩灯装饰记录 I](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/) | ✔️ | -| [LCR 150. 彩灯装饰记录 II](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/) | ✔️ | -| [LCR 151. 彩灯装饰记录 III](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-iii-lcof/) | ✔️ | +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------------------------------------------------------------------------ | ---- | ------ | +| [102. 二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal/) | 💛 | ✔️ | +| [107. 二叉树的层序遍历 II](https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/) | 💛 | ✔️ | +| [103. 二叉树的锯齿形层序遍历](https://leetcode.cn/problems/binary-tree-zigzag-level-order-traversal/) | 💛 | ✔️ | +| [116. 填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) | 💛 | ✔️ | +| [117. 填充每个节点的下一个右侧节点指针 II](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/) | 💛 | ✔️ | +| [662. 二叉树最大宽度](https://leetcode.cn/problems/maximum-width-of-binary-tree/) | 💛 | ✔️ | +| [515. 在每个树行中找最大值](https://leetcode.cn/problems/find-largest-value-in-each-tree-row/) | 💛 | ✔️ | +| [637. 二叉树的层平均值](https://leetcode.cn/problems/average-of-levels-in-binary-tree/) | 💚 | ✔️ | +| [958. 二叉树的完全性检验](https://leetcode.cn/problems/check-completeness-of-a-binary-tree/) | 💛 | ✔️ | +| [1161. 最大层内元素和](https://leetcode.cn/problems/maximum-level-sum-of-a-binary-tree/) | 💛 | ✔️ | +| [1302. 层数最深叶子节点的和](https://leetcode.cn/problems/deepest-leaves-sum/) | 💛 | ✔️ | +| [1609. 奇偶树](https://leetcode.cn/problems/even-odd-tree/) | 💛 | ✔️ | +| [919. 完全二叉树插入器](https://leetcode.cn/problems/complete-binary-tree-inserter/) | 💛 | ✔️ | +| [863. 二叉树中所有距离为 K 的结点](https://leetcode.cn/problems/all-nodes-distance-k-in-binary-tree/) | 💛 | ❌ | +| [LCR 149. 彩灯装饰记录 I](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/) | 💛 | ✔️ | +| [LCR 150. 彩灯装饰记录 II](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/) | 💚 | ✔️ | +| [LCR 151. 彩灯装饰记录 III](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-iii-lcof/) | 💛 | ✔️ | #### 二叉搜索树 -| 题目 | 掌握度 | -| ------------------------------------------------------------------------------------------------------------- | ------ | -| [230. 二叉搜索树中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-bst/) | ✔️ | -| [538. 把二叉搜索树转换为累加树](https://leetcode.cn/problems/convert-bst-to-greater-tree/) | ✔️ | -| [450. 删除二叉搜索树中的节点](https://leetcode.cn/problems/delete-node-in-a-bst/) | ❌ | -| [700. 二叉搜索树中的搜索](https://leetcode.cn/problems/search-in-a-binary-search-tree/) | ✔️ | -| [701. 二叉搜索树中的插入操作](https://leetcode.cn/problems/insert-into-a-binary-search-tree/) | ✔️ | -| [98. 验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree/) | ❗ | -| [96. 不同的二叉搜索树](https://leetcode.cn/problems/unique-binary-search-trees/) | ❌ | -| [95. 不同的二叉搜索树 II](https://leetcode.cn/problems/unique-binary-search-trees-ii/) | ❌ | -| [108. 将有序数组转换为二叉搜索树](https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/) | | -| [783. 二叉搜索树节点最小距离](https://leetcode.cn/problems/minimum-distance-between-bst-nodes/) | ❌ | -| [235. 二叉搜索树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/) | | +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------------------------------------------------------------- | ---- | ------ | +| [1038. 从二叉搜索树到更大和树](https://leetcode.cn/problems/binary-search-tree-to-greater-sum-tree/) | 💛 | ✔️ | +| [230. 二叉搜索树中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-bst/) | 💛 | ✔️ | +| [538. 把二叉搜索树转换为累加树](https://leetcode.cn/problems/convert-bst-to-greater-tree/) | 💛 | ✔️ | +| [450. 删除二叉搜索树中的节点](https://leetcode.cn/problems/delete-node-in-a-bst/) | 💛 | ✔️ | +| [700. 二叉搜索树中的搜索](https://leetcode.cn/problems/search-in-a-binary-search-tree/) | 💚 | ✔️ | +| [701. 二叉搜索树中的插入操作](https://leetcode.cn/problems/insert-into-a-binary-search-tree/) | 💛 | ✔️ | +| [98. 验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree/) | 💛 | ❗ | +| [96. 不同的二叉搜索树](https://leetcode.cn/problems/unique-binary-search-trees/) | 💛 | ❌ | +| [95. 不同的二叉搜索树 II](https://leetcode.cn/problems/unique-binary-search-trees-ii/) | 💛 | ❌ | +| [108. 将有序数组转换为二叉搜索树](https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/) | 💚 | ✔️ | +| [783. 二叉搜索树节点最小距离](https://leetcode.cn/problems/minimum-distance-between-bst-nodes/) | 💚 | ❌ | +| [235. 二叉搜索树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/) | 💛 | ❌ | +| [1373. 二叉搜索子树的最大键值和](https://leetcode.cn/problems/maximum-sum-bst-in-binary-tree/) | ❤️ | ❌ | + +#### N 叉树 -### 图 +| 题目 | 难度 | 掌握度 | +| :-------------------------------------------------------------------------------------- | :--: | ------ | +| [429. N 叉树的层序遍历](https://leetcode.cn/problems/n-ary-tree-level-order-traversal/) | 💛 | ✔️ | +| [559. N 叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-n-ary-tree/) | 💚 | ✔️ | +| [589. N 叉树的前序遍历](https://leetcode.cn/problems/n-ary-tree-preorder-traversal/) | 💚 | ✔️ | +| [590. N 叉树的后序遍历](https://leetcode.cn/problems/n-ary-tree-postorder-traversal/) | 💚 | ✔️ | -| 题目 | 掌握度 | -| ------------------------------------------------------------------------------------ | ------ | -| [797. 所有可能的路径](https://leetcode.cn/problems/all-paths-from-source-to-target/) | ❌ | -| | | +### 图 -#### 二分图判定算法 +#### BFS/DFS -| 题目 | 掌握度 | -| :---------------------------------------------------------------------- | ------ | -| [785. 判断二分图](https://leetcode.cn/problems/is-graph-bipartite/) | ❌ | -| [886. 可能的二分法](https://leetcode.cn/problems/possible-bipartition/) | ❌ | -| [剑指 Offer II 106. 二分图](https://leetcode.cn/problems/vEAB3K/) | ❌ | +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------------------------------------ | ------ | ------ | +| [797. 所有可能的路径](https://leetcode.cn/problems/all-paths-from-source-to-target/) | 💛 | ❌ | #### 环检测及拓扑排序算法 -| 题目 | 掌握度 | -| :----------------------------------------------------------------- | ------ | -| [207. 课程表](https://leetcode.cn/problems/course-schedule/) | | -| [210. 课程表 II](https://leetcode.cn/problems/course-schedule-ii/) | | +| 题目 | 难度 | 掌握度 | +| :----------------------------------------------------------- | ---- | ------ | +| [207. 课程表](https://leetcode.cn/problems/course-schedule/) | 💛 | | +| [210. 课程表 II](https://leetcode.cn/problems/course-schedule-ii/) | 💛 | | + +#### 二分图判定算法 + +| 题目 | 掌握度 | +| :----------------------------------------------------------- | ------ | +| [785. 判断二分图](https://leetcode.cn/problems/is-graph-bipartite/) | ❌ | +| [886. 可能的二分法](https://leetcode.cn/problems/possible-bipartition/) | ❌ | +| [剑指 Offer II 106. 二分图](https://leetcode.cn/problems/vEAB3K/) | ❌ | ### DFS diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/dfs/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" similarity index 67% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/dfs/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" index 5619547..bd04a8e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/dfs/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" @@ -1,5 +1,6 @@ -package io.github.dunwu.algorithm.graph; +package io.github.dunwu.algorithm.graph.dfs; +import cn.hutool.core.collection.CollectionUtil; import org.junit.jupiter.api.Assertions; import java.util.Arrays; @@ -26,36 +27,40 @@ public static void main(String[] args) { for (int i = 0; i < expect.size(); i++) { Assertions.assertArrayEquals(expect.get(i).toArray(), output.get(i).toArray()); } - System.out.println("v = " + output); + // System.out.println("v = " + output); } static class Solution { - - LinkedList> res = new LinkedList<>(); + // 记录所有路径 + List> res = new LinkedList<>(); LinkedList path = new LinkedList<>(); public List> allPathsSourceTarget(int[][] graph) { - if (graph == null || graph.length == 0) return res; - traverse(graph, 0); + dfs(graph, 0); return res; } - void traverse(int[][] graph, int s) { + // 图的遍历框架 + void dfs(int[][] graph, int s) { - // 前序 + // 添加节点 s 到路径 path.addLast(s); - if (s == graph.length - 1) { + int n = graph.length; + if (s == n - 1) { + // 到达终点 + System.out.println("find path: " + CollectionUtil.join(path, "->")); res.add(new LinkedList<>(path)); path.removeLast(); return; } + // 递归每个相邻节点 for (int v : graph[s]) { - traverse(graph, v); + dfs(graph, v); } - // 后序 + // 从路径移出节点 s path.removeLast(); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\212\202\347\202\271.java" index 3d1f714..86b8925 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\212\202\347\202\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\212\202\347\202\271.java" @@ -15,13 +15,9 @@ public class DFS遍历图的所有节点 { // 遍历图的所有节点 void traverse(Graph graph, int s, boolean[] visited) { // base case - if (s < 0 || s >= graph.size()) { - return; - } - if (visited[s]) { - // 防止死循环 - return; - } + if (s < 0 || s >= graph.size()) { return; } + // 防止死循环 + if (visited[s]) { return; } // 前序位置 visited[s] = true; System.out.println("visit " + s); @@ -34,19 +30,15 @@ void traverse(Graph graph, int s, boolean[] visited) { // 图的遍历框架 // 需要一个 visited 数组记录被遍历过的节点 // 避免走回头路陷入死循环 - void traverse(Vertex s, boolean[] visited) { + void traverse(Vertex v, boolean[] visited) { // base case - if (s == null) { - return; - } - if (visited[s.id]) { - // 防止死循环 - return; - } + if (v == null) { return; } + // 防止死循环 + if (visited[v.id]) { return; } // 前序位置 - visited[s.id] = true; - System.out.println("visit " + s.id); - for (Vertex neighbor : s.neighbors) { + visited[v.id] = true; + System.out.println("visit " + v.id); + for (Vertex neighbor : v.neighbors) { traverse(neighbor, visited); } // 后序位置 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" new file mode 100644 index 0000000..0a53f86 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" @@ -0,0 +1,64 @@ +package io.github.dunwu.algorithm.graph.template; + +import io.github.dunwu.algorithm.graph.Edge; +import io.github.dunwu.algorithm.graph.Graph; +import io.github.dunwu.algorithm.tree.Node; + +import java.util.LinkedList; + +/** + * DFS遍历图的所有路径 + * + * @author Zhang Peng + * @date 2025-12-02 + */ +public class DFS遍历图的所有路径 { + + // onPath 和 path 记录当前递归路径上的节点 + boolean[] onPath = null; + // 多叉树的遍历框架,寻找从根节点到目标节点的路径 + LinkedList path = new LinkedList<>(); + + void traverse(Node root, Node targetNode) { + // base case + if (root == null) { + return; + } + if (root.val == targetNode.val) { + // 找到目标节点 + System.out.println("find path: " + String.join("->", path) + "->" + targetNode); + return; + } + // 前序位置 + path.addLast(String.valueOf(root.val)); + for (Node child : root.children) { + traverse(child, targetNode); + } + // 后序位置 + path.removeLast(); + } + + void traverse(Graph graph, int from, int to) { + if (onPath == null) { onPath = new boolean[graph.size()]; } + // base case + if (from < 0 || from >= graph.size()) { return; } + // 防止死循环(成环) + if (onPath[from]) { return; } + if (from == to) { + // 找到目标节点 + System.out.println("find path: " + String.join("->", path) + "->" + to); + return; + } + + // 前序位置 + onPath[from] = true; + path.add(String.valueOf(from)); + for (Edge e : graph.neighbors(from)) { + traverse(graph, e.to, to); + } + // 后序位置 + path.remove(path.size() - 1); + onPath[from] = false; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" index 80aec10..8081142 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" @@ -1,5 +1,7 @@ package io.github.dunwu.algorithm.graph.template; +import io.github.dunwu.algorithm.graph.Edge; +import io.github.dunwu.algorithm.graph.Graph; import io.github.dunwu.algorithm.graph.Vertex; import io.github.dunwu.algorithm.tree.Node; @@ -14,9 +16,7 @@ public class DFS遍历图的所有边 { // 遍历多叉树的树枝 void traverseBranch(Node root) { // base case - if (root == null) { - return; - } + if (root == null) { return; } for (Node child : root.children) { System.out.println("visit branch: " + root.val + " -> " + child.val); traverseBranch(child); @@ -24,22 +24,32 @@ void traverseBranch(Node root) { } // 遍历图的边 - // 需要一个二维 visited 数组记录被遍历过的边,visited[u][v] 表示边 u->v 已经被遍历过 - void traverseEdges(Vertex s, boolean[][] visited) { + // 需要一个二维 visited 数组记录被遍历过的边,visited[from][to] 表示边 from->to 已经被遍历过 + void traverseEdges(Vertex v, boolean[][] visited) { // base case - if (s == null) { - return; - } - for (Vertex neighbor : s.neighbors) { + if (v == null) { return; } + for (Vertex neighbor : v.neighbors) { // 如果边已经被遍历过,则跳过 - if (visited[s.id][neighbor.id]) { - continue; - } + if (visited[v.id][neighbor.id]) { continue; } // 标记并访问边 - visited[s.id][neighbor.id] = true; - System.out.println("visit edge: " + s.id + " -> " + neighbor.id); + visited[v.id][neighbor.id] = true; + System.out.println("visit edge: " + v.id + " -> " + neighbor.id); traverseEdges(neighbor, visited); } } + // 从起点 s 开始遍历图的所有边 + void traverseEdges(Graph graph, int s, boolean[][] visited) { + // base case + if (s < 0 || s >= graph.size()) { return; } + for (Edge e : graph.neighbors(s)) { + // 如果边已经被遍历过,则跳过 + if (visited[s][e.to]) { continue; } + // 标记并访问边 + visited[s][e.to] = true; + System.out.println("visit edge: " + s + " -> " + e.to); + traverseEdges(graph, e.to, visited); + } + } + } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\347\237\251\351\230\265\345\256\236\347\216\260\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\347\237\251\351\230\265\345\256\236\347\216\260\345\233\276.java" index cdd84bb..140b44c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\347\237\251\351\230\265\345\256\236\347\216\260\345\233\276.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\347\237\251\351\230\265\345\256\236\347\216\260\345\233\276.java" @@ -13,26 +13,6 @@ */ public class 邻接矩阵实现图 { - public static void main(String[] args) { - WeightedDigraph graph = new WeightedDigraph(3); - graph.addEdge(0, 1, 1); - graph.addEdge(1, 2, 2); - graph.addEdge(2, 0, 3); - graph.addEdge(2, 1, 4); - - System.out.println(graph.hasEdge(0, 1)); // true - System.out.println(graph.hasEdge(1, 0)); // false - - graph.neighbors(2).forEach(edge -> { - System.out.println(2 + " -> " + edge.to + ", wight: " + edge.weight); - }); - // 2 -> 0, wight: 3 - // 2 -> 1, wight: 4 - - graph.removeEdge(0, 1); - System.out.println(graph.hasEdge(0, 1)); // false - } // 存储相邻节点及边的权重 - // 加权有向图的通用实现(邻接矩阵) static class WeightedDigraph { @@ -75,6 +55,26 @@ public List neighbors(int v) { return res; } + public static void main(String[] args) { + WeightedDigraph graph = new WeightedDigraph(3); + graph.addEdge(0, 1, 1); + graph.addEdge(1, 2, 2); + graph.addEdge(2, 0, 3); + graph.addEdge(2, 1, 4); + + System.out.println(graph.hasEdge(0, 1)); // true + System.out.println(graph.hasEdge(1, 0)); // false + + graph.neighbors(2).forEach(edge -> { + System.out.println(2 + " -> " + edge.to + ", wight: " + edge.weight); + }); + // 2 -> 0, wight: 3 + // 2 -> 1, wight: 4 + + graph.removeEdge(0, 1); + System.out.println(graph.hasEdge(0, 1)); // false + } + } // 无向加权图的通用实现 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\250.java" new file mode 100644 index 0000000..ce64e41 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\250.java" @@ -0,0 +1,92 @@ +package io.github.dunwu.algorithm.graph.topological_sort; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 207. 课程表 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 课程表 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[][] input = new int[][] { { 1, 0 } }; + int[][] input2 = new int[][] { { 1, 0 }, { 0, 1 } }; + Assertions.assertTrue(s.canFinish(2, input)); + Assertions.assertFalse(s.canFinish(2, input2)); + } + + static class Solution { + + // 记录递归堆栈中的节点 + boolean[] onPath; + // 记录节点是否被遍历过 + boolean[] visited; + // 记录图中是否有环 + boolean hasCycle = false; + + public boolean canFinish(int numCourses, int[][] prerequisites) { + List[] graph = buildGraph(numCourses, prerequisites); + + onPath = new boolean[numCourses]; + visited = new boolean[numCourses]; + + for (int i = 0; i < numCourses; i++) { + // 遍历图中的所有节点 + dfs(graph, i); + } + // 只要没有循环依赖可以完成所有课程 + return !hasCycle; + } + + // 图遍历函数,遍历所有路径 + void dfs(List[] graph, int s) { + if (hasCycle) { + // 如果已经找到了环,也不用再遍历了 + return; + } + + if (onPath[s]) { + // s 已经在递归路径上,说明成环了 + hasCycle = true; + return; + } + + if (visited[s]) { + // 不用再重复遍历已遍历过的节点 + return; + } + + // 前序代码位置 + visited[s] = true; + onPath[s] = true; + for (int t : graph[s]) { + dfs(graph, t); + } + // 后序代码位置 + onPath[s] = false; + } + + List[] buildGraph(int numCourses, int[][] prerequisites) { + // 图中共有 numCourses 个节点 + List[] graph = new LinkedList[numCourses]; + for (int i = 0; i < numCourses; i++) { + graph[i] = new LinkedList<>(); + } + for (int[] edge : prerequisites) { + int from = edge[1], to = edge[0]; + // 添加一条从 from 指向 to 的有向边 + // 边的方向是「被依赖」关系,即修完课程 from 才能修课程 to + graph[from].add(to); + } + return graph; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/base/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/base/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" new file mode 100644 index 0000000..2afe676 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/base/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" @@ -0,0 +1,34 @@ +package io.github.dunwu.algorithm.linkedlist.base; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 二进制链表转整数 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 二进制链表转整数 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(5, s.getDecimalValue(ListNode.buildList(1, 0, 1))); + Assertions.assertEquals(0, s.getDecimalValue(ListNode.buildList(0))); + } + + static class Solution { + + public int getDecimalValue(ListNode head) { + int res = 0; + ListNode p = head; + while (p != null) { + res = res * 2 + p.val; + p = p.next; + } + return res; + } + + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/DoublyLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/DoublyLinkedList.java similarity index 99% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/DoublyLinkedList.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/DoublyLinkedList.java index fda6b80..9b4c126 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/DoublyLinkedList.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/DoublyLinkedList.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.linkedlist; +package io.github.dunwu.algorithm.linkedlist.demo; import lombok.Getter; import lombok.Setter; diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/LRUBaseLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/LRUBaseLinkedList.java similarity index 98% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/LRUBaseLinkedList.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/LRUBaseLinkedList.java index b64ac35..de8e751 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/LRUBaseLinkedList.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/LRUBaseLinkedList.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.linkedlist; +package io.github.dunwu.algorithm.linkedlist.demo; import java.util.Scanner; diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/LRUBasedArray.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/LRUBasedArray.java similarity index 98% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/LRUBasedArray.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/LRUBasedArray.java index 255489a..cd909e4 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/LRUBasedArray.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/LRUBasedArray.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.linkedlist; +package io.github.dunwu.algorithm.linkedlist.demo; import java.util.HashMap; import java.util.Map; diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/MyLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/MyLinkedList.java similarity index 99% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/MyLinkedList.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/MyLinkedList.java index 694b2d4..be76a54 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/MyLinkedList.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/MyLinkedList.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.linkedlist; +package io.github.dunwu.algorithm.linkedlist.demo; import java.util.NoSuchElementException; diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/SinglyLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/SinglyLinkedList.java similarity index 99% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/SinglyLinkedList.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/SinglyLinkedList.java index e89238d..d519205 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/SinglyLinkedList.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/SinglyLinkedList.java @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.linkedlist; +package io.github.dunwu.algorithm.linkedlist.demo; import lombok.Getter; import lombok.Setter; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" similarity index 98% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" index d09a8ee..b3ba9ec 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.linkedlist; +package io.github.dunwu.algorithm.linkedlist.demo; import java.util.ArrayList; import java.util.List; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" similarity index 98% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" index 8658232..f6db8af 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.linkedlist; +package io.github.dunwu.algorithm.linkedlist.demo; /** * @author Zhang Peng diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/divide/\346\216\222\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/divide/\346\216\222\345\272\217\351\223\276\350\241\250.java" new file mode 100644 index 0000000..cec79e6 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/divide/\346\216\222\345\272\217\351\223\276\350\241\250.java" @@ -0,0 +1,72 @@ +package io.github.dunwu.algorithm.linkedlist.divide; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 148.排序链表 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 排序链表 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(ListNode.buildList(1, 2, 3, 4), s.sortList(ListNode.buildList(4, 2, 1, 3))); + Assertions.assertEquals(ListNode.buildList(-1, 0, 3, 4, 5), s.sortList(ListNode.buildList(-1, 5, 3, 4, 0))); + Assertions.assertEquals(ListNode.buildList(), s.sortList(ListNode.buildList())); + } + + public static class Solution { + + public ListNode sortList(ListNode head) { + // 如果链表为空或者只有一个节点,无需排序 + if (head == null || head.next == null) { + return head; + } + // 找到中间节点 head2,并断开 head2 与其前一个节点的连接 + // 比如 head=[4,2,1,3],那么 middleNode 调用结束后 head=[4,2] head2=[1,3] + ListNode head2 = middleNode(head); + // 分治 + head = sortList(head); + head2 = sortList(head2); + // 合并 + return mergeTwoLists(head, head2); + } + + // 876. 链表的中间结点(快慢指针) + private ListNode middleNode(ListNode head) { + ListNode pre = head; + ListNode slow = head; + ListNode fast = head; + while (fast != null && fast.next != null) { + pre = slow; // 记录 slow 的前一个节点 + slow = slow.next; + fast = fast.next.next; + } + pre.next = null; // 断开 slow 的前一个节点和 slow 的连接 + return slow; + } + + // 21. 合并两个有序链表(双指针) + private ListNode mergeTwoLists(ListNode list1, ListNode list2) { + ListNode dummy = new ListNode(-1); // 用哨兵节点简化代码逻辑 + ListNode cur = dummy; // cur 指向新链表的末尾 + while (list1 != null && list2 != null) { + if (list1.val < list2.val) { + cur.next = list1; // 把 list1 加到新链表中 + list1 = list1.next; + } else { // 注:相等的情况加哪个节点都是可以的 + cur.next = list2; // 把 list2 加到新链表中 + list2 = list2.next; + } + cur = cur.next; + } + cur.next = list1 != null ? list1 : list2; // 拼接剩余链表 + return dummy.next; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" index 2f2e6e7..dd4a500 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" @@ -3,6 +3,9 @@ import io.github.dunwu.algorithm.linkedlist.ListNode; import org.junit.jupiter.api.Assertions; +import java.util.ArrayList; +import java.util.List; + /** * 234. 回文链表 * 面试题 02.06. 回文链表 @@ -14,9 +17,8 @@ public class 回文链表 { public static void main(String[] args) { Solution s = new Solution(); - ListNode head = ListNode.buildList(1, 2, 2, 1); - Assertions.assertTrue(s.isPalindrome(head)); - + ListNode input = ListNode.buildList(1, 2, 2, 1); + Assertions.assertTrue(s.isPalindrome(input)); ListNode input2 = ListNode.buildList(1, 2); Assertions.assertFalse(s.isPalindrome(input2)); } @@ -24,37 +26,24 @@ public static void main(String[] args) { static class Solution { public boolean isPalindrome(ListNode head) { - ListNode slow, fast; - slow = fast = head; - while (fast != null && fast.next != null) { - slow = slow.next; - fast = fast.next.next; + List list = new ArrayList<>(); + ListNode p = head; + while (p != null) { + list.add(p.val); + p = p.next; } - if (fast != null) { slow = slow.next; } - - ListNode left = head; - ListNode right = reverse(slow); - while (right != null) { - if (left.val != right.val) { return false; } - left = left.next; - right = right.next; + int left = 0, right = list.size() - 1; + while (left < right) { + if (!list.get(left).equals(list.get(right))) { + return false; + } + left++; + right--; } - return true; } - ListNode reverse(ListNode head) { - ListNode pre = null, cur = head; - while (cur != null) { - ListNode next = cur.next; - cur.next = pre; - pre = cur; - cur = next; - } - return pre; - } - } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" index 2156a24..7cc9d0c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Assertions; /** - * 23. 合并 K 个升序链表 + * 25. K 个一组翻转链表 * * @author Zhang Peng * @since 2020-06-09 @@ -22,13 +22,12 @@ public static void main(String[] args) { static class Solution { public ListNode reverseKGroup(ListNode head, int k) { - if (head == null) return null; + if (head == null) { return null; } // 区间 [a, b) 包含 k 个待反转元素 - ListNode a, b; - a = b = head; + ListNode a = head, b = head; for (int i = 0; i < k; i++) { // 不足 k 个,不需要反转了 - if (b == null) return head; + if (b == null) { return head; } b = b.next; } // 反转前 k 个元素 @@ -36,7 +35,6 @@ public ListNode reverseKGroup(ListNode head, int k) { // 此时 b 指向下一组待反转的头结点 // 递归反转后续链表并连接起来 a.next = reverseKGroup(b, k); - return newHead; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\245\207\345\201\266\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\245\207\345\201\266\351\223\276\350\241\250.java" new file mode 100644 index 0000000..5d3c5be --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\245\207\345\201\266\351\223\276\350\241\250.java" @@ -0,0 +1,46 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 328. 奇偶链表 + * + * @author Zhang Peng + * @since 2020-07-08 + */ +public class 奇偶链表 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(ListNode.buildList(1, 3, 5, 2, 4), s.oddEvenList(ListNode.buildList(1, 2, 3, 4, 5))); + Assertions.assertEquals(ListNode.buildList(2, 3, 6, 7, 1, 5, 4), + s.oddEvenList(ListNode.buildList(2, 1, 3, 5, 6, 4, 7))); + } + + static class Solution { + + public ListNode oddEvenList(ListNode head) { + ListNode oddDummy = new ListNode(-1); + ListNode evenDummy = new ListNode(-1); + ListNode p = head, o = oddDummy, e = evenDummy; + int i = 1; + while (p != null) { + if (i % 2 == 0) { + e.next = p; + e = e.next; + } else { + o.next = p; + o = o.next; + } + p = p.next; + i++; + } + e.next = null; + o.next = evenDummy.next; + return oddDummy.next; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" new file mode 100644 index 0000000..0bba21c --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" @@ -0,0 +1,45 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +import java.util.HashSet; +import java.util.Set; + +/** + * 面试题 02.01. 移除重复节点 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 移除重复节点 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(ListNode.buildList(1, 2, 3), + s.removeDuplicateNodes(ListNode.buildList(1, 2, 3, 3, 2, 1))); + Assertions.assertEquals(ListNode.buildList(1, 2), + s.removeDuplicateNodes(ListNode.buildList(1, 1, 1, 1, 2))); + } + + static class Solution { + + public ListNode removeDuplicateNodes(ListNode head) { + Set set = new HashSet<>(); + ListNode dummy = new ListNode(-1); + ListNode p = head, n = dummy; + while (p != null) { + if (!set.contains(p.val)) { + n.next = p; + n = n.next; + set.add(p.val); + } + p = p.next; + } + n.next = null; + return dummy.next; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" new file mode 100644 index 0000000..6cb6000 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" @@ -0,0 +1,40 @@ +package io.github.dunwu.algorithm.linkedlist.two_pointer; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * 203. 移除链表元素 + * + * @author Zhang Peng + * @since 2020-06-09 + */ +public class 移除链表元素 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(ListNode.buildList(1, 2, 3, 4, 5), + s.removeElements(ListNode.buildList(1, 2, 6, 3, 4, 5, 6), 6)); + Assertions.assertEquals(ListNode.buildList(), s.removeElements(ListNode.buildList(), 1)); + Assertions.assertEquals(ListNode.buildList(), s.removeElements(ListNode.buildList(7, 7, 7, 7, 7), 7)); + } + + static class Solution { + + public ListNode removeElements(ListNode head, int val) { + ListNode dummy = new ListNode(0); + ListNode p = head, q = dummy; + while (p != null) { + if (p.val != val) { + q.next = p; + q = q.next; + } + p = p.next; + } + q.next = null; + return dummy.next; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" deleted file mode 100644 index 33c195f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" +++ /dev/null @@ -1,89 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 二进制链表转整数 { - - public static void main(String[] args) { - ListNode head = ListNode.buildList(1, 0, 1); - System.out.println(ListNode.toList(head)); - int result = getDecimalValue(head); - Assertions.assertEquals(5, result); - - head = new ListNode(0); - System.out.println(ListNode.toList(head)); - result = getDecimalValue(head); - Assertions.assertEquals(0, result); - - head = new ListNode(1); - System.out.println(ListNode.toList(head)); - result = getDecimalValue(head); - Assertions.assertEquals(1, result); - - head = ListNode.buildList(1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0); - System.out.println(ListNode.toList(head)); - result = getDecimalValue(head); - Assertions.assertEquals(18880, result); - } - - /** - * 二进制链表转整数 算法实现 - *

- * 给你一个单链表的引用结点 head。链表中每个结点的值不是 0 就是 1。已知此链表是一个整数数字的二进制表示形式。 - *

- * 请你返回该链表所表示数字的 十进制值 。 - *

- * 示例 1: - *

-     * 输入:head = [1,0,1]
-     * 输出:5
-     * 解释:二进制数 (101) 转化为十进制数 (5)
-     * 
- *

- * 示例 2: - *

-     * 输入:head = [0]
-     * 输出:0
-     * 
- *

- * 示例 3: - *

-     * 输入:head = [1]
-     * 输出:1
-     * 
- *

- * 示例 4: - *

-     * 输入:head = [1,0,0,1,0,0,1,1,1,0,0,0,0,0,0]
-     * 输出:18880
-     * 
- *

- * 示例 5: - *

-     * 输入:head = [0,0]
-     * 输出:0
-     * 
- *

- * 提示: - *

-     * 链表不为空。
-     * 链表的结点总数不超过 30。
-     * 每个结点的值不是 0 就是 1。
-     * 
- * - * @see 二进制链表转整数 - */ - public static int getDecimalValue(ListNode head) { - int sum = 0; - while (head != null) { - sum = sum * 2 + head.val; - head = head.next; - } - return sum; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" deleted file mode 100644 index 69e3aae..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\344\273\216\346\234\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250\344\270\255\347\247\273\351\231\244\351\207\215\345\244\215\345\205\203\347\264\240.java" +++ /dev/null @@ -1,94 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 83. 删除排序链表中的重复元素 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 从未排序的链表中移除重复元素 { - - public static void main(String[] args) { - ListNode head = ListNode.buildList(1, 2, 3, 2); - System.out.println(ListNode.toList(head)); - ListNode result = deleteDuplicates2(head); - List list = ListNode.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 1, 3 }, list.toArray(new Integer[0])); - - ListNode head2 = ListNode.buildList(2, 1, 1, 2); - System.out.println(ListNode.toList(head2)); - ListNode result2 = deleteDuplicates2(head2); - List list2 = ListNode.toList(result2); - System.out.println(list2); - Assertions.assertArrayEquals(new Integer[] {}, list2.toArray(new Integer[0])); - - ListNode head3 = ListNode.buildList(3, 2, 2, 1, 3, 2, 4); - System.out.println(ListNode.toList(head3)); - ListNode result3 = deleteDuplicates2(head3); - List list3 = ListNode.toList(result3); - System.out.println(list3); - Assertions.assertArrayEquals(new Integer[] { 1, 4 }, list3.toArray(new Integer[0])); - } - - public static ListNode deleteDuplicates(ListNode head) { - Map map = new HashMap<>(); - ListNode p = head; - while (p != null) { - map.put(p.val, map.getOrDefault(p.val, 0) + 1); - p = p.next; - } - - ListNode dup = new ListNode(101); - ListNode nodup = new ListNode(101); - ListNode pDup = dup, pNodup = nodup; - p = head; - while (p != null) { - if (map.get(p.val) > 1) { - pDup.next = p; - pDup = pDup.next; - } else { - pNodup.next = p; - pNodup = pNodup.next; - } - - p = p.next; - pDup.next = null; - pNodup.next = null; - } - return nodup.next; - } - - public static ListNode deleteDuplicates2(ListNode head) { - ListNode dupList = new ListNode(0); - ListNode nodupList = new ListNode(0); - ListNode dup = dupList, nodup = nodupList; - ListNode p = head; - Map map = new HashMap<>(); - while (p != null) { - map.put(p.val, map.getOrDefault(p.val, 0) + 1); - p = p.next; - } - p = head; - while (p != null) { - if (map.get(p.val) > 1) { - dup.next = p; - dup = dup.next; - } else { - nodup.next = p; - nodup = nodup.next; - } - p = p.next; - dup.next = null; - nodup.next = null; - } - return nodupList.next; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\245\207\345\201\266\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\245\207\345\201\266\351\223\276\350\241\250.java" deleted file mode 100644 index a3ce6b0..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\345\245\207\345\201\266\351\223\276\350\241\250.java" +++ /dev/null @@ -1,33 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist; - -import java.util.List; - -/** - * @author Zhang Peng - * @since 2020-07-08 - */ -public class 奇偶链表 { - - public static void main(String[] args) { - ListNode head = ListNode.buildList(1, 2, 3, 4, 5); - List list = ListNode.toList(oddEvenList(head)); - System.out.println(list); - // Assertions.assertFalse(); - } - - public static ListNode oddEvenList(ListNode head) { - if (head == null || head.next == null) return head; - - ListNode odd = head, even = head.next, evenHead = even; - - while (even != null && even.next != null) { - odd.next = even.next; - odd = odd.next; - even.next = odd.next; - even = even.next; - } - odd.next = evenHead; - return head; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\346\216\222\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\346\216\222\345\272\217\351\223\276\350\241\250.java" deleted file mode 100644 index 197c377..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\346\216\222\345\272\217\351\223\276\350\241\250.java" +++ /dev/null @@ -1,96 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist; - -import org.junit.jupiter.api.Assertions; - -import java.util.List; - -/** - * @author Zhang Peng - * @see 148.排序链表 - * @since 2020-06-09 - */ -public class 排序链表 { - - public static void main(String[] args) { - ListNode head = ListNode.buildList(4, 2, 1, 3); - System.out.println(ListNode.toList(head)); - ListNode result = sortList(head); - List list = ListNode.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3, 4 }, list.toArray(new Integer[0])); - - head = ListNode.buildList(-1, 5, 3, 4, 0); - System.out.println(ListNode.toList(head)); - result = sortList(head); - list = ListNode.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { -1, 0, 3, 4, 5 }, list.toArray(new Integer[0])); - } - - public static ListNode sortList(ListNode head) { - if (head == null) {return head;} - return mergeSort(head); - } - - static ListNode mergeSort(ListNode head) { - //回归条件 - if (head.next == null) { - return head; - } - //快指针,考虑到链表为2时的情况,fast比slow早一格 - ListNode fast = head.next; - //慢指针 - ListNode slow = head; - //快慢指针开跑 - while (fast != null && fast.next != null) { - fast = fast.next.next; - slow = slow.next; - } - //找到右子链表头元素,复用fast引用 - fast = slow.next; - //将中点后续置空,切割为两个子链表 - slow.next = null; - //递归分解左子链表,得到新链表起点 - head = mergeSort(head); - //递归分解右子链表,得到新链表起点 - fast = mergeSort(fast); - //并归两个子链表 - return merge(head, fast); - } - - static ListNode merge(ListNode left, ListNode right) { - //维护临时序列的头元素 - ListNode head; - if (left.val <= right.val) { - head = left; - left = left.next; - } else { - head = right; - right = right.next; - } - //两个子链表均存在剩余元素 - ListNode temp = head; - while (left != null && right != null) { - //将较小的元素加入临时序列 - if (left.val <= right.val) { - temp.next = left; - left = left.next; - temp = temp.next; - } else { - temp.next = right; - right = right.next; - temp = temp.next; - } - } - //左子序列用完将右子序列余下元素加入临时序列 - if (left == null) { - temp.next = right; - } - //右子序列用完将左子序列余下元素加入临时序列 - if (right == null) { - temp.next = left; - } - return head; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" deleted file mode 100644 index 502bdb1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" +++ /dev/null @@ -1,63 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist; - -import org.junit.jupiter.api.Assertions; - -import java.util.List; - -/** - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 移除重复节点 { - - public static void main(String[] args) { - ListNode head = ListNode.buildList(1, 2, 3, 3, 2, 1); - ListNode listNode = removeDuplicateNodes(head); - List result = ListNode.toList(listNode); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, result.toArray()); - } - - /** - * @see 面试题 02.01. 移除重复节点 - */ - public static ListNode removeDuplicateNodes(ListNode head) { - if (head == null) { - return null; - } - - ListNode list = new ListNode(-1); - list.next = null; - - ListNode node = head; - while (node != null) { - if (!exists(list, node.val)) { - addToTail(list, node.val); - } - node = node.next; - } - return list.next; - } - - private static boolean exists(ListNode head, int val) { - ListNode node = head; - while (node != null) { - if (node.val == val) { return true; } - node = node.next; - } - return false; - } - - private static void addToTail(ListNode head, int val) { - if (head == null) { - return; - } - ListNode node = head; - while (node.next != null) { - node = node.next; - } - ListNode newNode = new ListNode(val); - node.next = newNode; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" deleted file mode 100644 index 4612cdc..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" +++ /dev/null @@ -1,81 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist; - -import org.junit.jupiter.api.Assertions; - -import java.util.List; - -/** - * @author Zhang Peng - * @see 203. 移除链表元素 - * @since 2020-06-09 - */ -public class 移除链表元素 { - - public static void main(String[] args) { - ListNode head = ListNode.buildList(1, 2); - System.out.println(ListNode.toList(head)); - ListNode result = removeElementByValue(head, 1); - List list = ListNode.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 2 }, list.toArray(new Integer[0])); - - head = new ListNode(1); - System.out.println(ListNode.toList(head)); - result = removeElementByValue(head, 1); - list = ListNode.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] {}, list.toArray(new Integer[0])); - - head = ListNode.buildList(1, 1); - System.out.println(ListNode.toList(head)); - result = removeElementByValue(head, 1); - list = ListNode.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] {}, list.toArray(new Integer[0])); - - head = ListNode.buildList(1, 2, 6, 3, 4, 5, 6); - System.out.println(ListNode.toList(head)); - result = removeElementByValue(head, 6); - list = ListNode.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3, 4, 5 }, list.toArray(new Integer[0])); - } - - public static ListNode removeElementByValue(ListNode head, int val) { - if (head == null) return null; - - ListNode root = new ListNode(-1); - root.next = head; - ListNode prev = root; - while (prev.next != null) { - if (prev.next.val == val) { - prev.next = prev.next.next; - } else { - prev = prev.next; - } - } - return root.next; - } - - public static ListNode removeElementByIndex(ListNode head, int index) { - if (head == null) { - return null; - } - - ListNode root = new ListNode(-1); - root.next = head; - ListNode node = root; - int pos = 0; - while (node.next != null && pos != index) { - node = node.next; - pos++; - } - - if (node.next != null) { - node.next = node.next.next; - } - - return root.next; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\350\256\276\350\256\241\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\350\256\276\350\256\241\351\223\276\350\241\250.java" deleted file mode 100644 index fd01e53..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/\350\256\276\350\256\241\351\223\276\350\241\250.java" +++ /dev/null @@ -1,132 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @since 2020-07-08 - */ -public class 设计链表 { - - public static void main(String[] args) { - MyLinkedList list = new MyLinkedList(); - list.addAtHead(1); - list.print(); - list.addAtTail(3); - list.print(); - list.addAtIndex(1, 2); //链表变为1-> 2-> 3 - list.print(); - System.out.println(list.get(1));//返回2 - Assertions.assertEquals(2, list.get(1)); - list.deleteAtIndex(1); //现在链表是1-> 3 - list.print(); - Assertions.assertEquals(3, list.get(1)); - } - - static class MyLinkedList { - - private Node head; - - /** - * Initialize your data structure here. - */ - public MyLinkedList() { - head = new Node(-1); - } - - /** - * Get the value of the index-th node in the linked list. If the index is invalid, return -1. - */ - public int get(int index) { - int i = 0; - Node p = head.next; - while (p.next != null && i < index) { - p = p.next; - i++; - } - return p.val; - } - - /** - * Add a node of value val before the first element of the linked list. After the insertion, the new node will - * be the first node of the linked list. - */ - public void addAtHead(int val) { - Node node = new Node(val); - if (head.next == null) { - head.next = node; - } else { - node.next = head.next; - head.next = node; - } - } - - /** - * Append a node of value val to the last element of the linked list. - */ - public void addAtTail(int val) { - Node p = head; - while (p.next != null) { - p = p.next; - } - p.next = new Node(val); - } - - /** - * Add a node of value val before the index-th node in the linked list. If index equals to the length of linked - * list, the node will be appended to the end of linked list. If index is greater than the length, the node will - * not be inserted. - */ - public void addAtIndex(int index, int val) { - int i = 0; - Node p = head.next; - while (p.next != null && i < index - 1) { - p = p.next; - } - - Node node = new Node(val); - node.next = p.next; - p.next = node; - } - - /** - * Delete the index-th node in the linked list, if the index is valid. - */ - public void deleteAtIndex(int index) { - int i = 0; - Node p = head.next; - while (p.next != null && i < index - 1) { - p = p.next; - } - - if (p.next != null) { - p.next = p.next.next; - } else { - p.next = null; - } - } - - public void print() { - Node p = head; - while (p.next != null) { - p = p.next; - System.out.print(p.val + "\t"); - } - System.out.println(); - } - - static class Node { - - int val; - Node next; - - public Node(int val) { - this.val = val; - next = null; - } - - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BTree.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BTree.java index 0e14249..cac20fd 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BTree.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BTree.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.LinkedList; import java.util.List; +import java.util.Objects; import java.util.Queue; /** @@ -27,7 +28,7 @@ public BTree(TreeNode root) { this.root = root; } - public static > BTree buildTree(T... array) { + public static > BTree build(T... array) { BTree tree = new BTree<>(); List> list = new ArrayList<>(); @@ -83,32 +84,7 @@ public static > BTree buildTree(T... array) { * @return true / false */ public static > boolean isEquals(final BTree tree1, final BTree tree2) { - return isEquals(tree1.root, tree2.root); - } - - /** - * 判断两颗二叉树是否完全一致 - * - * @param root1 二叉树根节点,类型:{@link BTree#root} - * @param root2 二叉树根节点,类型:{@link BTree#root} - * @param 元素类型 - * @return true / false - * @see 相同的树 - */ - private static > boolean isEquals(TreeNode root1, TreeNode root2) { - if (root1 == null && root2 == null) { - return true; - } - - if (root1 == null || root2 == null) { - return false; - } - - if (!root1.value.equals(root2.value)) { - return false; - } - - return isEquals(root1.left, root2.left) && isEquals(root1.right, root2.right); + return TreeNode.isEquals(tree1.root, tree2.root); } /** @@ -120,37 +96,16 @@ private static > boolean isEquals(TreeNode root1, Tre * @see 叶子相似的树 */ public static > boolean isLeafSimilar(final BTree tree1, final BTree tree2) { - List leafs1 = new LinkedList<>(); - List leafs2 = new LinkedList<>(); - getLeafNodes(tree1, leafs1); - getLeafNodes(tree2, leafs2); + List leafs1 = TreeNode.getLeafNodes(tree1.root); + List leafs2 = TreeNode.getLeafNodes(tree2.root); return Arrays.equals(leafs1.toArray(), leafs2.toArray()); } /** * 获取叶子节点 - * - * @param tree {@link BTree} - * @param leafs [出参]叶子节点列表{@link List} - * @param 元素类型 - */ - public static > void getLeafNodes(BTree tree, List leafs) { - getLeafNodes(tree.root, leafs); - } - - /** - * 获取叶子节点 - * - * @param root {@link TreeNode} - * @param leafs [出参]叶子节点列表{@link List} - * @param 元素类型 */ - private static > void getLeafNodes(TreeNode root, List leafs) { - if (root == null) { return; } - - if (root.left == null && root.right == null) { leafs.add(root.value); } - getLeafNodes(root.left, leafs); - getLeafNodes(root.right, leafs); + public List getLeafNodes() { + return TreeNode.getLeafNodes(this.root); } /** @@ -159,24 +114,7 @@ private static > void getLeafNodes(TreeNode root, Lis * @return 二叉树的最大深度 */ public int maxDepth() { - return maxDepth(this.root); - } - - /** - * 采用递归方法获取二叉树的最大深度 - * - * @param root 二叉树根节点,类型:{@link BTree#root} - * @return 二叉树的最大深度 - * @see 二叉树的最大深度 - */ - private int maxDepth(TreeNode root) { - if (root == null) return 0; - - int left = maxDepth(root.left); - - int right = maxDepth(root.right); - - return Math.max(left, right) + 1; + return TreeNode.maxDepth(this.root); } /** @@ -185,86 +123,246 @@ private int maxDepth(TreeNode root) { * @return 二叉树的最小深度 */ public int minDepth() { - return minDepth(this.root); + return TreeNode.minDepth(this.root); } + // ------------------------------------------------------------- 遍历元素 + /** - * 采用递归方法获取二叉树的最小深度 + * 将二叉树按层次遍历顺序转换为列表,即广度优先搜索(BFS) * - * @param root 二叉树根节点,类型:{@link BTree#root} - * @return 二叉树的最小深度 - * @see 二叉树的最小深度 + * @return {@link List>} */ - private int minDepth(TreeNode root) { - if (root == null) { return 0; } + public List> levelOrderLists() { + return TreeNode.levelOrderLists(this.root); + } + + public static class TreeNode> { - int left = minDepth(root.left); + T val; - int right = minDepth(root.right); + TreeNode left; + + TreeNode right; - if (left == 0 || right == 0) { - return left + right + 1; + public TreeNode(T val) { + this.val = val; } - return Math.min(left, right) + 1; - } + public TreeNode(T val, TreeNode left, TreeNode right) { + this.val = val; + this.left = left; + this.right = right; + } - // ------------------------------------------------------------- 遍历元素 + @Override + public String toString() { + return String.valueOf(val); + } - /** - * 将二叉树按层次遍历顺序转换为列表,即广度优先搜索(BFS) - * - * @return {@link List>} - * @see 二叉树的层次遍历 II - */ - public List> levelOrderLists() { - List> lists = new ArrayList<>(); - if (root == null) { return lists; } - Queue> queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - int size = queue.size(); - List temp = new ArrayList<>(); - for (int i = 0; i < size; i++) { + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof TreeNode)) return false; + TreeNode treeNode = (TreeNode) o; + return Objects.equals(val, treeNode.val) && + Objects.equals(left, treeNode.left) && + Objects.equals(right, treeNode.right); + } + + @Override + public int hashCode() { + return Objects.hash(val, left, right); + } + + public static > TreeNode build(T... values) { + + if (values == null || values.length == 0 || values[0] == null) { + return null; + } + + Queue> queue = new LinkedList<>(); + TreeNode root = new TreeNode<>(values[0]); + queue.offer(root); + + int i = 1; + while (!queue.isEmpty()) { + TreeNode current = queue.poll(); + + // 处理左子节点 + if (i < values.length && values[i] != null) { + current.left = new TreeNode(values[i]); + queue.offer(current.left); + } + i++; + + // 处理右子节点 + if (i < values.length && values[i] != null) { + current.right = new TreeNode(values[i]); + queue.offer(current.right); + } + i++; + } + + return root; + } + + public static > TreeNode find(TreeNode root, T val) { + if (root == null || Objects.equals(root.val, val)) { return root; } + TreeNode left = find(root.left, val); + if (left != null) return left; + return find(root.right, val); + } + + public static > List> toList(TreeNode root) { + List> list = new ArrayList<>(); + if (root == null) { + return list; + } + + Queue> queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { TreeNode node = queue.poll(); - temp.add(node.value); - if (node.left != null) { queue.offer(node.left); } - if (node.right != null) { queue.offer(node.right); } + list.add(node); + if (node == null) continue; + queue.add(node.left); + queue.add(node.right); + } + + // 删除队列尾部的所有 null + int last = list.size() - 1; + while (last > 0 && list.get(last) == null) { + last--; } - lists.add(temp); + return list.subList(0, last + 1); } - return lists; - } - public List levelOrderList() { - List list = new ArrayList<>(); - if (root == null) { return list; } - Queue> queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - int size = queue.size(); - for (int i = 0; i < size; i++) { + public static > List toValueList(TreeNode root) { + List list = new ArrayList<>(); + if (root == null) { + return list; + } + + Queue> queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { TreeNode node = queue.poll(); - list.add(node.value); - if (node.left != null) { queue.offer(node.left); } - if (node.right != null) { queue.offer(node.right); } + if (node == null) { + list.add(null); + continue; + } else { + list.add(node.val); + } + + queue.add(node.left); + queue.add(node.right); + } + + // 删除队列尾部的所有 null + int last = list.size() - 1; + while (last > 0 && list.get(last) == null) { + last--; } + return list.subList(0, last + 1); + } + + /** + * 判断两颗二叉树是否完全一致 + * + * @param root1 二叉树根节点,类型:{@link BTree#root} + * @param root2 二叉树根节点,类型:{@link BTree#root} + * @param 元素类型 + * @return true / false + * @see 相同的树 + */ + private static > boolean isEquals(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 == null) { return true; } + if (root1 == null || root2 == null) { return false; } + if (!root1.val.equals(root2.val)) { return false; } + return isEquals(root1.left, root2.left) && isEquals(root1.right, root2.right); } - return list; - } - static class TreeNode> { + /** + * 获取叶子节点 + * + * @param root {@link TreeNode} + * @param 元素类型 + */ + public static > List getLeafNodes(TreeNode root) { + List res = new ArrayList<>(); + getLeafNodes(root, res); + return res; + } - T value; + /** + * 获取叶子节点 + * + * @param root {@link TreeNode} + * @param leafs [出参]叶子节点列表{@link List} + * @param 元素类型 + */ + private static > void getLeafNodes(TreeNode root, List leafs) { + if (root == null) { return; } + if (root.left == null && root.right == null) { leafs.add(root.val); } + getLeafNodes(root.left, leafs); + getLeafNodes(root.right, leafs); + } - TreeNode left; + /** + * 采用递归方法获取二叉树的最大深度 + * + * @param root 二叉树根节点,类型:{@link BTree#root} + * @return 二叉树的最大深度 + * @see 二叉树的最大深度 + */ + public static > int maxDepth(TreeNode root) { + if (root == null) { return 0; } + int left = maxDepth(root.left); + int right = maxDepth(root.right); + return Math.max(left, right) + 1; + } - TreeNode right; + /** + * 采用递归方法获取二叉树的最小深度 + * + * @param root 二叉树根节点,类型:{@link BTree#root} + * @return 二叉树的最小深度 + * @see 二叉树的最小深度 + */ + public static > int minDepth(TreeNode root) { + if (root == null) { return 0; } + int left = minDepth(root.left); + int right = minDepth(root.right); + if (left == 0 || right == 0) { + return left + right + 1; + } + return Math.min(left, right) + 1; + } - public TreeNode(T value, TreeNode left, TreeNode right) { - this.value = value; - this.left = left; - this.right = right; + /** + * 将二叉树按层次遍历顺序转换为列表,即广度优先搜索(BFS) + * + * @return {@link List>} + * @see 二叉树的层次遍历 II + */ + public static > List> levelOrderLists(TreeNode root) { + List> lists = new ArrayList<>(); + if (root == null) { return lists; } + Queue> queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + int size = queue.size(); + List list = new ArrayList<>(); + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + list.add(node.val); + if (node.left != null) { queue.offer(node.left); } + if (node.right != null) { queue.offer(node.right); } + } + lists.add(list); + } + return lists; } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BaseCase.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BaseCase.java index f6ea850..8da17c6 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BaseCase.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BaseCase.java @@ -10,7 +10,7 @@ */ public class BaseCase { - public static class Node extends NAryTree { + public static class Node extends NTree { public Node(int val) { super(val); diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/IntBTree.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/IntBTree.java deleted file mode 100644 index 00bac67..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/IntBTree.java +++ /dev/null @@ -1,175 +0,0 @@ -package io.github.dunwu.algorithm.tree; - -import java.util.LinkedList; -import java.util.Queue; -import java.util.Stack; - -/** - * @author Zhang Peng - * @since 2020-01-20 - */ -public class IntBTree { - - /** - * 前序遍历递归方法 - * - * @param root {@link TreeNode} - */ - public static void preOrder(TreeNode root) { - TreeNode node = root; - if (node != null) { - System.out.print(node.val + " "); - preOrder(node.left); - preOrder(node.right); - } - } - - /** - * 前序遍历非递归方法 - * - * @param root {@link TreeNode} - */ - public static void preOrder2(TreeNode root) { - if (root == null) return; - Stack stack = new Stack<>(); - while (!stack.isEmpty() || root != null) { - while (root != null) { - System.out.print(root.val + " "); - stack.push(root); - root = root.left; - } - if (!stack.isEmpty()) { - TreeNode t = stack.pop(); - root = t.right; - } - } - } - - /** - * 中序遍历递归方法 - * - * @param root {@link TreeNode} - */ - public static void inOrder(TreeNode root) { - if (root != null) { - preOrder(root.left); - System.out.print(root.val + " "); - preOrder(root.right); - } - } - - /** - * 中序遍历非递归方法 - * - * @param root {@link TreeNode} - */ - public static void inOrder2(TreeNode root) { - if (root == null) { - return; - } - - Stack stack = new Stack<>(); - while (!stack.isEmpty() || root != null) { - while (root != null) { - stack.push(root); - root = root.left; - } - if (!stack.isEmpty()) { - TreeNode t = stack.pop(); - System.out.print(t.val + " "); - root = t.right; - } - } - } - - public static void postOrder(TreeNode root) { - if (root != null) { - postOrder(root.left); - postOrder(root.right); - System.out.print(root.val + " "); - } - } - - /** - * 中序遍历非递归方法 - * - * @param root {@link TreeNode} - */ - public static void postOrder2(TreeNode root) { - if (root == null) { - return; - } - - Stack stack = new Stack<>(); - while (!stack.isEmpty() || root != null) { - while (root != null) { - stack.push(root); - root = root.left; - } - if (!stack.isEmpty()) { - TreeNode t = stack.pop(); - System.out.print(t.val + " "); - root = t.left; - } - } - } - - public static void levelTraverse(TreeNode root) { - if (root == null) { - return; - } - Queue queue = new LinkedList<>(); - queue.add(root); - while (!queue.isEmpty()) { - TreeNode node = queue.poll(); - System.out.print(node.val + " "); - if (node.left != null) queue.add(node.left); - if (node.right != null) queue.add(node.right); - } - } - - public static void depthOrderTraverse(TreeNode root) { - if (root == null) { - return; - } - LinkedList stack = new LinkedList<>(); - stack.push(root); - while (!stack.isEmpty()) { - TreeNode node = stack.pop(); - System.out.print(node.val + " "); - if (node.left != null) stack.push(node.left); - if (node.right != null) stack.push(node.right); - } - } - - public static TreeNode sortedArrayToBST(int[] nums) { - if (nums == null || nums.length == 0) return null; - return _sortedArrayToBST(nums, 0, nums.length - 1); - } - - public static TreeNode _sortedArrayToBST(int[] nums, int left, int right) { - if (left > right) return null; - - // always choose left middle node as a root - int p = (left + right) / 2; - - // inorder traversal: left -> node -> right - TreeNode root = new TreeNode(nums[p]); - root.left = _sortedArrayToBST(nums, left, p - 1); - root.right = _sortedArrayToBST(nums, p + 1, right); - return root; - } - - public static class TreeNode { - - public int val; - - public TreeNode left; - - public TreeNode right; - - public TreeNode(int val) { this.val = val; } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/NAryTree.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/NTree.java similarity index 75% rename from codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/NAryTree.java rename to codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/NTree.java index e442847..664e896 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/NAryTree.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/NTree.java @@ -9,22 +9,22 @@ * @author Zhang Peng * @date 2025-10-27 */ -public class NAryTree> { +public class NTree> { public int val; public List children; - public NAryTree() { + public NTree() { val = -1; children = new LinkedList<>(); } - public NAryTree(int val) { + public NTree(int val) { this.val = val; this.children = new LinkedList<>(); } - public NAryTree(int val, List children) { + public NTree(int val, List children) { this.val = val; this.children = children; } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/Node.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/Node.java index c131411..8c295ec 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/Node.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/Node.java @@ -1,5 +1,6 @@ package io.github.dunwu.algorithm.tree; +import java.util.LinkedList; import java.util.List; // 多叉树节点 @@ -8,4 +9,19 @@ public class Node { public int val; public List children; + public Node() { + val = -1; + children = new LinkedList<>(); + } + + public Node(int val) { + this.val = val; + this.children = new LinkedList<>(); + } + + public Node(int val, List children) { + this.val = val; + this.children = children; + } + } \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/N\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/N\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" deleted file mode 100644 index e2ce861..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/N\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.dunwu.algorithm.tree; - -import java.util.List; - -// 559. N叉树的最大深度 -// -// https://leetcode-cn.com/problems/maximum-depth-of-n-ary-tree/ -// -// 给定一个 N 叉树,找到其最大深度。 -// -// 最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。 -// -// 例如,给定一个 3叉树 : -// -// 我们应返回其最大深度,3。 -// -// 说明: -// -// 树的深度不会超过 1000。 -// 树的节点总不会超过 5000。 -public class N叉树的最大深度 { - - public static int maxDepth(Node root) { - if (root == null) return 0; - if (root.children == null || root.children.size() == 0) return 1; - int max = 0; - for (Node node : root.children) { - int temp = maxDepth(node); - if (temp > max) { - max = temp; - } - } - return max + 1; - } - - static class Node { - - public int val; - - public List children; - - public Node() {} - - public Node(int val) { - this.val = val; - } - - public Node(int val, List children) { - this.val = val; - this.children = children; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" index d821891..1f5ec87 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" @@ -20,23 +20,32 @@ public static void main(String[] args) { static class Solution { - public int numTrees(int n) { - int[][] memo = new int[n + 1][n + 1]; - return recursion(1, n, memo); - } + // 备忘录 + int[][] memo; - public int recursion(int begin, int end, int[][] memo) { - if (begin > end) { return 1; } + int numTrees(int n) { + // 备忘录的值初始化为 0 + memo = new int[n + 1][n + 1]; + return count(1, n); + } - if (memo[begin][end] != 0) { return memo[begin][end]; } + // 定义:返回 [begin, end] 范围内构造的不同 BST 的数量 + int count(int begin, int end) { + if (begin >= end) return 1; + // 查备忘录 + if (memo[begin][end] != 0) { + return memo[begin][end]; + } int res = 0; - for (int i = begin; i <= end; i++) { - int left = recursion(begin, i - 1, memo); - int right = recursion(i + 1, end, memo); + for (int mid = begin; mid <= end; mid++) { + int left = count(begin, mid - 1); + int right = count(mid + 1, end); res += left * right; } + // 将结果存入备忘录 memo[begin][end] = res; + return res; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" index b4121a7..fee5b65 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" @@ -45,24 +45,31 @@ public static void main(String[] args) { static class Solution { + // 主函数 public List generateTrees(int n) { if (n == 0) return new LinkedList<>(); - return recursion(1, n); + // 构造闭区间 [1, n] 组成的 BST + return build(1, n); } - public List recursion(int begin, int end) { - + // 构造闭区间 [lo, hi] 组成的 BST + List build(int lo, int hi) { List res = new LinkedList<>(); - if (begin > end) { + // base case + if (lo > hi) { res.add(null); return res; } - for (int i = begin; i <= end; i++) { - List leftTrees = recursion(begin, i - 1); - List rightTrees = recursion(i + 1, end); - for (TreeNode left : leftTrees) { - for (TreeNode right : rightTrees) { + // 1、穷举 root 节点的所有可能。 + for (int i = lo; i <= hi; i++) { + // 2、递归构造出左右子树的所有合法 BST。 + List leftTree = build(lo, i - 1); + List rightTree = build(i + 1, hi); + // 3、给 root 节点穷举所有左右子树的组合。 + for (TreeNode left : leftTree) { + for (TreeNode right : rightTree) { + // i 作为根节点 root 的值 TreeNode root = new TreeNode(i); root.left = left; root.right = right; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\345\255\220\346\240\221\347\232\204\346\234\200\345\244\247\351\224\256\345\200\274\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\345\255\220\346\240\221\347\232\204\346\234\200\345\244\247\351\224\256\345\200\274\345\222\214.java" new file mode 100644 index 0000000..e4c8092 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\345\255\220\346\240\221\347\232\204\346\234\200\345\244\247\351\224\256\345\200\274\345\222\214.java" @@ -0,0 +1,77 @@ +package io.github.dunwu.algorithm.tree.bstree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +/** + * 96. 不同的二叉搜索树 + * + * @author Zhang Peng + * @date 2025-10-22 + */ +public class 二叉搜索子树的最大键值和 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(20, + s.maxSumBST(TreeNode.buildTree(1, 4, 3, 2, 4, 2, 5, null, null, null, null, null, null, 4, 6))); + Assertions.assertEquals(2, s.maxSumBST(TreeNode.buildTree(4, 3, null, 1, 2))); + Assertions.assertEquals(0, s.maxSumBST(TreeNode.buildTree(-4, -2, -5))); + Assertions.assertEquals(6, s.maxSumBST(TreeNode.buildTree(2, 1, 3))); + Assertions.assertEquals(7, s.maxSumBST(TreeNode.buildTree(5, 4, 8, 3, null, 6, 3))); + } + + static class Solution { + + // 记录 BST 最大节点之和 + int maxSum = 0; + + public int maxSumBST(TreeNode root) { + maxSum = 0; + findMaxMinSum(root); + return maxSum; + } + + // 计算以 root 为根的二叉树的最大值、最小值、节点和 + int[] findMaxMinSum(TreeNode root) { + // base case + if (root == null) { + return new int[] { + 1, Integer.MAX_VALUE, Integer.MIN_VALUE, 0 + }; + } + + // 递归计算左右子树 + int[] left = findMaxMinSum(root.left); + int[] right = findMaxMinSum(root.right); + + // ******* 后序位置 ******* + // 通过 left 和 right 推导返回值 + // 并且正确更新 maxSum 变量 + int[] res = new int[4]; + // 这个 if 在判断以 root 为根的二叉树是不是 BST + if (left[0] == 1 && right[0] == 1 && + root.val > left[2] && root.val < right[1]) { + // 以 root 为根的二叉树是 BST + res[0] = 1; + // 计算以 root 为根的这棵 BST 的最小值 + res[1] = Math.min(left[1], root.val); + // 计算以 root 为根的这棵 BST 的最大值 + res[2] = Math.max(right[2], root.val); + // 计算以 root 为根的这棵 BST 所有节点之和 + res[3] = left[3] + right[3] + root.val; + // 更新全局变量 + maxSum = Math.max(maxSum, res[3]); + } else { + // 以 root 为根的二叉树不是 BST + res[0] = 0; + // 其他的值都没必要计算了,因为用不到 + } + // ************************ + + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" index 795a849..c705bf3 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" @@ -30,13 +30,17 @@ static class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if (root == null) { return null; } - if (root == p || root == q) { return root; } - - TreeNode left = lowestCommonAncestor(root.left, p, q); - TreeNode right = lowestCommonAncestor(root.right, p, q); - if (left != null && right != null) { return root; } - if (left == null && right == null) { return null; } - return left == null ? right : left; + if (p.val > q.val) { + return lowestCommonAncestor(root, q, p); + } + if (p.val <= root.val && root.val <= q.val) { + return root; + } + if (root.val > q.val) { + return lowestCommonAncestor(root.left, p, q); + } else { + return lowestCommonAncestor(root.right, p, q); + } } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" index 47bedb7..a4cd7f7 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Assertions; /** - * 二叉搜索树结点最小距离 + * 783. 二叉搜索树节点最小距离 * * @author Zhang Peng * @date 2020-06-18 @@ -12,35 +12,42 @@ public class 二叉搜索树节点最小距离 { public static void main(String[] args) { - Solution s = new Solution(); - - TreeNode tree = TreeNode.buildTree(4, 2, 6, 1, 3); - Assertions.assertEquals(1, s.minDiffInBST(tree)); + Assertions.assertEquals(1, s.minDiffInBST(TreeNode.buildTree(4, 2, 6, 1, 3))); + Assertions.assertEquals(1, s.minDiffInBST(TreeNode.buildTree(1, 0, 48, null, null, 12, 49))); } static class Solution { - int pre = -1; - int min = Integer.MAX_VALUE; + private int res; public int minDiffInBST(TreeNode root) { - pre = -1; - min = Integer.MAX_VALUE; - dfs(root); - return min; + res = 0; + int rightMin = getMin(root.right); + int leftMax = getMax(root.left); + res = min(root.val, rightMin, leftMax); + return res; } - public void dfs(TreeNode root) { - if (root == null) return; - dfs(root.left); - if (pre == -1) { - pre = root.val; - } else { - min = Math.min(min, Math.abs(pre - root.val)); - pre = root.val; + public int getMin(TreeNode root) { + if (root.left != null) { + return getMin(root.left); } - dfs(root.right); + return root.val; + } + + public int getMax(TreeNode root) { + if (root.right != null) { + return getMax(root.right); + } + return root.val; + } + + public int min(int a, int b, int c) { + int min = 0; + min = Math.min(Math.abs(a - b), Math.abs(a - c)); + min = Math.min(min, Math.abs(b - c)); + return min; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\273\216\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\345\210\260\346\233\264\345\244\247\345\222\214\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\273\216\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\345\210\260\346\233\264\345\244\247\345\222\214\346\240\221.java" new file mode 100644 index 0000000..e76ff50 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\273\216\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\345\210\260\346\233\264\345\244\247\345\222\214\346\240\221.java" @@ -0,0 +1,47 @@ +package io.github.dunwu.algorithm.tree.bstree; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +/** + * 538. 把二叉搜索树转换为累加树 + * + * @author Zhang Peng + * @date 2025-10-22 + */ +public class 从二叉搜索树到更大和树 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + TreeNode input1 = TreeNode.buildTree(4, 1, 6, 0, 2, 5, 7, null, null, null, 3, null, null, null, 8); + TreeNode output1 = s.bstToGst(input1); + TreeNode expect1 = TreeNode.buildTree(30, 36, 21, 36, 35, 26, 15, null, null, null, 33, null, null, null, 8); + Assertions.assertEquals(expect1, output1); + + Assertions.assertEquals(TreeNode.buildTree(1, null, 1), s.bstToGst(TreeNode.buildTree(0, null, 1))); + } + + static class Solution { + + private int sum = 0; + + public TreeNode bstToGst(TreeNode root) { + sum = 0; + dfs(root); + return root; + } + + public void dfs(TreeNode root) { + if (root == null) { return; } + dfs(root.right); + sum += root.val; + root.val = sum; + // System.out.printf("%s\n", root.val); + dfs(root.left); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" index 536a296..e088862 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" @@ -21,36 +21,44 @@ public static void main(String[] args) { TreeNode output2 = s.deleteNode(TreeNode.buildTree(5, 3, 6, 2, 4, null, 7), 0); Assertions.assertEquals(TreeNode.buildTree(5, 3, 6, 2, 4, null, 7), output2); + TreeNode output3 = s.deleteNode(TreeNode.buildTree(5, 3, 6, 2, 4, null, 7), 5); + Assertions.assertEquals(TreeNode.buildTree(6, 3, 7, 2, 4), output3); + + Assertions.assertEquals(TreeNode.buildTree(1), s.deleteNode(TreeNode.buildTree(2, 1), 2)); + Assertions.assertNull(s.deleteNode(TreeNode.buildTree(), 0)); + Assertions.assertNull(s.deleteNode(TreeNode.buildTree(0), 0)); } static class Solution { public TreeNode deleteNode(TreeNode root, int key) { if (root == null) { return null; } - - if (root.val < key) { - root.right = deleteNode(root.right, key); - } else if (root.val > key) { - root.left = deleteNode(root.left, key); - } else { + if (root.val == key) { if (root.left == null) { return root.right; } if (root.right == null) { return root.left; } + // 获得右子树最小的节点 TreeNode minRightNode = getMin(root.right); + // 删除右子树最小的节点 root.right = deleteNode(root.right, minRightNode.val); + // 用右子树最小的节点替换 root 节点 minRightNode.left = root.left; minRightNode.right = root.right; root = minRightNode; + } else if (root.val > key) { + // 去左子树找 + root.left = deleteNode(root.left, key); + } else if (root.val < key) { + // 去右子树找 + root.right = deleteNode(root.right, key); } return root; } public TreeNode getMin(TreeNode root) { if (root == null) { return null; } - if (root.left == null) { - return root; - } - return getMin(root.left); + if (root.left != null) { return getMin(root.left); } + return root; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\260\206\346\234\211\345\272\217\346\225\260\347\273\204\350\275\254\346\215\242\344\270\272\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\260\206\346\234\211\345\272\217\346\225\260\347\273\204\350\275\254\346\215\242\344\270\272\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" index 13f1b29..2ba0983 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\260\206\346\234\211\345\272\217\346\225\260\347\273\204\350\275\254\346\215\242\344\270\272\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\260\206\346\234\211\345\272\217\346\225\260\347\273\204\350\275\254\346\215\242\344\270\272\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Assertions; /** - * 二叉搜索树结点最小距离 + * 108. 将有序数组转换为二叉搜索树 * * @author Zhang Peng * @since 2020-07-07 @@ -13,36 +13,32 @@ public class 将有序数组转换为二叉搜索树 { public static void main(String[] args) { Solution s = new Solution(); - TreeNode output1 = s.sortedArrayToBST(new int[] { -10, -3, 0, 5, 9 }); - Assertions.assertArrayEquals(new Integer[] { 0, -3, 9, -10, null, 5 }, TreeNode.toValueList(output1).toArray()); + Assertions.assertEquals(TreeNode.buildTree(0, -3, 9, -10, null, 5), + s.sortedArrayToBST(new int[] { -10, -3, 0, 5, 9 })); + Assertions.assertEquals(TreeNode.buildTree(3, 1), s.sortedArrayToBST(new int[] { 1, 3 })); } static class Solution { public TreeNode sortedArrayToBST(int[] nums) { - if (nums == null || nums.length == 0) { return null; } - TreeNode root = new TreeNode(nums[0]); - for (int i = 1; i < nums.length; i++) { - insert(root, nums[i]); - } - return root; + return sortedArrayToBST(nums, 0, nums.length - 1); } - public void insert(TreeNode root, int val) { - if (root == null) { return; } - if (val < root.val) { - if (root.left == null) { - root.left = new TreeNode(val); - } else { - insert(root.left, val); - } - } else if (val > root.val) { - if (root.right == null) { - root.right = new TreeNode(val); - } else { - insert(root.right, val); - } + // 将闭区间 [left, right] 中的元素转化成 BST,返回根节点 + TreeNode sortedArrayToBST(int[] nums, int left, int right) { + if (left > right) { + // 区间为空 + return null; } + // 构造根节点 + // BST 节点左小右大,中间的元素就是根节点 + int mid = (left + right) / 2; + TreeNode root = new TreeNode(nums[mid]); + // 递归构建左子树 + root.left = sortedArrayToBST(nums, left, mid - 1); + // 递归构造右子树 + root.right = sortedArrayToBST(nums, mid + 1, right); + return root; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" index 28fe59b..5fb168e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" @@ -4,10 +4,9 @@ import org.junit.jupiter.api.Assertions; /** - * 98. 验证二叉搜索树 算法实现 + * 98. 验证二叉搜索树 * * @author Zhang Peng - * @see 98. 验证二叉搜索树 * @since 2020-07-02 */ public class 验证二叉搜索树 { @@ -28,13 +27,13 @@ public boolean isValidBST(TreeNode root) { // 限定以 root 为根的子树节点必须满足 max.val > root.val > min.val boolean isValidBST(TreeNode root, TreeNode min, TreeNode max) { - if (root == null) { return true; } + // base case + if (root == null) return true; // 若 root.val 不符合 max 和 min 的限制,说明不是合法 BST - if (min != null && root.val <= min.val) { return false; } - if (max != null && root.val >= max.val) { return false; } + if (min != null && root.val <= min.val) return false; + if (max != null && root.val >= max.val) return false; // 限定左子树的最大值是 root.val,右子树的最小值是 root.val - return isValidBST(root.left, min, root) - && isValidBST(root.right, root, max); + return isValidBST(root.left, min, root) && isValidBST(root.right, root, max); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\344\270\255\346\211\200\346\234\211\350\267\235\347\246\273\344\270\272K\347\232\204\347\273\223\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\344\270\255\346\211\200\346\234\211\350\267\235\347\246\273\344\270\272K\347\232\204\347\273\223\347\202\271.java" new file mode 100644 index 0000000..c9c6a89 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\344\270\255\346\211\200\346\234\211\350\267\235\347\246\273\344\270\272K\347\232\204\347\273\223\347\202\271.java" @@ -0,0 +1,87 @@ +package io.github.dunwu.algorithm.tree.btree.bfs; + +import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; + +/** + * 863. 二叉树中所有距离为 K 的结点 + * + * @author Zhang Peng + * @date 2025-12-01 + */ +public class 二叉树中所有距离为K的结点 { + + public static void main(String[] args) { + Solution s = new Solution(); + TreeNode input = TreeNode.buildTree(1, 2, 3, 4, 5, 6, 7); + TreeNode target = TreeNode.find(input, 5); + Assertions.assertArrayEquals(new Integer[] { 7, 4, 1 }, s.distanceK(input, target, 2).toArray()); + } + + static class Solution { + + // 记录父节点:node.val -> parentNode + // 题目说了树中所有节点值都是唯一的,所以可以用 node.val 代表 TreeNode + HashMap parent = new HashMap<>(); + + public List distanceK(TreeNode root, TreeNode target, int k) { + // 遍历所有节点,记录每个节点的父节点 + traverse(root, null); + + // 开始从 target 节点施放 BFS 算法,找到距离为 k 的节点 + LinkedList q = new LinkedList<>(); + HashSet visited = new HashSet<>(); + q.offer(target); + visited.add(target.val); + // 记录离 target 的距离 + int dist = 0; + List res = new LinkedList<>(); + + while (!q.isEmpty()) { + int sz = q.size(); + for (int i = 0; i < sz; i++) { + TreeNode cur = q.poll(); + if (dist == k) { + // 找到距离起点 target 距离为 k 的节点 + res.add(cur.val); + } + // 向父节点、左右子节点扩散 + TreeNode parentNode = parent.get(cur.val); + if (parentNode != null && !visited.contains(parentNode.val)) { + visited.add(parentNode.val); + q.offer(parentNode); + } + if (cur.left != null && !visited.contains(cur.left.val)) { + visited.add(cur.left.val); + q.offer(cur.left); + } + if (cur.right != null && !visited.contains(cur.right.val)) { + visited.add(cur.right.val); + q.offer(cur.right); + } + } + // 向外扩展一圈 + dist++; + } + + return res; + } + + private void traverse(TreeNode root, TreeNode parentNode) { + if (root == null) { + return; + } + parent.put(root.val, parentNode); + // 二叉树递归框架 + traverse(root.left, root); + traverse(root.right, root); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" index 860155a..740f4ea 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" @@ -1,12 +1,12 @@ package io.github.dunwu.algorithm.tree.btree.bfs; import io.github.dunwu.algorithm.tree.TreeNode; +import org.junit.jupiter.api.Assertions; import java.util.LinkedList; -import java.util.Queue; /** - * 1302. 层数最深叶子节点的和 + * 919. 完全二叉树插入器 * * @author Zhang Peng * @date 2025-08-18 @@ -14,56 +14,59 @@ public class 完全二叉树插入器 { public static void main(String[] args) { - TreeNode root = TreeNode.buildTree(1, 2); - Solution cBTInserter = new Solution(root); - cBTInserter.insert(3); // 返回 1 - cBTInserter.insert(4); // 返回 2 - cBTInserter.get_root(); // 返回 [1, 2, 3, 4] + CBTInserter c = new CBTInserter(TreeNode.buildTree(1, 2)); + Assertions.assertEquals(1, c.insert(3)); + Assertions.assertEquals(2, c.insert(4)); + Assertions.assertEquals(TreeNode.buildTree(1, 2, 3, 4), c.get_root()); } - static class Solution { + static class CBTInserter { - private TreeNode root = null; - private Queue q = null; + private TreeNode root; + private final LinkedList unfull; - public Solution(TreeNode root) { + public CBTInserter(TreeNode root) { this.root = root; - this.q = new LinkedList<>(); - // 进行普通的 BFS,目的是找到底部可插入的节点 - Queue temp = new LinkedList<>(); - temp.offer(root); - while (!temp.isEmpty()) { - TreeNode cur = temp.poll(); - if (cur.left != null) { - temp.offer(cur.left); - } - if (cur.right != null) { - temp.offer(cur.right); - } - if (cur.right == null || cur.left == null) { - // 找到完全二叉树底部可以进行插入的节点 - q.offer(cur); + this.unfull = new LinkedList<>(); + + LinkedList q = new LinkedList<>(); + q.offer(this.root); + while (!q.isEmpty()) { + for (int i = 0; i < q.size(); i++) { + TreeNode node = q.poll(); + if (node.left != null) { + q.offer(node.left); + } + if (node.right != null) { + q.offer(node.right); + } + if (node.left == null || node.right == null) { + unfull.offer(node); + } } } } public int insert(int val) { + if (root == null) { + root = new TreeNode(val); + return 0; + } + + TreeNode parent = unfull.peek(); TreeNode node = new TreeNode(val); - TreeNode cur = q.peek(); - // 进行插入 - if (cur.left == null) { - cur.left = node; - } else if (cur.right == null) { - cur.right = node; - q.poll(); + if (parent.left == null) { + parent.left = node; + } else if (parent.right == null) { + parent.right = node; + unfull.poll(); } - // 新节点的左右节点也是可以插入的 - q.offer(node); - return cur.val; + unfull.offer(node); + return parent.val; } public TreeNode get_root() { - return root; + return this.root; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\345\211\252\346\236\235.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\345\211\252\346\236\235.java" index 649b851..ca687c2 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\345\211\252\346\236\235.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\345\211\252\346\236\235.java" @@ -25,9 +25,11 @@ static class Solution { public TreeNode pruneTree(TreeNode root) { if (root == null) { return null; } + root.left = pruneTree(root.left); root.right = pruneTree(root.right); - if (root.val == 0 && root.left == null && root.right == null) { + + if (root.left == null && root.right == null && root.val == 0) { return null; } return root; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" index e8adf03..550c275 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; /** * 508. 出现次数最多的子树元素和 @@ -18,27 +19,31 @@ public class 出现次数最多的子树元素和 { public static void main(String[] args) { Solution s = new Solution(); Assertions.assertArrayEquals(new int[] { 2, -3, 4 }, s.findFrequentTreeSum(TreeNode.buildTree(5, 2, -3))); + Assertions.assertArrayEquals(new int[] { 2 }, s.findFrequentTreeSum(TreeNode.buildTree(5, 2, -5))); } static class Solution { - private HashMap map = new HashMap<>(); + private Map map; public int[] findFrequentTreeSum(TreeNode root) { - + map = new HashMap<>(); sum(root); int max = Integer.MIN_VALUE; - for (int cnt : map.values()) { - max = Math.max(max, cnt); - } - List list = new ArrayList<>(); - for (Integer key : map.keySet()) { - if (map.get(key) == max) { - list.add(key); + for (Map.Entry entry : map.entrySet()) { + Integer k = entry.getKey(); + Integer v = entry.getValue(); + if (v > max) { + max = v; + list.clear(); + list.add(k); + } else if (v == max) { + list.add(k); } } + int[] res = new int[list.size()]; for (int i = 0; i < list.size(); i++) { res[i] = list.get(i); @@ -48,9 +53,9 @@ public int[] findFrequentTreeSum(TreeNode root) { public int sum(TreeNode root) { if (root == null) { return 0; } - int leftSum = sum(root.left); - int rightSum = sum(root.right); - int sum = leftSum + rightSum + root.val; + int left = sum(root.left); + int right = sum(root.right); + int sum = left + right + root.val; map.put(sum, map.getOrDefault(sum, 0) + 1); return sum; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" index c97a2f8..60f113b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" @@ -4,7 +4,6 @@ import org.junit.jupiter.api.Assertions; import java.util.ArrayList; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; @@ -39,28 +38,34 @@ public static void main(String[] args) { static class Solution { - private Set set = null; - private List res = null; + Set delSet; + // 记录森林的根节点 + List res; public List delNodes(TreeNode root, int[] to_delete) { - if (root == null) { return new ArrayList<>(); } - set = new HashSet<>(); - res = new LinkedList<>(); - for (int val : to_delete) { - set.add(val); + if (root == null) return new LinkedList<>(); + for (int d : to_delete) { + delSet.add(d); } - traverse(root, false); + doDelete(root, false); return res; } - public TreeNode traverse(TreeNode root, boolean hasParent) { - if (root == null) { return null; } - boolean deleted = set.contains(root.val); + // 定义:输入一棵二叉树,删除 delSet 中的节点,返回删除完成后的根节点 + private TreeNode doDelete(TreeNode root, boolean hasParent) { + if (root == null) { + return null; + } + // 判断是否需要被删除 + boolean deleted = delSet.contains(root.val); if (!deleted && !hasParent) { + // 没有父节点且不需要被删除,就是一个新的根节点 res.add(root); } - root.left = traverse(root.left, !deleted); - root.right = traverse(root.right, !deleted); + // 去左右子树进行删除 + root.left = doDelete(root.left, !deleted); + root.right = doDelete(root.right, !deleted); + // 如果需要被删除,返回 null 给父节点 return deleted ? null : root; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" index 4b597e9..6c7a1b7 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" @@ -23,15 +23,18 @@ public static void main(String[] args) { static class Solution { public boolean flipEquiv(TreeNode root1, TreeNode root2) { + // 判断 root1 和 root2 两个节点是否能够匹配 if (root1 == null && root2 == null) { return true; } if (root1 == null || root2 == null) { return false; } if (root1.val != root2.val) { return false; } + // 根据函数定义,判断子树是否能够匹配 + // 不翻转、翻转两种情况满足一种即可算是匹配 return ( // 不翻转子树 flipEquiv(root1.left, root2.left) && flipEquiv(root1.right, root2.right) ) || ( - // 翻转子树 - flipEquiv(root1.right, root2.left) && flipEquiv(root1.left, root2.right) + // 反转子树 + flipEquiv(root1.left, root2.right) && flipEquiv(root1.right, root2.left) ); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" index 190a86a..1862877 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" @@ -2,8 +2,8 @@ import org.junit.jupiter.api.Assertions; -import java.util.Arrays; import java.util.LinkedList; +import java.util.Stack; /** * 331. 验证二叉树的前序序列化 @@ -18,6 +18,11 @@ public static void main(String[] args) { Assertions.assertTrue(s.isValidSerialization("9,3,4,#,#,1,#,#,2,#,6,#,#")); Assertions.assertFalse(s.isValidSerialization("1,#")); Assertions.assertFalse(s.isValidSerialization("9,#,#,1")); + + Solution2 s2 = new Solution2(); + Assertions.assertTrue(s2.isValidSerialization("9,3,4,#,#,1,#,#,2,#,6,#,#")); + Assertions.assertFalse(s2.isValidSerialization("1,#")); + Assertions.assertFalse(s2.isValidSerialization("9,#,#,1")); } static class Solution { @@ -26,14 +31,37 @@ static class Solution { * 参考题解:https://leetcode.cn/problems/verify-preorder-serialization-of-a-binary-tree/solutions/651132/pai-an-jiao-jue-de-liang-chong-jie-fa-zh-66nt */ public boolean isValidSerialization(String preorder) { - LinkedList values = new LinkedList<>(Arrays.asList(preorder.split(","))); + LinkedList stack = new LinkedList<>(); + for (String s : preorder.split(",")) { + stack.push(s); + while (stack.size() >= 3 + && stack.get(0).equals("#") + && stack.get(1).equals("#") + && !stack.get(2).equals("#")) { + stack.pop(); + stack.pop(); + stack.pop(); + stack.push("#"); + } + } + return stack.size() == 1 && stack.pop().equals("#"); + } + + } + + static class Solution2 { + + /** + * 参考题解:https://leetcode.cn/problems/verify-preorder-serialization-of-a-binary-tree/solutions/651132/pai-an-jiao-jue-de-liang-chong-jie-fa-zh-66nt + */ + public boolean isValidSerialization(String preorder) { int diff = 1; - for (String val : values) { + for (String s : preorder.split(",")) { diff -= 1; if (diff < 0) { return false; } - if (!val.equals("#")) { + if (!s.equals("#")) { diff += 2; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" index 2c934ef..c55a9d6 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" @@ -21,20 +21,21 @@ public static void main(String[] args) { static class Solution { - int res = 0; + private int max = 0; public int diameterOfBinaryTree(TreeNode root) { - res = 0; - dfs(root); - return res; + max = 0; + depth(root); + return max; } - public int dfs(TreeNode root) { - if (root == null) { return -1; } - int left = dfs(root.left) + 1; - int right = dfs(root.right) + 1; - res = Math.max(res, left + right); - return Math.max(left, right); + public int depth(TreeNode root) { + if (root == null) { return 0; } + int left = depth(root.left); + int right = depth(root.right); + int depth = Math.max(left, right) + 1; + max = Math.max(max, left + right); + return depth; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 0000000..3f2138f --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,47 @@ +package io.github.dunwu.algorithm.tree.ntree; + +import io.github.dunwu.algorithm.tree.Node; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.List; + +/** + * 589. N 叉树的前序遍历 + * + * @author Zhang Peng + * @date 2025-10-27 + */ +public class N叉树的前序遍历 { + + public static void main(String[] args) { + Solution s = new Solution(); + Node node3 = new Node(3); + node3.children.add(new Node(5)); + node3.children.add(new Node(6)); + Node root = new Node(1); + root.children.add(node3); + root.children.add(new Node(2)); + root.children.add(new Node(4)); + Assertions.assertArrayEquals(new Integer[] { 1, 3, 5, 6, 2, 4 }, s.preorder(root).toArray()); + } + + static class Solution { + + public List preorder(Node root) { + List res = new ArrayList<>(); + dfs(root, res); + return res; + } + + public void dfs(Node root, List res) { + if (root == null) { return; } + res.add(root.val); + for (int i = 0; i < root.children.size(); i++) { + dfs(root.children.get(i), res); + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 0000000..17db4ac --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,47 @@ +package io.github.dunwu.algorithm.tree.ntree; + +import io.github.dunwu.algorithm.tree.Node; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.List; + +/** + * 589. N 叉树的前序遍历 + * + * @author Zhang Peng + * @date 2025-10-27 + */ +public class N叉树的后序遍历 { + + public static void main(String[] args) { + Solution s = new Solution(); + Node node3 = new Node(3); + node3.children.add(new Node(5)); + node3.children.add(new Node(6)); + Node root = new Node(1); + root.children.add(node3); + root.children.add(new Node(2)); + root.children.add(new Node(4)); + Assertions.assertArrayEquals(new Integer[] { 5, 6, 3, 2, 4, 1 }, s.postorder(root).toArray()); + } + + static class Solution { + + public List postorder(Node root) { + List res = new ArrayList<>(); + dfs(root, res); + return res; + } + + public void dfs(Node root, List res) { + if (root == null) { return; } + for (int i = 0; i < root.children.size(); i++) { + dfs(root.children.get(i), res); + } + res.add(root.val); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" similarity index 56% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" index 4caf155..ca4152f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" @@ -1,5 +1,8 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; +package io.github.dunwu.algorithm.tree.ntree; +import io.github.dunwu.algorithm.tree.Node; + +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -27,56 +30,32 @@ public static void main(String[] args) { static class Solution { public List> levelOrder(Node root) { - if (root == null) { return new LinkedList<>(); } - - int depth = 1; - LinkedList> res = new LinkedList<>(); + List> res = new ArrayList<>(); LinkedList queue = new LinkedList<>(); - queue.addLast(root); + queue.offer(root); + while (!queue.isEmpty()) { int size = queue.size(); - List list = new LinkedList<>(); + LinkedList list = new LinkedList<>(); for (int i = 0; i < size; i++) { - Node node = queue.removeFirst(); + Node node = queue.poll(); if (node == null) { continue; } list.add(node.val); - if (node.children != null && node.children.size() > 0) { + if (!node.children.isEmpty()) { for (Node child : node.children) { - queue.addLast(child); + queue.offer(child); } } } - System.out.printf("[depth: %d]nodes: %s\n", depth, list); - res.add(list); - depth++; + if (!list.isEmpty()) { + res.add(list); + } } return res; } } - static class Node { - - public int val; - public List children; - - public Node() { - val = -1; - children = new LinkedList<>(); - } - - public Node(int val) { - this.val = val; - this.children = new LinkedList<>(); - } - - public Node(int val, List children) { - this.val = val; - this.children = children; - } - - } - } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" new file mode 100644 index 0000000..b4ab98a --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" @@ -0,0 +1,49 @@ +package io.github.dunwu.algorithm.tree.ntree; + +import io.github.dunwu.algorithm.tree.Node; +import org.junit.jupiter.api.Assertions; + +/** + * 559. N叉树的最大深度 + * + * @author Zhang Peng + * @date 2020-03-23 + */ +public class N叉树的最大深度 { + + public static void main(String[] args) { + Solution s = new Solution(); + io.github.dunwu.algorithm.tree.Node node3 = new io.github.dunwu.algorithm.tree.Node(3); + node3.children.add(new io.github.dunwu.algorithm.tree.Node(5)); + node3.children.add(new io.github.dunwu.algorithm.tree.Node(6)); + io.github.dunwu.algorithm.tree.Node root = new io.github.dunwu.algorithm.tree.Node(1); + root.children.add(node3); + root.children.add(new io.github.dunwu.algorithm.tree.Node(2)); + root.children.add(new io.github.dunwu.algorithm.tree.Node(4)); + Assertions.assertEquals(3, s.maxDepth(root)); + } + + static class Solution { + + private int max = 0; + + public int maxDepth(Node root) { + max = 0; + dfs(root); + return max; + } + + public int dfs(Node root) { + if (root == null) { return 0; } + + int depth = 0; + for (int i = 0; i < root.children.size(); i++) { + depth = Math.max(depth, dfs(root.children.get(i))); + } + max = Math.max(max, depth + 1); + return depth + 1; + } + + } + +} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java index 448f347..89c3766 100644 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java +++ b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java @@ -1,6 +1,6 @@ package io.github.dunwu.algorithm.list; -import io.github.dunwu.algorithm.linkedlist.DoublyLinkedList; +import io.github.dunwu.algorithm.linkedlist.demo.DoublyLinkedList; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java index aabfe67..15020fd 100644 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java +++ b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java @@ -1,6 +1,6 @@ package io.github.dunwu.algorithm.list; -import io.github.dunwu.algorithm.linkedlist.SinglyLinkedList; +import io.github.dunwu.algorithm.linkedlist.demo.SinglyLinkedList; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BTreeDemoTests.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BTreeDemoTests.java deleted file mode 100644 index 72c3450..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BTreeDemoTests.java +++ /dev/null @@ -1,75 +0,0 @@ -package io.github.dunwu.algorithm.tree; - -import org.junit.jupiter.api.Test; - -/** - * @author Zhang Peng - * @since 2020-01-18 - */ -public class BTreeDemoTests { - - public IntBTree.TreeNode initBTree() { - IntBTree.TreeNode root = new IntBTree.TreeNode(3); - root.left = new IntBTree.TreeNode(9); - root.right = new IntBTree.TreeNode(20); - root.left.left = null; - root.left.right = null; - root.right.left = new IntBTree.TreeNode(15); - root.right.right = new IntBTree.TreeNode(17); - return root; - } - - @Test - public void preOrderTest() { - IntBTree.TreeNode root = new IntBTree.TreeNode(3); - root.left = new IntBTree.TreeNode(9); - root.right = new IntBTree.TreeNode(20); - root.left.left = null; - root.left.right = null; - root.right.left = new IntBTree.TreeNode(15); - root.right.right = new IntBTree.TreeNode(17); - IntBTree.preOrder(root); - System.out.println(); - IntBTree.preOrder2(root); - System.out.println(); - } - - @Test - public void inOrderTest() { - IntBTree.TreeNode root = new IntBTree.TreeNode(3); - root.left = new IntBTree.TreeNode(9); - root.right = new IntBTree.TreeNode(20); - root.left.left = null; - root.left.right = null; - root.right.left = new IntBTree.TreeNode(15); - root.right.right = new IntBTree.TreeNode(17); - IntBTree.inOrder(root); - System.out.println(); - IntBTree.inOrder2(root); - System.out.println(); - } - - @Test - public void postOrderTest() { - IntBTree.TreeNode root = initBTree(); - IntBTree.postOrder(root); - System.out.println(); - IntBTree.postOrder2(root); - System.out.println(); - } - - @Test - public void levelTraverseTest() { - IntBTree.TreeNode root = initBTree(); - IntBTree.levelTraverse(root); - System.out.println(); - } - - @Test - public void depthOrderTraverseTest() { - IntBTree.TreeNode root = initBTree(); - IntBTree.depthOrderTraverse(root); - System.out.println(); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BTreeTests.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BTreeTests.java index 9605eed..f53c916 100644 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BTreeTests.java +++ b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BTreeTests.java @@ -18,36 +18,36 @@ public class BTreeTests { @Test @DisplayName("二叉树的最大深度") public void maxDepthTest() { - BTree tree = BTree.buildTree(1, 2, 3, 4, 5); + BTree tree = BTree.build(1, 2, 3, 4, 5); Assertions.assertEquals(3, tree.maxDepth()); } @Test @DisplayName("二叉树的最小深度") public void minDepthTest() { - BTree tree = BTree.buildTree(3, 9, 20, null, null, 15, 7); + BTree tree = BTree.build(3, 9, 20, null, null, 15, 7); Assertions.assertEquals(2, tree.minDepth()); - tree = BTree.buildTree(1, 2); + tree = BTree.build(1, 2); Assertions.assertEquals(2, tree.minDepth()); } @Test @DisplayName("判断两颗二叉树是否完全一致") public void isEqualsTest() { - BTree tree1 = BTree.buildTree(1, 2, 3); - BTree tree2 = BTree.buildTree(1, 2, 3); + BTree tree1 = BTree.build(1, 2, 3); + BTree tree2 = BTree.build(1, 2, 3); Assertions.assertTrue(BTree.isEquals(tree1, tree2)); - tree1 = BTree.buildTree(1, 2, 1); - tree2 = BTree.buildTree(1, 1, 2); + tree1 = BTree.build(1, 2, 1); + tree2 = BTree.build(1, 1, 2); Assertions.assertFalse(BTree.isEquals(tree1, tree2)); } @Test @DisplayName("广度优先搜索(BFS)") public void levelOrderBottomTest() { - BTree tree = BTree.buildTree(3, 9, 20, null, null, 15, 7); + BTree tree = BTree.build(3, 9, 20, null, null, 15, 7); List> lists = new ArrayList<>(); lists.add(Collections.singletonList(3)); lists.add(Arrays.asList(9, 20)); @@ -58,8 +58,8 @@ public void levelOrderBottomTest() { @Test @DisplayName("判断两颗二叉树的叶子节点是否相似") public void isLeafSimilarTest() { - BTree tree1 = BTree.buildTree(3, 5, 1, 6, 2, 9, 8, null, null, 7, 4); - BTree tree2 = BTree.buildTree(3, 5, 1, 6, 7, 4, 2, null, null, null, null, null, null, 9, 8); + BTree tree1 = BTree.build(3, 5, 1, 6, 2, 9, 8, null, null, 7, 4); + BTree tree2 = BTree.build(3, 5, 1, 6, 7, 4, 2, null, null, null, null, null, null, 9, 8); Assertions.assertTrue(BTree.isLeafSimilar(tree1, tree2)); } From 8d505ce2a3bfc5124b881c372f0953a55aad51f9 Mon Sep 17 00:00:00 2001 From: dunwu Date: Sat, 6 Dec 2025 22:19:54 +0800 Subject: [PATCH 18/21] =?UTF-8?q?feat:=20leetcode=20=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 119 ++++++++----- .../dunwu/algorithm/array/ArrayDemo.java | 25 --- ...\347\232\204\344\270\252\346\225\260.java" | 37 +++++ ...\346\234\200\345\244\247\346\225\260.java" | 37 +++++ ...\345\205\245\344\275\215\347\275\256.java" | 41 +++++ .../\346\250\241\346\213\237ArrayList1.java" | 2 +- .../\346\250\241\346\213\237ArrayList2.java" | 2 +- ...\347\232\204\345\215\225\350\257\215.java" | 32 ++-- ...\347\272\277\351\201\215\345\216\206.java" | 66 ++++++++ ...\346\227\213\347\237\251\351\230\265.java" | 3 +- ...\351\233\266\347\237\251\351\230\265.java" | 54 ++++++ ...\345\277\203\347\264\242\345\274\225.java" | 66 ++++++++ ...\344\270\252\351\203\250\345\210\206.java" | 58 +++++++ ...\346\225\260\344\271\213\345\222\214.java" | 62 +++++++ ...\345\210\266\346\261\202\345\222\214.java" | 46 ++++++ ...\345\271\266\345\214\272\351\227\264.java" | 62 +++++++ ...\346\226\207\345\255\220\344\270\262.java" | 21 ++- ...\345\255\220\346\225\260\347\273\204.java" | 1 + ...345\244\215\345\205\203\347\264\2402.java" | 18 +- ...\345\244\215\345\255\227\347\254\246.java" | 28 +++- ...\346\225\260\344\271\213\345\222\214.java" | 65 -------- .../array/\344\270\221\346\225\260I.java" | 27 --- .../array/\344\270\221\346\225\260II.java" | 51 ------ .../array/\344\270\221\346\225\260III.java" | 40 ----- ...\345\272\217\346\225\260\347\273\204.java" | 34 ---- ...\345\210\266\346\261\202\345\222\214.java" | 46 ------ .../array/\345\212\240\344\270\200.java" | 62 ------- ...\345\271\266\345\214\272\351\227\264.java" | 68 -------- ...346\211\276\346\225\260\345\255\227I.java" | 40 ----- ...\347\272\277\351\201\215\345\216\206.java" | 125 -------------- ...\345\277\203\347\264\242\345\274\225.java" | 101 ------------ ...\344\270\252\351\203\250\345\210\206.java" | 30 ---- ...\345\205\245\344\275\215\347\275\256.java" | 69 -------- ...347\273\204\346\213\206\345\210\2061.java" | 42 ----- ...\347\232\204\344\270\252\346\225\260.java" | 50 ------ ...\350\276\211\344\270\211\350\247\222.java" | 81 --------- ...350\276\211\344\270\211\350\247\2222.java" | 69 -------- ...\344\270\252\345\225\206\345\223\201.java" | 55 ------ ...\346\234\200\345\244\247\346\225\260.java" | 67 -------- ...\347\272\247\344\270\221\346\225\260.java" | 45 ----- ...\345\255\220\346\225\260\347\273\204.java" | 47 ------ ...\351\233\266\347\237\251\351\230\265.java" | 73 -------- .../dp/array/\344\270\221\346\225\2602.java" | 78 +++++++++ .../dp/array/\344\270\221\346\225\2603.java" | 43 +++++ ...\347\272\247\344\270\221\346\225\260.java" | 73 ++++++++ ...\350\276\211\344\270\211\350\247\222.java" | 54 ++++++ ...350\276\211\344\270\211\350\247\2222.java" | 49 ++++++ ...\344\272\214\345\210\206\345\233\276.java" | 138 ++++++++++++++++ ...\344\272\214\345\210\206\346\263\225.java" | 82 +++++++++ .../algorithm/graph/template/Dijkstra.java | 78 +++++++++ ...\345\271\266\346\237\245\351\233\206.java" | 60 +++++++ ...\350\257\276\347\250\213\350\241\250.java" | 113 +++++++++---- ...350\257\276\347\250\213\350\241\2502.java" | 156 ++++++++++++++++++ ...\344\275\231\350\277\236\346\216\245.java" | 84 ++++++++++ ...\346\273\241\350\266\263\346\200\247.java" | 94 +++++++++++ ...\347\232\204\345\214\272\345\237\237.java" | 134 +++++++++++++++ ...\344\272\214\345\210\206\345\233\276.java" | 72 -------- ...\347\273\204\346\213\206\345\210\206.java" | 35 ++++ ...\345\272\217\351\223\276\350\241\250.java" | 6 +- ...\350\275\254\351\223\276\350\241\250.java" | 32 ++-- .../math/\344\270\221\346\225\260.java" | 32 ++++ .../math/\345\212\240\344\270\200.java" | 38 +++++ ...\345\272\217\345\210\227\345\214\226.java" | 1 - 63 files changed, 1994 insertions(+), 1525 deletions(-) delete mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/ArrayDemo.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/base/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/base/\350\207\263\345\260\221\346\230\257\345\205\266\344\273\226\346\225\260\345\255\227\344\270\244\345\200\215\347\232\204\346\234\200\345\244\247\346\225\260.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\250\241\346\213\237ArrayList1.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/demo/\346\250\241\346\213\237ArrayList1.java" (98%) rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\250\241\346\213\237ArrayList2.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/demo/\346\250\241\346\213\237ArrayList2.java" (99%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\351\233\266\347\237\251\351\230\265.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250\345\210\206.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\211\346\225\260\344\271\213\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\220\210\345\271\266\345\214\272\351\227\264.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\211\346\225\260\344\271\213\345\222\214.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260II.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260III.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\212\240\344\270\200.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\345\214\272\351\227\264.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\346\225\260\345\255\227I.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250\345\210\206.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\225\260\347\273\204\346\213\206\345\210\2061.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\235\250\350\276\211\344\270\211\350\247\222.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\235\250\350\276\211\344\270\211\350\247\2222.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\207\263\345\260\221\346\230\257\345\205\266\344\273\226\346\225\260\345\255\227\344\270\244\345\200\215\347\232\204\346\234\200\345\244\247\346\225\260.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\233\266\347\237\251\351\230\265.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2602.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2603.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\235\250\350\276\211\344\270\211\350\247\222.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\235\250\350\276\211\344\270\211\350\247\2222.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\217\257\350\203\275\347\232\204\344\272\214\345\210\206\346\263\225.java" create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/Dijkstra.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\271\266\346\237\245\351\233\206.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\2502.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\345\206\227\344\275\231\350\277\236\346\216\245.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\347\255\211\345\274\217\346\226\271\347\250\213\347\232\204\345\217\257\346\273\241\350\266\263\346\200\247.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\346\225\260\347\273\204\346\213\206\345\210\206.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/math/\344\270\221\346\225\260.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/math/\345\212\240\344\270\200.java" diff --git a/README.md b/README.md index 954d5c9..84f4e1c 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ | [61. 旋转链表](https://leetcode.cn/problems/rotate-list/) | 💛 | ✔️ | | [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/) | 💚 | ✔️ | | [92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/) | 💛 | ✔️ | -| [25. K 个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group/) | ❤️ | ❗ | +| [25. K 个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group/) | ❤️ | ✔️ | #### 分治 @@ -109,6 +109,13 @@ ### 数组 +#### 基础 + +| 题目 | 难度 | 掌握度 | +| -------------------------------------------------------------------------------------------------------- | ---- | ------ | +| [485. 最大连续 1 的个数](https://leetcode.cn/problems/max-consecutive-ones/) | 💚 | ✔️ | +| [747. 至少是其他数字两倍的最大数](https://leetcode.cn/problems/largest-number-at-least-twice-of-others/) | 💚 | ✔️ | + #### 双指针技巧 | 题目 | 难度 | 掌握度 | @@ -117,6 +124,7 @@ | [283. 移动零](https://leetcode.cn/problems/move-zeroes/) | 💚 | ✔️ | | [LCR 179. 查找总价格为目标值的两个商品](https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/) | 💚 | ✔️ | | [1. 两数之和](https://leetcode.cn/problems/two-sum/) | 💚 | ✔️ | +| [67. 二进制求和](https://leetcode.cn/problems/add-binary/) | 💚 | ✔️ | | [167. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/)
[LCR 006. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/kLl5u1/) | 💛 | ✔️ | | [26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/) | 💚 | ✔️ | | [80. 删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/) | 💛 | ✔️ | @@ -130,17 +138,19 @@ | [1260. 二维网格迁移](https://leetcode.cn/problems/shift-2d-grid/) | 💚 | ✔️ | | [867. 转置矩阵](https://leetcode.cn/problems/transpose-matrix/) | 💚 | ✔️ | | [14. 最长公共前缀](https://leetcode.cn/problems/longest-common-prefix/) | 💚 | ✔️ | -| [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | 💛 | | -| [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | 💛 | | +| [15. 三数之和](https://leetcode.cn/problems/3sum/) | 💛 | ❗ | +| [56. 合并区间](https://leetcode.cn/problems/merge-intervals/) | 💛 | ✔️ | #### 二维数组遍历 | 题目 | 难度 | 掌握度 | | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---- | ------ | -| [151. 反转字符串中的单词](https://leetcode.cn/problems/reverse-words-in-a-string/) | 💛 | ❗ | +| [151. 反转字符串中的单词](https://leetcode.cn/problems/reverse-words-in-a-string/) | 💛 | ✔️ | | [48. 旋转图像](https://leetcode.cn/problems/rotate-image/) | 💛 | ✔️ | -| [54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/)
[LCR 146. 螺旋遍历二维数组](https://leetcode.cn/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/) | 💛 | ❗ | +| [54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/)
[LCR 146. 螺旋遍历二维数组](https://leetcode.cn/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/) | 💛 | ✔️ | | [59. 螺旋矩阵 II](https://leetcode.cn/problems/spiral-matrix-ii/) | 💛 | ✔️ | +| [498. 对角线遍历](https://leetcode.cn/problems/diagonal-traverse/) | 💛 | ❌ | +| [面试题 01.08. 零矩阵](https://leetcode.cn/problems/zero-matrix-lcci/) | 💛 | ✔️ | #### 滑动窗口算法 @@ -151,12 +161,12 @@ | [567. 字符串的排列](https://leetcode.cn/problems/permutation-in-string/) | 💛 | ✔️ | | [76. 最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring/) | ❤️ | ❗ | | [1658. 将 x 减到 0 的最小操作数](https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/) | 💛 | ❌ | -| [713. 乘积小于 K 的子数组](https://leetcode.cn/problems/subarray-product-less-than-k/) | 💛 | ❗ | +| [713. 乘积小于 K 的子数组](https://leetcode.cn/problems/subarray-product-less-than-k/) | 💛 | ✔️ | | [1004. 最大连续 1 的个数 III](https://leetcode.cn/problems/max-consecutive-ones-iii/) | 💛 | ✔️ | | [424. 替换后的最长重复字符](https://leetcode.cn/problems/longest-repeating-character-replacement/) | 💛 | ❗ | | [217. 存在重复元素](https://leetcode.cn/problems/contains-duplicate/) | 💚 | ✔️ | -| [219. 存在重复元素 II](https://leetcode.cn/problems/contains-duplicate-ii/) | 💛 | ❗ | -| [220. 存在重复元素 III](https://leetcode.cn/problems/contains-duplicate-iii/) | 💛 | ❌ | +| [219. 存在重复元素 II](https://leetcode.cn/problems/contains-duplicate-ii/) | 💛 | ✔️ | +| [220. 存在重复元素 III](https://leetcode.cn/problems/contains-duplicate-iii/) | ❤️ | ❌ | | [209. 长度最小的子数组](https://leetcode.cn/problems/minimum-size-subarray-sum/) | 💛 | ✔️ | | [395. 至少有 K 个重复字符的最长子串](https://leetcode.cn/problems/longest-substring-with-at-least-k-repeating-characters/) | 💛 | ❌ | @@ -165,18 +175,22 @@ | 题目 | 难度 | 掌握度 | | :-------------------------------------------------------------------------------------------------------------------------------------- | :--- | ------ | | [34. 在排序数组中查找元素的第一个和最后一个位置](https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/) | 💛 | ✔️ | +| [35. 搜索插入位置](https://leetcode.cn/problems/search-insert-position/) | 💚 | ✔️ | | [704. 二分查找](https://leetcode.cn/problems/binary-search/) | 💚 | ✔️ | | [LCR 172. 统计目标成绩的出现次数](https://leetcode.cn/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/) | 💚 | ✔️ | | [875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) | 💛 | ❌ | | [1011. 在 D 天内送达包裹的能力](https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/) | 💛 | ❌ | | [410. 分割数组的最大值](https://leetcode.cn/problems/split-array-largest-sum/) | 💛 | ❌ | +| [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | 💛 | ❌ | #### 前缀和数组 -| 题目 | 难度 | 掌握度 | -| ---------------------------------------------------------------------------------------------- | ---- | ------ | -| [303. 区域和检索 - 数组不可变](https://leetcode.cn/problems/range-sum-query-immutable/) | 💚 | ✔️ | -| [304. 二维区域和检索 - 矩阵不可变](https://leetcode.cn/problems/range-sum-query-2d-immutable/) | 💛 | ❌ | +| 题目 | 难度 | 掌握度 | +| ----------------------------------------------------------------------------------------------------------------- | ---- | ------ | +| [303. 区域和检索 - 数组不可变](https://leetcode.cn/problems/range-sum-query-immutable/) | 💚 | ✔️ | +| [724. 寻找数组的中心下标](https://leetcode.cn/problems/find-pivot-index/) | 💚 | ✔️ | +| [1013. 将数组分成和相等的三个部分](https://leetcode.cn/problems/partition-array-into-three-parts-with-equal-sum/) | 💚 | ✔️ | +| [304. 二维区域和检索 - 矩阵不可变](https://leetcode.cn/problems/range-sum-query-2d-immutable/) | 💛 | ❌ | #### 差分数组 @@ -189,14 +203,15 @@ #### 队列 -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------------------------------ | ---- | ------ | -| [225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/) | 💚 | ✔️ | -| [933. 最近的请求次数](https://leetcode.cn/problems/number-of-recent-calls/) | 💚 | ❗ | -| [622. 设计循环队列](https://leetcode.cn/problems/design-circular-queue/) | 💛 | ❌ | -| [641. 设计循环双端队列](https://leetcode.cn/problems/design-circular-deque/) | 💛 | | -| [1670. 设计前中后队列](https://leetcode.cn/problems/design-front-middle-back-queue/) | 💛 | | -| [2073. 买票需要的时间](https://leetcode.cn/problems/time-needed-to-buy-tickets/) | 💚 | ✔️ | +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------------------------------------------- | ---- | ------ | +| [225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/) | 💚 | ✔️ | +| [933. 最近的请求次数](https://leetcode.cn/problems/number-of-recent-calls/) | 💚 | ❗ | +| [622. 设计循环队列](https://leetcode.cn/problems/design-circular-queue/) | 💛 | ❌ | +| [641. 设计循环双端队列](https://leetcode.cn/problems/design-circular-deque/) | 💛 | | +| [1670. 设计前中后队列](https://leetcode.cn/problems/design-front-middle-back-queue/) | 💛 | | +| [2073. 买票需要的时间](https://leetcode.cn/problems/time-needed-to-buy-tickets/) | 💚 | ✔️ | +| [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | 💛 | | #### 栈 @@ -350,23 +365,40 @@ #### BFS/DFS | 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------------------------------ | ------ | ------ | +| ------------------------------------------------------------------------------------ | ---- | ------ | | [797. 所有可能的路径](https://leetcode.cn/problems/all-paths-from-source-to-target/) | 💛 | ❌ | #### 环检测及拓扑排序算法 -| 题目 | 难度 | 掌握度 | -| :----------------------------------------------------------- | ---- | ------ | -| [207. 课程表](https://leetcode.cn/problems/course-schedule/) | 💛 | | -| [210. 课程表 II](https://leetcode.cn/problems/course-schedule-ii/) | 💛 | | +| 题目 | 难度 | 掌握度 | +| :----------------------------------------------------------------- | ---- | ------ | +| [207. 课程表](https://leetcode.cn/problems/course-schedule/) | 💛 | ❌ | +| [210. 课程表 II](https://leetcode.cn/problems/course-schedule-ii/) | 💛 | ❌ | #### 二分图判定算法 -| 题目 | 掌握度 | -| :----------------------------------------------------------- | ------ | -| [785. 判断二分图](https://leetcode.cn/problems/is-graph-bipartite/) | ❌ | -| [886. 可能的二分法](https://leetcode.cn/problems/possible-bipartition/) | ❌ | -| [剑指 Offer II 106. 二分图](https://leetcode.cn/problems/vEAB3K/) | ❌ | +| 题目 | 难度 | 掌握度 | +| :---------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | +| [785. 判断二分图](https://leetcode.cn/problems/is-graph-bipartite/)
[LCR 106. 判断二分图](https://leetcode.cn/problems/vEAB3K/) | 💛 | ❌ | +| [886. 可能的二分法](https://leetcode.cn/problems/possible-bipartition/) | 💛 | ❌ | + +#### 并查集算法 + +| 题目 | 难度 | 掌握度 | +| :-------------------------------------------------------------------------------------------- | ---- | ------ | +| [130. 被围绕的区域](https://leetcode.cn/problems/surrounded-regions/) | 💛 | ❌ | +| [684. 冗余连接](https://leetcode.cn/problems/redundant-connection/) | 💛 | ❗ | +| [990. 等式方程的可满足性](https://leetcode.cn/problems/satisfiability-of-equality-equations/) | 💛 | ❗ | + +#### Dijkstra 算法 + +| 题目 | 难度 | 掌握度 | +| :--------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | +| [743. 网络延迟时间](https://leetcode.cn/problems/network-delay-time/) | 💛 | ❌ | +| [1631. 最小体力消耗路径](https://leetcode.cn/problems/path-with-minimum-effort/) | 💛 | ❌ | +| [1514. 概率最大的路径](https://leetcode.cn/problems/path-with-maximum-probability/) | 💛 | ❌ | +| [787. K 站中转内最便宜的航班](https://leetcode.cn/problems/cheapest-flights-within-k-stops/) | 💛 | ❌ | +| [1368. 使网格图至少有一条有效路径的最小代价](https://leetcode.cn/problems/minimum-cost-to-make-at-least-one-valid-path-in-a-grid/) | ❤️ | ❌ | ### DFS @@ -455,11 +487,16 @@ | [91. 解码方法](https://leetcode.cn/problems/decode-ways/) | 💛 | | | [983. 最低票价](https://leetcode.cn/problems/minimum-cost-for-tickets/) | 💛 | | | [790. 多米诺和托米诺平铺](https://leetcode.cn/problems/domino-and-tromino-tiling/) | 💛 | | +| [264. 丑数 II](https://leetcode.cn/problems/ugly-number-ii/) | 💛 | ❌ | +| [1201. 丑数 III](https://leetcode.cn/problems/ugly-number-iii/) | 💛 | ❌ | +| [313. 超级丑数](https://leetcode.cn/problems/super-ugly-number/) | 💛 | ❌ | #### 矩阵 | 题目 | 难度 | 掌握度 | | ----------------------------------------------------------------------------- | :--: | :----: | +| [118. 杨辉三角](https://leetcode.cn/problems/pascals-triangle/) | 💚 | ✔️ | +| [119. 杨辉三角 II](https://leetcode.cn/problems/pascals-triangle-ii/) | 💚 | ✔️ | | [62. 不同路径](https://leetcode.cn/problems/unique-paths/) | 💛 | ✔️ | | [63. 不同路径 II](https://leetcode.cn/problems/unique-paths-ii/) | 💛 | ✔️ | | [64. 最小路径和](https://leetcode.cn/problems/minimum-path-sum/) | 💛 | ✔️ | @@ -506,10 +543,11 @@ ### 贪心算法 -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------- | ---- | ------ | -| [55. 跳跃游戏](https://leetcode.cn/problems/jump-game/) | 💛 | | -| [45. 跳跃游戏 II](https://leetcode.cn/problems/jump-game-ii/) | 💛 | | +| 题目 | 难度 | 掌握度 | +| -------------------------------------------------------------- | ---- | ------ | +| [561. 数组拆分](https://leetcode.cn/problems/array-partition/) | 💚 | ❌ | +| [55. 跳跃游戏](https://leetcode.cn/problems/jump-game/) | 💛 | | +| [45. 跳跃游戏 II](https://leetcode.cn/problems/jump-game-ii/) | 💛 | | ### 分治算法 @@ -517,22 +555,29 @@ | --------------------------------------------------------------------------- | ------ | | [23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/) | ✔️ | +### 数学 + +| 题目 | 难度 | 掌握度 | +| ------------------------------------------------------ | ---- | ------ | +| [66. 加一](https://leetcode.cn/problems/plus-one/) | 💚 | ✔️ | +| [263. 丑数](https://leetcode.cn/problems/ugly-number/) | 💚 | ✔️ | + ## 📚 资料 - **书籍** - - 刷题必备 + - **刷题必备** - 《剑指 offer》 - 《编程之美》 - 《编程之法:面试和算法心得》 - 《算法谜题》 都是思维题 - - 基础 + - **基础** - [《编程珠玑(第 2 版)》](https://www.amazon.cn/gp/product/B00SFZH0DC/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00SFZH0DC&linkCode=as2&tag=vastwork-23) - [《编程珠玑(续)》](https://www.amazon.cn/gp/product/B0150BMQDM/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B0150BMQDM&linkCode=as2&tag=vastwork-23) - [《数据结构与算法分析 : C++描述(第 4 版)》](https://www.amazon.cn/gp/product/B01LDG2DSG/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B01LDG2DSG&linkCode=as2&tag=vastwork-23) - [《数据结构与算法分析 : C 语言描述(第 2 版)》](https://www.amazon.cn/gp/product/B002WC7NGS/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B002WC7NGS&linkCode=as2&tag=vastwork-23) - [《数据结构与算法分析 : Java 语言描述(第 2 版)》](https://www.amazon.cn/gp/product/B01CNP0CG6/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B01CNP0CG6&linkCode=as2&tag=vastwork-23) - [《算法(第 4 版)》](https://www.amazon.cn/gp/product/B009OCFQ0O/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B009OCFQ0O&linkCode=as2&tag=vastwork-23) - - 算法设计 + - **算法设计** - [《算法设计与分析基础(第 3 版)》](https://www.amazon.cn/gp/product/B00S4HCQUI/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00S4HCQUI&linkCode=as2&tag=vastwork-23) - 《Algorithm Design Manual》 - 算法设计手册 红皮书 - [《算法导论》](https://www.amazon.cn/gp/product/B00AK7BYJY/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00AK7BYJY&linkCode=as2&tag=vastwork-23) - 是一本对算法介绍比较全面的经典书籍 diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/ArrayDemo.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/ArrayDemo.java deleted file mode 100644 index 62c1db5..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/ArrayDemo.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.github.dunwu.algorithm.array; - -/** - * @author Zhang Peng - * @since 2020-01-20 - */ -public class ArrayDemo { - - public static int maxSubArray(int[] nums) { - int len = nums.length; - - int maxSum = nums[0]; - for (int i = 1; i < len; i++) { - if (nums[i - 1] > 0) nums[i] += nums[i - 1]; - maxSum = Math.max(nums[i], maxSum); - } - return maxSum; - } - - public static void main(String[] args) { - int max = maxSubArray(new int[] { -2, 1, -3, 4, -1, 2, 1, -5, 4 }); - System.out.println("max = " + max); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/base/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/base/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.java" new file mode 100644 index 0000000..7e1cb56 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/base/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.java" @@ -0,0 +1,37 @@ +package io.github.dunwu.algorithm.array.base; + +import org.junit.jupiter.api.Assertions; + +/** + * 485. 最大连续 1 的个数 + * + * @author Zhang Peng + * @since 2018-11-05 + */ +public class 最大连续1的个数 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(3, s.findMaxConsecutiveOnes(new int[] { 1, 1, 0, 1, 1, 1 })); + Assertions.assertEquals(2, s.findMaxConsecutiveOnes(new int[] { 1, 0, 1, 1, 0, 1 })); + } + + static class Solution { + + public int findMaxConsecutiveOnes(int[] nums) { + int max = 0; + int cnt = 0; + for (int num : nums) { + if (num == 1) { + cnt++; + max = Math.max(max, cnt); + } else { + cnt = 0; + } + } + return max; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/base/\350\207\263\345\260\221\346\230\257\345\205\266\344\273\226\346\225\260\345\255\227\344\270\244\345\200\215\347\232\204\346\234\200\345\244\247\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/base/\350\207\263\345\260\221\346\230\257\345\205\266\344\273\226\346\225\260\345\255\227\344\270\244\345\200\215\347\232\204\346\234\200\345\244\247\346\225\260.java" new file mode 100644 index 0000000..cd5ceb9 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/base/\350\207\263\345\260\221\346\230\257\345\205\266\344\273\226\346\225\260\345\255\227\344\270\244\345\200\215\347\232\204\346\234\200\345\244\247\346\225\260.java" @@ -0,0 +1,37 @@ +package io.github.dunwu.algorithm.array.base; + +import org.junit.jupiter.api.Assertions; + +/** + * 747. 至少是其他数字两倍的最大数 + * + * @author Zhang Peng + * @since 2018-11-04 + */ +public class 至少是其他数字两倍的最大数 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(1, s.dominantIndex(new int[] { 3, 6, 1, 0 })); + Assertions.assertEquals(-1, s.dominantIndex(new int[] { 1, 2, 3, 4 })); + Assertions.assertEquals(0, s.dominantIndex(new int[] { 1, 0 })); + } + + static class Solution { + + public int dominantIndex(int[] nums) { + int second = -1, max = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[i] > nums[max]) { + second = max; + max = i; + } else if (second == -1 || nums[i] > nums[second]) { + second = i; + } + } + return nums[max] >= 2 * nums[second] ? max : -1; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" new file mode 100644 index 0000000..bdc2bb9 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" @@ -0,0 +1,41 @@ +package io.github.dunwu.algorithm.array.bsearch; + +import org.junit.jupiter.api.Assertions; + +/** + * 35. 搜索插入位置 + * + * @author Zhang Peng + * @since 2020-07-29 + */ +public class 搜索插入位置 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(0, s.searchInsert(new int[] { 1 }, 1)); + Assertions.assertEquals(2, s.searchInsert(new int[] { 1, 3, 5, 6 }, 5)); + Assertions.assertEquals(1, s.searchInsert(new int[] { 1, 3, 5, 6 }, 2)); + Assertions.assertEquals(4, s.searchInsert(new int[] { 1, 3, 5, 6 }, 7)); + Assertions.assertEquals(0, s.searchInsert(new int[] { 1, 3, 5, 6 }, 0)); + } + + static class Solution { + + public int searchInsert(int[] nums, int target) { + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + if (nums[mid] == target) { + return mid; + } else if (nums[mid] < target) { + left = mid + 1; + } else if (nums[mid] > target) { + right = mid - 1; + } + } + return left; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\250\241\346\213\237ArrayList1.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/demo/\346\250\241\346\213\237ArrayList1.java" similarity index 98% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\250\241\346\213\237ArrayList1.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/demo/\346\250\241\346\213\237ArrayList1.java" index 841235f..1787652 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\250\241\346\213\237ArrayList1.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/demo/\346\250\241\346\213\237ArrayList1.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.array; +package io.github.dunwu.algorithm.array.demo; import java.util.Arrays; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\250\241\346\213\237ArrayList2.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/demo/\346\250\241\346\213\237ArrayList2.java" similarity index 99% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\250\241\346\213\237ArrayList2.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/demo/\346\250\241\346\213\237ArrayList2.java" index 22250c6..d38d8d9 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\250\241\346\213\237ArrayList2.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/demo/\346\250\241\346\213\237ArrayList2.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.array; +package io.github.dunwu.algorithm.array.demo; public class 模拟ArrayList2 { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215.java" index 1e6eff6..2a10b4a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215.java" @@ -26,18 +26,15 @@ public static void main(String[] args) { static class Solution { public String reverseWords(String s) { - String[] strs = s.split(" "); + String[] arr = s.trim().split(" "); StringBuilder sb = new StringBuilder(); - for (int i = strs.length - 1; i >= 0; i--) { - if (strs[i].equals("")) { + for (int i = arr.length - 1; i >= 0; i--) { + if (arr[i].equals("")) { continue; } - sb.append(strs[i]).append(" "); + sb.append(arr[i]).append(" "); } - if (sb.lastIndexOf(" ") == sb.length() - 1) { - return sb.substring(0, sb.length() - 1); - } - return sb.toString(); + return sb.toString().trim(); } } @@ -48,19 +45,18 @@ static class Solution2 { public String reverseWords(String s) { // 删除首尾空格 s = s.trim(); - int i = s.length() - 1, j = i; + int l = s.length() - 1, r = l; StringBuilder res = new StringBuilder(); - while (i >= 0) { - // 搜索首个空格 - while (i >= 0 && s.charAt(i) != ' ') { i--; } + while (l >= 0) { + // 左指针偏移,直到遇到空格 + while (l >= 0 && s.charAt(l) != ' ') { l--; } // 添加单词 - res.append(s.substring(i + 1, j + 1)).append(" "); - // 跳过单词间空格 - while (i >= 0 && s.charAt(i) == ' ') { i--; } - // j 指向下个单词的尾字符 - j = i; + res.append(s.substring(l + 1, r + 1)).append(' '); + // 左指针偏移,直到遇到非空格 + while (l >= 0 && s.charAt(l) == ' ') { l--; } + // 右指针对齐左指针 + r = l; } - // 转化为字符串并返回 return res.toString().trim(); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" new file mode 100644 index 0000000..d39a10e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" @@ -0,0 +1,66 @@ +package io.github.dunwu.algorithm.array.matrix; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 498. 对角线遍历 + * + * @author Zhang Peng + * @since 2018-11-04 + */ +public class 对角线遍历 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + int[][] input = { { 1, 2 }, { 3, 4 } }; + int[] expect = { 1, 2, 3, 4 }; + + int[][] input2 = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + int[] expect2 = { 1, 2, 4, 7, 5, 3, 6, 8, 9 }; + + int[][] input3 = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }, { 13, 14, 15, 16 } }; + int[] expect3 = { 1, 2, 5, 9, 6, 3, 4, 7, 10, 13, 14, 11, 8, 12, 15, 16 }; + + Assertions.assertArrayEquals(expect, s.findDiagonalOrder(input)); + Assertions.assertArrayEquals(expect2, s.findDiagonalOrder(input2)); + Assertions.assertArrayEquals(expect3, s.findDiagonalOrder(input3)); + } + + static class Solution { + + public int[] findDiagonalOrder(int[][] mat) { + + // base case + if (mat == null || mat.length == 0) { return new int[0]; } + + int m = mat.length, n = mat[0].length; + List list = new LinkedList<>(); + for (int step = 0; step <= m + n - 2; step++) { + int min = Math.max(step - (m - 1), 0); + int max = Math.min(step, n - 1); + if (step % 2 == 0) { + for (int i = max; i >= min; i--) { + list.add(mat[i][step - i]); + } + } else { + for (int i = min; i <= max; i++) { + list.add(mat[i][step - i]); + } + } + } + + int[] res = new int[list.size()]; + for (int k = 0; k < list.size(); k++) { + res[k] = list.get(k); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\265.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\265.java" index dc2eee6..e0085df 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\265.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\265.java" @@ -29,8 +29,7 @@ public List spiralOrder(int[][] matrix) { } int m = matrix.length, n = matrix[0].length; - int up = 0, down = m - 1; - int left = 0, right = n - 1; + int up = 0, down = m - 1, left = 0, right = n - 1; List res = new LinkedList<>(); while (res.size() < m * n) { // 向右 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\351\233\266\347\237\251\351\230\265.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\351\233\266\347\237\251\351\230\265.java" new file mode 100644 index 0000000..6c7d535 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\351\233\266\347\237\251\351\230\265.java" @@ -0,0 +1,54 @@ +package io.github.dunwu.algorithm.array.matrix; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 08. 零矩阵 + * + * @author Zhang Peng + * @since 2020-06-05 + */ +public class 零矩阵 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[][] input = { + { 1, 1, 1 }, + { 1, 0, 1 }, + { 1, 1, 1 } + }; + int[][] expect = { + { 1, 0, 1 }, + { 0, 0, 0 }, + { 1, 0, 1 } + }; + s.setZeroes(input); + Assertions.assertArrayEquals(expect, input); + } + + static class Solution { + + public void setZeroes(int[][] matrix) { + int m = matrix.length, n = matrix[0].length; + LinkedList queue = new LinkedList<>(); + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (matrix[i][j] == 0) { + queue.offer(new int[] { i, j }); + } + } + } + + while (!queue.isEmpty()) { + int[] point = queue.poll(); + int x = point[0], y = point[1]; + for (int i = 0; i < n; i++) { matrix[x][i] = 0; } + for (int i = 0; i < m; i++) { matrix[i][y] = 0; } + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" new file mode 100644 index 0000000..c7d8c6b --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" @@ -0,0 +1,66 @@ +package io.github.dunwu.algorithm.array.range; + +import org.junit.jupiter.api.Assertions; + +/** + * 724. 寻找数组的中心索引 + * + * @author Zhang Peng + * @since 2018-11-04 + */ +public class 寻找数组的中心索引 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(3, s.pivotIndex(new int[] { 1, 7, 3, 6, 5, 6 })); + Assertions.assertEquals(-1, s.pivotIndex(new int[] { 1, 2, 3 })); + Assertions.assertEquals(0, s.pivotIndex(new int[] { 2, 1, -1 })); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals(3, s2.pivotIndex(new int[] { 1, 7, 3, 6, 5, 6 })); + Assertions.assertEquals(-1, s2.pivotIndex(new int[] { 1, 2, 3 })); + Assertions.assertEquals(0, s2.pivotIndex(new int[] { 2, 1, -1 })); + } + + static class Solution { + + public int pivotIndex(int[] nums) { + for (int mid = 0; mid < nums.length; mid++) { + int leftSum = 0, rightSum = 0; + for (int i = 0; i < mid; i++) { + leftSum += nums[i]; + } + for (int i = mid + 1; i < nums.length; i++) { + rightSum += nums[i]; + } + if (leftSum == rightSum) { + return mid; + } + } + return -1; + } + + } + + static class Solution2 { + + public int pivotIndex(int[] nums) { + int total = 0; + for (int num : nums) { + total += num; + } + + int leftSum = 0; + for (int i = 0; i < nums.length; i++) { + int rightSum = total - leftSum - nums[i]; + if (leftSum == rightSum) { + return i; + } + leftSum += nums[i]; + } + return -1; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250\345\210\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250\345\210\206.java" new file mode 100644 index 0000000..43dca82 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250\345\210\206.java" @@ -0,0 +1,58 @@ +package io.github.dunwu.algorithm.array.range; + +import org.junit.jupiter.api.Assertions; + +/** + * 1013.将数组分成和相等的三个部分 + * + * @author Zhang Peng + * @since 2020-06-05 + */ +public class 将数组分成和相等的三个部分 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.canThreePartsEqualSum(new int[] { 0, 2, 1, -6, 6, -7, 9, 1, 2, 0, 1 })); + Assertions.assertTrue(s.canThreePartsEqualSum(new int[] { 3, 3, 6, 5, -2, 2, 5, 1, -9, 4 })); + Assertions.assertFalse(s.canThreePartsEqualSum(new int[] { 0, 2, 1, -6, 6, 7, 9, -1, 2, 0, 1 })); + } + + static class Solution { + + public boolean canThreePartsEqualSum(int[] arr) { + int n = arr.length; + NumArray preSum = new NumArray(arr); + for (int i = 1; i < n; i++) { + for (int j = i + 1; j < n; j++) { + int leftSum = preSum.sumRange(0, i - 1); + int midSum = preSum.sumRange(i, j - 1); + int rightSum = preSum.sumRange(j, n - 1); + if (leftSum == midSum && midSum == rightSum) { + return true; + } + } + } + return false; + } + + static class NumArray { + + private final int[] preSum; + + public NumArray(int[] arr) { + preSum = new int[arr.length + 1]; + preSum[0] = 0; + for (int i = 1; i <= arr.length; i++) { + preSum[i] = preSum[i - 1] + arr[i - 1]; + } + } + + public int sumRange(int left, int right) { + return preSum[right + 1] - preSum[left]; + } + + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\211\346\225\260\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\211\346\225\260\344\271\213\345\222\214.java" new file mode 100644 index 0000000..74922f2 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\211\346\225\260\344\271\213\345\222\214.java" @@ -0,0 +1,62 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * + * 三数之和 + * + * @author Zhang Peng + * @since 2020-01-18 + */ +public class 三数之和 { + + public static void main(String[] args) { + Solution s = new Solution(); + List> input = s.threeSum(new int[] { -1, 0, 1, 2, -1, -4 }); + List> expect = new ArrayList<>(); + expect.add(Arrays.asList(-1, -1, 2)); + expect.add(Arrays.asList(-1, 0, 1)); + Assertions.assertArrayEquals(expect.toArray(), input.toArray()); + } + + static class Solution { + + public List> threeSum(int[] nums) { + if (nums == null || nums.length < 3) { return new ArrayList<>(); } + Arrays.sort(nums); + List> res = new ArrayList<>(); + for (int i = 0; i < nums.length; i++) { + // 跳过重复元素 + if (i > 0 && nums[i] == nums[i - 1]) continue; + + // 双指针,目标是找到 nums[l] + nums[r] = -nums[i] + int left = i + 1, right = nums.length - 1; + int target = -nums[i]; + + while (left < right) { + int sum = nums[left] + nums[right]; + if (sum == target) { + res.add(Arrays.asList(nums[i], nums[left], nums[right])); + left++; + right--; + // 跳过重复元素 + while (left < right && nums[left] == nums[left - 1]) left++; + while (left < right && nums[right] == nums[right + 1]) right--; + } else if (sum < target) { + left++; + } else { + right--; + } + } + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" new file mode 100644 index 0000000..812604b --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" @@ -0,0 +1,46 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +/** + * 67. 二进制求和 + * + * @author Zhang Peng + * @date 2025-01-21 + */ +public class 二进制求和 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals("100", s.addBinary("11", "1")); + Assertions.assertEquals("10101", s.addBinary("1010", "1011")); + } + + static class Solution { + + public String addBinary(String a, String b) { + int i = a.length() - 1; + int j = b.length() - 1; + int carry = 0; + StringBuilder sb = new StringBuilder(); + while (i >= 0 || j >= 0) { + int numA = i < 0 ? 0 : a.charAt(i--) - '0'; + int numB = j < 0 ? 0 : b.charAt(j--) - '0'; + int sum = numA + numB + carry; + if (sum > 1) { + carry = 1; + sb.append(sum % 2); + } else { + carry = 0; + sb.append(sum); + } + } + if (carry > 0) { + sb.append(carry); + } + return sb.reverse().toString(); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\220\210\345\271\266\345\214\272\351\227\264.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\220\210\345\271\266\345\214\272\351\227\264.java" new file mode 100644 index 0000000..d424a3e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\220\210\345\271\266\345\214\272\351\227\264.java" @@ -0,0 +1,62 @@ +package io.github.dunwu.algorithm.array.two_pointer; + +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 56. 合并区间 + * + * @author Zhang Peng + * @since 2020-07-29 + */ +public class 合并区间 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + int[][] input = new int[][] { { 1, 4 }, { 2, 3 } }; + int[][] expect = new int[][] { { 1, 4 } }; + Assertions.assertArrayEquals(expect, s.merge(input)); + + int[][] input2 = new int[][] { { 1, 3 }, { 2, 6 }, { 8, 10 }, { 15, 18 } }; + int[][] expect2 = new int[][] { { 1, 6 }, { 8, 10 }, { 15, 18 } }; + Assertions.assertArrayEquals(expect2, s.merge(input2)); + + int[][] input3 = new int[][] { { 1, 4 }, { 4, 5 } }; + int[][] expect3 = new int[][] { { 1, 5 } }; + Assertions.assertArrayEquals(expect3, s.merge(input3)); + } + + static class Solution { + + public int[][] merge(int[][] intervals) { + + // base case + if (intervals == null || intervals.length <= 1) { return intervals; } + + // 先按区间下限排序 + Arrays.sort(intervals, (a, b) -> a[0] - b[0]); + + // 设置双指针,扫描 intervals + List merged = new ArrayList<>(); + for (int[] interval : intervals) { + int l = interval[0], r = interval[1]; + int last = merged.size() - 1; + if (last == -1 || merged.get(last)[1] < l) { + merged.add(new int[] { l, r }); + } else { + l = merged.get(last)[0]; + r = Math.max(merged.get(last)[1], r); + merged.set(last, new int[] { l, r }); + } + } + return merged.toArray(new int[merged.size()][2]); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" index 44ca954..d891982 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" @@ -18,7 +18,7 @@ public static void main(String[] args) { Assertions.assertEquals("bb", s.longestPalindrome("bb")); Solution2 s2 = new Solution2(); - Assertions.assertEquals("bab", s2.longestPalindrome("babad")); + Assertions.assertEquals("aba", s2.longestPalindrome("babad")); Assertions.assertEquals("bb", s2.longestPalindrome("cbbd")); Assertions.assertEquals("a", s2.longestPalindrome("a")); Assertions.assertEquals("bb", s2.longestPalindrome("bb")); @@ -64,19 +64,22 @@ public String longestPalindrome(String s) { for (int i = 0; i < s.length(); i++) { String s1 = palindrome(s, i, i); String s2 = palindrome(s, i, i + 1); - res = s1.length() > res.length() ? s1 : res; - res = s2.length() > res.length() ? s2 : res; + res = res.length() > s1.length() ? res : s1; + res = res.length() > s2.length() ? res : s2; } return res; } - public String palindrome(String s, int i, int j) { - if (i < 0 || j >= s.length() || i > j) return ""; - while (i >= 0 && j < s.length() && s.charAt(i) == s.charAt(j)) { - i--; - j++; + public String palindrome(String s, int l, int r) { + // 防止索引越界 + while (l >= 0 && r < s.length() + && s.charAt(l) == s.charAt(r)) { + // 双指针向两边展开 + l--; + r++; } - return s.substring(i + 1, j); + // 此时 s[l+1..r-1] 就是最长回文串 + return s.substring(l + 1, r); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" index 4914245..6a6d857 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" @@ -41,6 +41,7 @@ public int numSubarrayProductLessThanK(int[] nums, int k) { // 所以我们需要把 [3], [2,3], [1,2,3] 这 right - left 个子数组都加上 count += right - left; } + return count; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2402.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2402.java" index 067485a..2e6b279 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2402.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2402.java" @@ -3,7 +3,6 @@ import org.junit.jupiter.api.Assertions; import java.util.HashSet; -import java.util.Set; /** * 219. 存在重复元素 II @@ -24,17 +23,22 @@ public static void main(String[] args) { static class Solution { public boolean containsNearbyDuplicate(int[] nums, int k) { + + // base case + if (nums == null || nums.length < 2) { return false; } + int left = 0, right = 0; - Set set = new HashSet<>(); + HashSet window = new HashSet<>(); + // 滑动窗口算法框架,维护一个大小为 k 的窗口 while (right < nums.length) { - if (set.contains(nums[right])) { - return true; - } - set.add(nums[right]); + // 扩大窗口 + if (window.contains(nums[right])) { return true; } + window.add(nums[right]); right++; if (right - left > k) { - set.remove(nums[left]); + // 当窗口的大小大于 k 时,缩小窗口 + window.remove(nums[left]); left++; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" index aeef632..343894b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" @@ -20,23 +20,33 @@ public static void main(String[] args) { static class Solution { public int characterReplacement(String s, int k) { - - int res = 0; - int windowMaxCount = 0; int left = 0, right = 0; - int[] windowCount = new int[26]; + // 统计窗口中每个字符的出现次数 + int[] charCnt = new int[26]; + // 记录窗口中字符的最多重复次数 + // 记录这个值的意义在于,最划算的替换方法肯定是把其他字符替换成出现次数最多的那个字符 + int windowMaxCnt = 0; + // 记录结果长度 + int res = 0; + + // 开始滑动窗口模板 while (right < s.length()) { + // 扩大窗口 int c = s.charAt(right) - 'A'; - windowCount[c]++; - windowMaxCount = Math.max(windowMaxCount, windowCount[c]); + charCnt[c]++; + windowMaxCnt = Math.max(windowMaxCnt, charCnt[c]); right++; - while (right - left - windowMaxCount > k) { + // 这个 while 换成 if 也可以 + while (right - left - windowMaxCnt > k) { + // 杂牌字符数量 right - left - windowMaxCnt 多于 k + // 此时,k 次替换已经无法把窗口内的字符都替换成相同字符了 + // 必须缩小窗口 int d = s.charAt(left) - 'A'; - windowCount[d]--; + charCnt[d]--; left++; } - + // 经过收缩后,此时一定是一个合法的窗口 res = Math.max(res, right - left); } return res; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\211\346\225\260\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\211\346\225\260\344\271\213\345\222\214.java" deleted file mode 100644 index 5219810..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\211\346\225\260\344\271\213\345\222\214.java" +++ /dev/null @@ -1,65 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。 - *

- * 注意:答案中不可以包含重复的三元组。 - *

- * 示例:给定数组 nums = [-1, 0, 1, 2, -1, -4], - *

- * 满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ] - * - * @author Zhang Peng - * @see 三数之和 - * @since 2020-01-18 - */ -public class 三数之和 { - - public static List> threeSum(int[] nums) { - List> list = new ArrayList<>(); - - if (nums == null || nums.length < 3) return list; - - int len = nums.length; - Arrays.sort(nums); - - for (int i = 0; i < len; i++) { - if (nums[i] > 0) break; - - // 去重 - if (i > 0 && nums[i] == nums[i - 1]) continue; - - int L = i + 1; - int R = len - 1; - while (L < R) { - int sum = nums[i] + nums[L] + nums[R]; - if (sum == 0) { - list.add(Arrays.asList(nums[i], nums[L], nums[R])); - while (L < R && nums[L] == nums[L + 1]) L++; - while (L < R && nums[R] == nums[R - 1]) R--; - L++; - R--; - } else if (sum < 0) { - L++; - } else if (sum > 0) { - R--; - } - } - } - - return list; - } - - public static void main(String[] args) { - List> list = threeSum(new int[] { -1, 0, 1, 2, -1, -4 }); - Assertions.assertEquals(Arrays.asList(-1, 0, 1), list.get(1)); - Assertions.assertEquals(Arrays.asList(-1, -1, 2), list.get(0)); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" deleted file mode 100644 index dfbaf02..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260I.java" +++ /dev/null @@ -1,27 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 263. 丑数 - * - * @author Zhang Peng - * @date 2025-01-24 - */ -public class 丑数I { - - public static void main(String[] args) { - Assertions.assertTrue(isUgly(6)); - Assertions.assertTrue(isUgly(1)); - Assertions.assertFalse(isUgly(14)); - } - - public static boolean isUgly(int n) { - while (n <= 0) return false; - while (n % 2 == 0) n /= 2; - while (n % 3 == 0) n /= 3; - while (n % 5 == 0) n /= 5; - return n == 1; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260II.java" deleted file mode 100644 index 84b657f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260II.java" +++ /dev/null @@ -1,51 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 264. 丑数II - * - * @author Zhang Peng - * @date 2025-01-24 - */ -public class 丑数II { - - public static void main(String[] args) { - Assertions.assertEquals(12, nthUglyNumber(10)); - Assertions.assertEquals(1, nthUglyNumber(1)); - } - - public static int nthUglyNumber(int n) { - if (n == 1) { - return 1; - } - - // 可以理解为三个指向有序链表头结点的指针 - int p2 = 1, p3 = 1, p5 = 1; - // 可以理解为三个有序链表的头节点的值 - int product2 = 1, product3 = 1, product5 = 1; - // 可以理解为最终合并的有序链表(结果链表) - int[] ugly = new int[n + 1]; - // 可以理解为结果链表上的指针 - int u = 1; - - while (u <= n) { - int min = Math.min(product2, Math.min(product3, product5)); - ugly[u++] = min; - if (min == product2) { - product2 = 2 * ugly[p2]; - p2++; - } - if (min == product3) { - product3 = 3 * ugly[p3]; - p3++; - } - if (min == product5) { - product5 = 5 * ugly[p5]; - p5++; - } - } - return ugly[n]; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260III.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260III.java" deleted file mode 100644 index 49101b6..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\221\346\225\260III.java" +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 264. 丑数II - * - * @author Zhang Peng - * @date 2025-01-24 - */ -public class 丑数III { - - public static void main(String[] args) { - Assertions.assertEquals(4, nthUglyNumber(3, 2, 3, 5)); - Assertions.assertEquals(6, nthUglyNumber(4, 2, 3, 4)); - Assertions.assertEquals(10, nthUglyNumber(5, 2, 11, 13)); - Assertions.assertEquals(1999999984, nthUglyNumber(1000000000, 2, 217983653, 336916467)); - } - - public static int nthUglyNumber(int n, int a, int b, int c) { - int p = 1; - int vA = a, vB = b, vC = c; - long min = Integer.MAX_VALUE; - while (p <= n) { - min = Math.min(vA, Math.min(vB, vC)); - if (min == vA) { - vA += a; - } - if (min == vB) { - vB += b; - } - if (min == vC) { - vC += c; - } - p++; - } - return (int) min; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204.java" deleted file mode 100644 index bdc6751..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\270\244\346\225\260\344\271\213\345\222\214II_\350\276\223\345\205\245\346\234\211\345\272\217\346\225\260\347\273\204.java" +++ /dev/null @@ -1,34 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * LCR 006. 两数之和 II - 输入有序数组 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 两数之和II_输入有序数组 { - - public static void main(String[] args) { - Assertions.assertArrayEquals(new int[] { 1, 3 }, twoSum(new int[] { 1, 2, 4, 6, 10 }, 8)); - Assertions.assertArrayEquals(new int[] { 0, 2 }, twoSum(new int[] { 2, 3, 4 }, 6)); - Assertions.assertArrayEquals(new int[] { 0, 1 }, twoSum(new int[] { -1, 0 }, -1)); - } - - public static int[] twoSum(int[] numbers, int target) { - int left = 0, right = numbers.length - 1; - while (left < right) { - int sum = numbers[left] + numbers[right]; - if (sum == target) { - return new int[] { left, right }; - } else if (sum < target) { - left++; - } else { - right--; - } - } - return new int[0]; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" deleted file mode 100644 index 95857bf..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" +++ /dev/null @@ -1,46 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 67. 二进制求和 - * - * @author Zhang Peng - * @date 2025-01-21 - */ -public class 二进制求和 { - - public static void main(String[] args) { - Assertions.assertEquals("100", addBinary("11", "1")); - Assertions.assertEquals("10101", addBinary("1010", "1011")); - } - - public static String addBinary(String a, String b) { - - if (a == null || a.length() == 0) return b; - if (b == null || b.length() == 0) return a; - - char[] arrA = a.toCharArray(); - char[] arrB = b.toCharArray(); - StringBuilder sb = new StringBuilder(); - int carry = 0; - int i = arrA.length - 1, j = arrB.length - 1; - while (i >= 0 || j >= 0) { - int value = carry; - if (i >= 0) { - value += arrA[i--] - '0'; - } - if (j >= 0) { - value += arrB[j--] - '0'; - } - carry = value / 2; - value = value % 2; - sb.append(value); - } - if (carry != 0) { - sb.append(carry); - } - return sb.reverse().toString(); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\212\240\344\270\200.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\212\240\344\270\200.java" deleted file mode 100644 index dba8a10..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\212\240\344\270\200.java" +++ /dev/null @@ -1,62 +0,0 @@ -package io.github.dunwu.algorithm.array; - -// 【加一】 - -// -// 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 -// -// 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。 -// -// 你可以假设除了整数 0 之外,这个整数不会以零开头。 -// -// 示例 1: -// -// 输入: [1,2,3] -// 输出: [1,2,4] -// 解释: 输入数组表示数字 123。 -// 示例 2: -// -// 输入: [4,3,2,1] -// 输出: [4,3,2,2] -// 解释: 输入数组表示数字 4321。 - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 加一 { - - public static void main(String[] args) { - int[] nums1 = { 1, 2, 3 }; - int[] nums2 = { 4, 3, 2, 1 }; - int[] nums3 = { 9, 9, 9, 9 }; - - int[] expected1 = { 1, 2, 4 }; - int[] expected2 = { 4, 3, 2, 2 }; - int[] expected3 = { 1, 0, 0, 0, 0 }; - - Assertions.assertArrayEquals(expected1, 加一.plusOne(nums1)); - Assertions.assertArrayEquals(expected2, 加一.plusOne(nums2)); - Assertions.assertArrayEquals(expected3, 加一.plusOne(nums3)); - } - - public static int[] plusOne(int[] digits) { - int n = digits.length; - for (int i = n - 1; i >= 0; i--) { - if (digits[i] < 9) { - digits[i]++; - return digits; - } - - digits[i] = 0; - } - - int[] newNumber = new int[n + 1]; - newNumber[0] = 1; - - return newNumber; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\345\214\272\351\227\264.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\345\214\272\351\227\264.java" deleted file mode 100644 index 4e64e04..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\220\210\345\271\266\345\214\272\351\227\264.java" +++ /dev/null @@ -1,68 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * @author Zhang Peng - * @since 2020-07-29 - */ -public class 合并区间 { - - public static void main(String[] args) { - int[][] array = new int[][] { - { 1, 4 }, { 2, 3 } - }; - int[][] exprect = new int[][] { - { 1, 4 } - }; - Assertions.assertArrayEquals(exprect, merge(array)); - - // int[][] array = new int[][] { - // { 1, 3 }, { 2, 6 }, { 8, 10 }, { 15, 18 } - // }; - // int[][] exprect = new int[][] { - // { 1, 6 }, { 8, 10 }, { 15, 18 } - // }; - // Assertions.assertArrayEquals(exprect, merge(array)); - - int[][] array2 = new int[][] { - { 1, 4 }, { 4, 5 } - }; - int[][] exprect2 = new int[][] { - { 1, 5 } - }; - Assertions.assertArrayEquals(exprect2, merge(array2)); - } - - public static int[][] merge(int[][] intervals) { - Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]); - - int len = intervals.length; - int[][] res = new int[len][2]; - int cnt = 0; - for (int[] interval : intervals) { - boolean merged = false; - for (int i = 0; i < cnt; i++) { - if (interval[0] >= res[i][0] && interval[1] <= res[i][1]) { - merged = true; - continue; - } - if (interval[0] <= res[i][1]) { - if (interval[1] >= res[i][1]) { - res[i][1] = interval[1]; - merged = true; - continue; - } - } - } - if (!merged) { - res[cnt] = Arrays.copyOf(interval, 2); - cnt++; - } - } - return Arrays.copyOf(res, cnt); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\346\225\260\345\255\227I.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\346\225\260\345\255\227I.java" deleted file mode 100644 index d3c4f6c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\346\225\260\345\255\227I.java" +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 在排序数组中查找数字I { - - public static void main(String[] args) { - Assertions.assertEquals(2, count(8, new Integer[] { 7, 8, 5, 10, 7, 8 })); - Assertions.assertEquals(0, count(6, new Integer[] { 5, 7, 7, 8, 8, 10 })); - Assertions.assertEquals(2, count("abc", new String[] { "abc", "xyz", "lmn", "abc" })); - } - - /** - * 题目:面试题53 - I. - * 在排序数组中查找数字I - *

- * 统计一个元素在数组中出现的次数。 - */ - public static int count(T target, T[] array) { - Arrays.sort(array); - - int count = 0; - for (T i : array) { - if (target.equals(i)) { - count++; - continue; - } - - if (count != 0) { break; } - } - return count; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" deleted file mode 100644 index eb648a8..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" +++ /dev/null @@ -1,125 +0,0 @@ -package io.github.dunwu.algorithm.array; - -// 【对角线遍历】 -// -// 给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示。 -// -// 示例: -// -// 输入: -// [ -// [ 1, 2, 3 ], -// [ 4, 5, 6 ], -// [ 7, 8, 9 ] -// ] -// -// 输出: [1,2,4,7,5,3,6,8,9] -// -// 说明: -// -// 给定矩阵中的元素总数不会超过 100000 。 - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 对角线遍历 { - - public static void main(String[] args) { - - int[][] matrix = { { 1, 2 }, { 3, 4 } }; - int[] expected = { 1, 2, 3, 4 }; - - int[][] matrix2 = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; - int[] expected2 = { 1, 2, 4, 7, 5, 3, 6, 8, 9 }; - - int[][] matrix3 = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }, { 13, 14, 15, 16 } }; - int[] expected3 = { 1, 2, 5, 9, 6, 3, 4, 7, 10, 13, 14, 11, 8, 12, 15, 16 }; - - Assertions.assertArrayEquals(expected, 对角线遍历.findDiagonalOrder(matrix)); - Assertions.assertArrayEquals(expected2, 对角线遍历.findDiagonalOrder(matrix2)); - Assertions.assertArrayEquals(expected3, 对角线遍历.findDiagonalOrder(matrix3)); - } - - public static int[] findDiagonalOrder(int[][] matrix) { - if (matrix.length == 0) { - return new int[0]; - } - - int x = 0, y = 0; - final int M = matrix.length; - final int N = matrix[0].length; - int[] arr = new int[M * N]; - for (int i = 0; i < arr.length; i++) { - arr[i] = matrix[x][y]; - if ((x + y) % 2 == 0) { - if (y == N - 1) { - x++; - } else if (x == 0) { - y++; - } else { - x--; - y++; - } - } else { - if (x == M - 1) { - y++; - } else if (y == 0) { - x++; - } else { - x++; - y--; - } - } - } - return arr; - } - - public static int[] findDiagonalOrder2(int[][] matrix) { - final int UP = 1; - final int DOWN = 2; - final int M = matrix.length; - final int N = matrix[0].length; - int i = 0, j = 0, status = UP; - - int[] result = new int[M * N]; - // System.out.println("========================================"); - // System.out.println(JSONUtil.toJsonStr(matrix)); - // System.out.println("========================================"); - int index = 0; - while (i < M && j < N) { - result[index] = matrix[i][j]; - System.out.println(result[index]); - index++; - if (status == UP) { - if (i == 0 || j == N - 1) { - status = DOWN; - if (j == N - 1) { - i++; - } else { - j++; - } - } else { - i--; - j++; - } - } else { - if (j == 0 || i == M - 1) { - status = UP; - if (i == M - 1) { - j++; - } else { - i++; - } - } else { - i++; - j--; - } - } - } - return result; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" deleted file mode 100644 index a6d10be..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" +++ /dev/null @@ -1,101 +0,0 @@ -// 724. 寻找数组的中心下标 -// -// 给你一个整数数组nums ,请计算数组的 中心下标 。 -// -// 数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。 -// -// 如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。 -// -// 如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。 -// -// -// -// 示例 1: -// -// 输入:nums = [1, 7, 3, 6, 5, 6] -// 输出:3 -// 解释: -// 中心下标是 3 。 -// 左侧数之和 sum = nums[0] + nums[1] + nums[2] = 1 + 7 + 3 = 11 , -// 右侧数之和 sum = nums[4] + nums[5] = 5 + 6 = 11 ,二者相等。 -// 示例 2: -// -// 输入:nums = [1, 2, 3] -// 输出:-1 -// 解释: -// 数组中不存在满足此条件的中心下标。 -// 示例 3: -// -// 输入:nums = [2, 1, -1] -// 输出:0 -// 解释: -// 中心下标是 0 。 -// 左侧数之和 sum = 0 ,(下标 0 左侧不存在元素), -// 右侧数之和 sum = nums[1] + nums[2] = 1 + -1 = 0 。 -// -// 提示: -// -// 1 <= nums.length <= 104 -// -1000 <= nums[i] <= 1000 -// -// 链接:https://leetcode-cn.com/problems/find-pivot-index - -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * 724. 寻找数组的中心索引 - * - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 寻找数组的中心索引 { - - public static void main(String[] args) { - Assertions.assertEquals(3, pivotIndex(new int[] { 1, 7, 3, 6, 5, 6 })); - Assertions.assertEquals(-1, pivotIndex(new int[] { 1, 2, 3 })); - Assertions.assertEquals(0, pivotIndex(new int[] { 2, 1, -1 })); - - Assertions.assertEquals(3, pivotIndex2(new int[] { 1, 7, 3, 6, 5, 6 })); - Assertions.assertEquals(-1, pivotIndex2(new int[] { 1, 2, 3 })); - Assertions.assertEquals(0, pivotIndex2(new int[] { 2, 1, -1 })); - } - - public static int pivotIndex(int[] nums) { - int sum = 0; - int total = Arrays.stream(nums).sum(); - for (int pos = 0; pos < nums.length; pos++) { - if (sum * 2 + nums[pos] == total) { - return pos; - } - sum += nums[pos]; - } - return -1; - } - - public static int pivotIndex2(int[] nums) { - for (int pos = 0; pos < nums.length; pos++) { - - // pos 左侧所有元素累加 - int leftSum = 0; - for (int left = 0; left < pos; left++) { - leftSum += nums[left]; - } - - // pos 右侧所有元素累加 - int rightSum = 0; - for (int right = nums.length - 1; right > pos; right--) { - rightSum += nums[right]; - } - - if (leftSum == rightSum) { - return pos; - } - } - return -1; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250\345\210\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250\345\210\206.java" deleted file mode 100644 index 941ac0f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250\345\210\206.java" +++ /dev/null @@ -1,30 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 将数组分成和相等的三个部分 { - - public static void main(String[] args) { - Assertions.assertTrue(canThreePartsEqualSum(new int[] { 0, 2, 1, -6, 6, -7, 9, 1, 2, 0, 1 })); - Assertions.assertTrue(canThreePartsEqualSum(new int[] { 3, 3, 6, 5, -2, 2, 5, 1, -9, 4 })); - Assertions.assertFalse(canThreePartsEqualSum(new int[] { 0, 2, 1, -6, 6, 7, 9, -1, 2, 0, 1 })); - } - - /** - * 题目:1013. - * 将数组分成和相等的三个部分 - *

- * 给你一个整数数组 A,只有可以将其划分为三个和相等的非空部分时才返回 true,否则返回 false。 - *

- * 形式上,如果可以找出索引 i+1 < j 且满足 (A[0] + A[1] + ... + A[i] == A[i+1] + A[i+2] + ... + A[j-1] == A[j] + A[j-1] + ... + - * A[A.length - 1]) 就可以将数组三等分。 - */ - public static boolean canThreePartsEqualSum(int[] array) { - return false; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" deleted file mode 100644 index 193d6f5..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" +++ /dev/null @@ -1,69 +0,0 @@ -// 35. 搜索插入位置 -// -// 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 -// -// 请必须使用时间复杂度为 O(log n) 的算法。 -// -// -// -// 示例 1: -// -// 输入: nums = [1,3,5,6], target = 5 -// 输出: 2 -// 示例 2: -// -// 输入: nums = [1,3,5,6], target = 2 -// 输出: 1 -// 示例 3: -// -// 输入: nums = [1,3,5,6], target = 7 -// 输出: 4 -// 示例 4: -// -// 输入: nums = [1,3,5,6], target = 0 -// 输出: 0 -// 示例 5: -// -// 输入: nums = [1], target = 0 -// 输出: 0 -// -// -// 提示: -// -// 1 <= nums.length <= 104 -// -104 <= nums[i] <= 104 -// nums 为无重复元素的升序排列数组 -// -104 <= target <= 104 -// -// 来源:LeetCode(LeetCode) -// 链接:https://leetcode-cn.com/problems/search-insert-position - -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @see 搜索插入位置 - * @since 2020-07-29 - */ -public class 搜索插入位置 { - - public static void main(String[] args) { - Assertions.assertEquals(0, searchInsert(new int[] { 1 }, 1)); - Assertions.assertEquals(2, searchInsert(new int[] { 1, 3, 5, 6 }, 5)); - Assertions.assertEquals(1, searchInsert(new int[] { 1, 3, 5, 6 }, 2)); - Assertions.assertEquals(4, searchInsert(new int[] { 1, 3, 5, 6 }, 7)); - Assertions.assertEquals(0, searchInsert(new int[] { 1, 3, 5, 6 }, 0)); - } - - public static int searchInsert(int[] nums, int target) { - for (int pos = 0; pos < nums.length; pos++) { - if (nums[pos] >= target) { - return pos; - } - } - return nums.length; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\225\260\347\273\204\346\213\206\345\210\2061.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\225\260\347\273\204\346\213\206\345\210\2061.java" deleted file mode 100644 index 1f2380b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\225\260\347\273\204\346\213\206\345\210\2061.java" +++ /dev/null @@ -1,42 +0,0 @@ -package io.github.dunwu.algorithm.array; - -// 【数组拆分 I】 -// -// 给定长度为 2n 的数组, 你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), ..., (an, bn) ,使得从1 到 n 的 min(ai, bi) 总和最大。 -// -// 示例 1: -// -// 输入: [1,4,3,2] -// -// 输出: 4 -// 解释: n 等于 2, 最大总和为 4 = min(1, 2) + min(3, 4). -// 提示: -// -// n 是正整数,范围在 [1, 10000]. -// 数组中的元素范围在 [-10000, 10000]. - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 数组拆分1 { - - public static void main(String[] args) { - int[] nums1 = { 1, 4, 3, 2 }; - Assertions.assertEquals(4, 数组拆分1.arrayPairSum(nums1)); - } - - public static int arrayPairSum(int[] nums) { - Arrays.sort(nums); - int result = 0; - for (int i = 0; i < nums.length; i += 2) { - result += nums[i]; - } - return result; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.java" deleted file mode 100644 index 589c482..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.java" +++ /dev/null @@ -1,50 +0,0 @@ -package io.github.dunwu.algorithm.array; - -// 【最大连续1的个数】 - -// -// 给定一个二进制数组, 计算其中最大连续1的个数。 -// -// 示例 1: -// -// 输入: [1,1,0,1,1,1] -// 输出: 3 -// 解释: 开头的两位和最后的三位都是连续1,所以最大连续1的个数是 3. -// 注意: -// -// 输入的数组只包含 0 和1。 -// 输入数组的长度是正整数,且不超过 10,000。 - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 最大连续1的个数 { - - public static void main(String[] args) { - Assertions.assertEquals(3, 最大连续1的个数.findMaxConsecutiveOnes(new int[] { 1, 1, 0, 1, 1, 1 })); - } - - public static int findMaxConsecutiveOnes(int[] nums) { - int max = 0; - int count = 0; - for (int i = 0; i < nums.length; i++) { - if (nums[i] == 1) { - count++; - } else { - if (count > max) { - max = count; - } - count = 0; - } - } - - if (count > max) { - max = count; - } - return max; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\235\250\350\276\211\344\270\211\350\247\222.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\235\250\350\276\211\344\270\211\350\247\222.java" deleted file mode 100644 index 64e887b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\235\250\350\276\211\344\270\211\350\247\222.java" +++ /dev/null @@ -1,81 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -// 【杨辉三角】 -// -// 给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。 -// -// 在杨辉三角中,每个数是它左上方和右上方的数的和。 -// -// 示例: -// -// 输入: 5 -// 输出: -// [ -// [1], -// [1,1], -// [1,2,1], -// [1,3,3,1], -// [1,4,6,4,1] -// ] - -/** - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 杨辉三角 { - - public static void main(String[] args) { - List> lists = 杨辉三角.generate(5); - printPascalsTriangle(lists); - } - - public static List> generate(int numRows) { - List> result = new ArrayList<>(); - - if (numRows <= 0) { - - } else if (numRows == 1) { - result.add(Arrays.asList(1)); - } else if (numRows == 2) { - result.add(Arrays.asList(1)); - result.add(Arrays.asList(1, 1)); - } else { - result.add(Arrays.asList(1)); - result.add(Arrays.asList(1, 1)); - for (int i = 2; i < numRows; i++) { - List current = result.get(i - 1); - List next = new ArrayList<>(); - - for (int j = 0; j <= i; j++) { - if (j == 0 || j == i) { - next.add(1); - } else { - int x = current.get(j - 1); - int y = current.get(j); - next.add(x + y); - } - } - - result.add(next); - } - } - - return result; - } - - static void printPascalsTriangle(List> lists) { - System.out.printf("【%d层杨辉三角】\n", lists.size()); - for (List list : lists) { - for (Integer num : list) { - System.out.print(num + "\t"); - } - System.out.println(); - } - System.out.println(); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\235\250\350\276\211\344\270\211\350\247\2222.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\235\250\350\276\211\344\270\211\350\247\2222.java" deleted file mode 100644 index da70a72..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\235\250\350\276\211\344\270\211\350\247\2222.java" +++ /dev/null @@ -1,69 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import io.github.dunwu.algorithm.util.ArrayUtil; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -// 【杨辉三角 II】 -// -// 给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。 -// -// 在杨辉三角中,每个数是它左上方和右上方的数的和。 -// -// 示例: -// -// 输入: 3 -// 输出: [1,3,3,1] -// 进阶: -// -// 你可以优化你的算法到 O(k) 空间复杂度吗? - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 杨辉三角2 { - - public static void main(String[] args) { - List list = 杨辉三角2.getRow(3); - System.out.println(ArrayUtil.getArrayString(list.toArray(), 0, list.size() - 1)); - } - - public static List getRow(int rowIndex) { - List> result = new ArrayList<>(); - - int rows = rowIndex + 1; - if (rows <= 0) { - - } else if (rows == 1) { - result.add(Arrays.asList(1)); - } else if (rows == 2) { - result.add(Arrays.asList(1)); - result.add(Arrays.asList(1, 1)); - } else { - result.add(Arrays.asList(1)); - result.add(Arrays.asList(1, 1)); - for (int i = 2; i < rows; i++) { - List current = result.get(i - 1); - List next = new ArrayList<>(); - - for (int j = 0; j <= i; j++) { - if (j == 0 || j == i) { - next.add(1); - } else { - int x = current.get(j - 1); - int y = current.get(j); - next.add(x + y); - } - } - - result.add(next); - } - } - - return result.get(rowIndex); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" deleted file mode 100644 index 02e6f8f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; - -/** - * LCR 179. 查找总价格为目标值的两个商品 - * - * @author Zhang Peng - * @date 2025-01-13 - */ -public class 查找总价格为目标值的两个商品 { - - public static void main(String[] args) { - Assertions.assertArrayEquals(new int[] { 3, 15 }, twoSum(new int[] { 3, 9, 12, 15 }, 18)); - Assertions.assertArrayEquals(new int[] { 27, 34 }, twoSum(new int[] { 8, 21, 27, 34, 52, 66 }, 61)); - - Assertions.assertArrayEquals(new int[] { 3, 15 }, twoSum2(new int[] { 3, 9, 12, 15 }, 18)); - Assertions.assertArrayEquals(new int[] { 27, 34 }, twoSum2(new int[] { 8, 21, 27, 34, 52, 66 }, 61)); - } - - /** - * 时间复杂度:O(N) - */ - public static int[] twoSum(int[] price, int target) { - Map map = new HashMap<>(price.length); - for (int i = 0; i < price.length; i++) { - int diff = target - price[i]; - if (map.containsKey(diff)) { - return new int[] { diff, price[i] }; - } else { - map.put(price[i], i); - } - } - return new int[0]; - } - - public static int[] twoSum2(int[] price, int target) { - int left = 0, right = price.length - 1; - while (left < right) { - int sum = price[left] + price[right]; - if (sum == target) { - return new int[] { price[left], price[right] }; - } else if (sum < target) { - left++; - } else { - right--; - } - } - return new int[0]; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\207\263\345\260\221\346\230\257\345\205\266\344\273\226\346\225\260\345\255\227\344\270\244\345\200\215\347\232\204\346\234\200\345\244\247\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\207\263\345\260\221\346\230\257\345\205\266\344\273\226\346\225\260\345\255\227\344\270\244\345\200\215\347\232\204\346\234\200\345\244\247\346\225\260.java" deleted file mode 100644 index 332bf0c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\207\263\345\260\221\346\230\257\345\205\266\344\273\226\346\225\260\345\255\227\344\270\244\345\200\215\347\232\204\346\234\200\345\244\247\346\225\260.java" +++ /dev/null @@ -1,67 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -// 【至少是其他数字两倍的最大数】 -// -// 在一个给定的数组nums中,总是存在一个最大元素 。 -// -// 查找数组中的最大元素是否至少是数组中每个其他数字的两倍。 -// -// 如果是,则返回最大元素的索引,否则返回-1。 -// -// 示例 1: -// -// 输入: nums = [3, 6, 1, 0] -// 输出: 1 -// 解释: 6是最大的整数, 对于数组中的其他整数, -// 6大于数组中其他元素的两倍。6的索引是1, 所以我们返回1. -// -// -// 示例 2: -// -// 输入: nums = [1, 2, 3, 4] -// 输出: -1 -// 解释: 4没有超过3的两倍大, 所以我们返回 -1. -// -// -// 提示: -// -// nums 的长度范围在[1, 50]. -// 每个 nums[i] 的整数范围在 [0, 99]. - -/** - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 至少是其他数字两倍的最大数 { - - public static void main(String[] args) { - int[] nums1 = { 3, 6, 1, 0 }; - int[] nums2 = { 1, 2, 3, 4 }; - - Assertions.assertEquals(1, 至少是其他数字两倍的最大数.dominantIndex(nums1)); - Assertions.assertEquals(-1, 至少是其他数字两倍的最大数.dominantIndex(nums2)); - } - - public static int dominantIndex(int[] nums) { - int index = 0; - while (index < nums.length) { - boolean isMatch = true; - int max = nums[index]; - for (int i = 0; i < nums.length; i++) { - if (index != i && max < nums[i] * 2) { - isMatch = false; - break; - } - } - if (isMatch) { - return index; - } else { - index++; - } - } - return -1; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" deleted file mode 100644 index b9b257a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" +++ /dev/null @@ -1,45 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 313. 超级丑数 - * - * @author Zhang Peng - * @date 2025-01-24 - */ -public class 超级丑数 { - - public static void main(String[] args) { - Assertions.assertEquals(32, nthSuperUglyNumber(12, new int[] { 2, 7, 13, 19 })); - Assertions.assertEquals(1, nthSuperUglyNumber(1, new int[] { 2, 3, 5 })); - } - - public static int nthSuperUglyNumber(int n, int[] primes) { - int len = primes.length; - int[] offsets = new int[len]; - long[] values = new long[len]; - long[] ugly = new long[n + 1]; - int u = 1; - for (int i = 0; i < len; i++) { - offsets[i] = 1; - values[i] = 1; - } - while (u <= n) { - long min = Integer.MAX_VALUE; - for (int i = 0; i < len; i++) { - min = Math.min(values[i], min); - } - ugly[u++] = min; - - for (int i = 0; i < len; i++) { - if (values[i] == min) { - values[i] = primes[i] * ugly[offsets[i]]; - offsets[i] = offsets[i] + 1; - } - } - } - return (int) ugly[n]; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" deleted file mode 100644 index 6664fa0..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" +++ /dev/null @@ -1,47 +0,0 @@ -package io.github.dunwu.algorithm.array; - -// 【长度最小的子数组】 - -// -// 给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。 -// -// 示例: -// -// 输入: s = 7, nums = [2,3,1,2,4,3] -// 输出: 2 -// 解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。 -// 进阶: -// -// 如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。 - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 长度最小的子数组 { - - public static void main(String[] args) { - 长度最小的子数组.minSubArrayLen(7, new int[] { 2, 3, 1, 2, 4, 3 }); - 长度最小的子数组.minSubArrayLen(11, new int[] { 2, 3, 1, 2, 4, 3 }); - } - - public static int minSubArrayLen(int s, int[] nums) { - if (nums == null || nums.length == 0) { - return 0; - } - - int j = 0, i = 0, sum = 0, min = Integer.MAX_VALUE; - - while (i < nums.length) { - sum += nums[i++]; - - while (sum >= s) { - min = Math.min(min, i - j); - sum -= nums[j++]; - } - } - - return min == Integer.MAX_VALUE ? 0 : min; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\233\266\347\237\251\351\230\265.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\233\266\347\237\251\351\230\265.java" deleted file mode 100644 index be09756..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/\351\233\266\347\237\251\351\230\265.java" +++ /dev/null @@ -1,73 +0,0 @@ -package io.github.dunwu.algorithm.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 零矩阵 { - - public static void main(String[] args) { - int[][] array = { - { 1, 1, 1 }, - { 1, 0, 1 }, - { 1, 1, 1 } - }; - int[][] array2 = { - { 1, 0, 1 }, - { 0, 0, 0 }, - { 1, 0, 1 } - }; - setZeroes(array); - // setZeroForElement(array, 1, 1); - Assertions.assertArrayEquals(array2, array); - } - - /** - * @see 08. 零矩阵 - */ - public static void setZeroes(int[][] matrix) { - int row = matrix.length; - int column = matrix[0].length; - List list = new ArrayList<>(); - for (int i = 0; i < row; i++) { - for (int j = 0; j < column; j++) { - if (matrix[i][j] == 0) { - list.add(new Point(i, j)); - } - } - } - - list.forEach(p -> { - setZeroForElement(matrix, p.i, p.j); - }); - } - - public static void setZeroForElement(int[][] matrix, int x, int y) { - int row = matrix.length; - int column = matrix[0].length; - for (int i = 0; i < row; i++) { - matrix[i][y] = 0; - } - for (int j = 0; j < column; j++) { - matrix[x][j] = 0; - } - } - - static class Point { - - public int i; - public int j; - - public Point(int i, int j) { - this.i = i; - this.j = j; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2602.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2602.java" new file mode 100644 index 0000000..642e338 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2602.java" @@ -0,0 +1,78 @@ +package io.github.dunwu.algorithm.dp.array; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashSet; +import java.util.PriorityQueue; +import java.util.Set; + +/** + * 264. 丑数II + * + * @author Zhang Peng + * @date 2025-01-24 + */ +public class 丑数2 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(12, s.nthUglyNumber(10)); + Assertions.assertEquals(1, s.nthUglyNumber(1)); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals(12, s2.nthUglyNumber(10)); + Assertions.assertEquals(1, s2.nthUglyNumber(1)); + } + + // 动态规划方案 + static class Solution { + + public int nthUglyNumber(int n) { + int[] dp = new int[n + 1]; + dp[1] = 1; + int p2 = 1, p3 = 1, p5 = 1; + for (int i = 2; i <= n; i++) { + int num2 = dp[p2] * 2; + int num3 = dp[p3] * 3; + int num5 = dp[p5] * 5; + dp[i] = min(num2, num3, num5); + if (dp[i] == num2) { p2++; } + if (dp[i] == num3) { p3++; } + if (dp[i] == num5) { p5++; } + } + return dp[n]; + } + + int min(int a, int b, int c) { + return Math.min(a, Math.min(b, c)); + } + + } + + // 优先队列(堆)方案 + static class Solution2 { + + int[] nums = new int[] { 2, 3, 5 }; + + public int nthUglyNumber(int n) { + Set set = new HashSet<>(); + PriorityQueue q = new PriorityQueue<>(); + set.add(1L); + q.add(1L); + for (int i = 1; i <= n; i++) { + long x = q.poll(); + if (i == n) return (int) x; + for (int num : nums) { + long t = num * x; + if (!set.contains(t)) { + set.add(t); + q.add(t); + } + } + } + return -1; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2603.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2603.java" new file mode 100644 index 0000000..dbf9eb0 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2603.java" @@ -0,0 +1,43 @@ +package io.github.dunwu.algorithm.dp.array; + +import org.junit.jupiter.api.Assertions; + +/** + * 1201. 丑数 III + * + * @author Zhang Peng + * @date 2025-01-24 + */ +public class 丑数3 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(4, s.nthUglyNumber(3, 2, 3, 5)); + Assertions.assertEquals(6, s.nthUglyNumber(4, 2, 3, 4)); + Assertions.assertEquals(10, s.nthUglyNumber(5, 2, 11, 13)); + } + + static class Solution { + + public int nthUglyNumber(int n, int a, int b, int c) { + int[] dp = new int[n + 1]; + int pa = 0, pb = 0, pc = 0; + for (int i = 1; i <= n; i++) { + int numA = dp[pa] + a; + int numB = dp[pb] + b; + int numC = dp[pc] + c; + dp[i] = min(numA, numB, numC); + if (dp[i] == numA) { pa = i; } + if (dp[i] == numB) { pb = i; } + if (dp[i] == numC) { pc = i; } + } + return dp[n]; + } + + int min(int a, int b, int c) { + return Math.min(a, Math.min(b, c)); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" new file mode 100644 index 0000000..59d092a --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" @@ -0,0 +1,73 @@ +package io.github.dunwu.algorithm.dp.array; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashSet; +import java.util.PriorityQueue; +import java.util.Set; + +/** + * 313. 超级丑数 + * + * @author Zhang Peng + * @date 2025-01-24 + */ +public class 超级丑数 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(32, s.nthSuperUglyNumber(12, new int[] { 2, 7, 13, 19 })); + Assertions.assertEquals(1, s.nthSuperUglyNumber(1, new int[] { 2, 3, 5 })); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals(32, s2.nthSuperUglyNumber(12, new int[] { 2, 7, 13, 19 })); + Assertions.assertEquals(1, s2.nthSuperUglyNumber(1, new int[] { 2, 3, 5 })); + } + + // 优先队列(堆)方案 + static class Solution { + + public int nthSuperUglyNumber(int n, int[] primes) { + Set set = new HashSet<>(); + PriorityQueue queue = new PriorityQueue<>(); + set.add(1L); + queue.add(1L); + for (int i = 1; i <= n; i++) { + long x = queue.poll(); + if (i == n) { return (int) x; } + for (int num : primes) { + long val = num * x; + if (!set.contains(val)) { + set.add(val); + queue.add(val); + } + } + } + return -1; + } + + } + + // 多路归并方案 + static class Solution2 { + + public int nthSuperUglyNumber(int n, int[] nums) { + int m = nums.length; + PriorityQueue q = new PriorityQueue<>((a, b) -> a[0] - b[0]); + for (int i = 0; i < m; i++) { + q.add(new int[] { nums[i], i, 0 }); + } + int[] dp = new int[n]; + dp[0] = 1; + for (int j = 1; j < n; ) { + int[] poll = q.poll(); + int num = poll[0], i = poll[1], idx = poll[2]; + if (num != dp[j - 1]) dp[j++] = num; + q.add(new int[] { dp[idx + 1] * nums[i], i, idx + 1 }); + } + return dp[n - 1]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\235\250\350\276\211\344\270\211\350\247\222.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\235\250\350\276\211\344\270\211\350\247\222.java" new file mode 100644 index 0000000..4ace68d --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\235\250\350\276\211\344\270\211\350\247\222.java" @@ -0,0 +1,54 @@ +package io.github.dunwu.algorithm.dp; + +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * 118. 杨辉三角 + * + * @author Zhang Peng + * @since 2018-11-04 + */ +public class 杨辉三角 { + + public static void main(String[] args) { + Solution s = new Solution(); + List> expect = new ArrayList<>(); + expect.add(Arrays.asList(1)); + expect.add(Arrays.asList(1, 1)); + expect.add(Arrays.asList(1, 2, 1)); + expect.add(Arrays.asList(1, 3, 3, 1)); + expect.add(Arrays.asList(1, 4, 6, 4, 1)); + List> lists = s.generate(5); + Assertions.assertArrayEquals(expect.toArray(), lists.toArray()); + } + + static class Solution { + + public List> generate(int row) { + int[][] matrix = new int[row][row]; + matrix[0][0] = 1; + List> res = new ArrayList<>(); + res.add(Collections.singletonList(1)); + for (int i = 1; i < row; i++) { + List list = new ArrayList<>(); + for (int j = 0; j <= i; j++) { + if (j == 0) { + matrix[i][j] = matrix[i - 1][j]; + } else { + matrix[i][j] = matrix[i - 1][j] + matrix[i - 1][j - 1]; + } + list.add(matrix[i][j]); + } + res.add(list); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\235\250\350\276\211\344\270\211\350\247\2222.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\235\250\350\276\211\344\270\211\350\247\2222.java" new file mode 100644 index 0000000..a6a3faa --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\235\250\350\276\211\344\270\211\350\247\2222.java" @@ -0,0 +1,49 @@ +package io.github.dunwu.algorithm.dp; + +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 119. 杨辉三角 II + * + * @author Zhang Peng + * @since 2018-11-05 + */ +public class 杨辉三角2 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new Integer[] { 1, 3, 3, 1 }, s.getRow(3).toArray()); + Assertions.assertArrayEquals(new Integer[] { 1 }, s.getRow(0).toArray()); + Assertions.assertArrayEquals(new Integer[] { 1, 1 }, s.getRow(1).toArray()); + } + + static class Solution { + + public List getRow(int rowIndex) { + int row = rowIndex + 1; + int[][] matrix = new int[row][row]; + matrix[0][0] = 1; + List> res = new ArrayList<>(); + res.add(Collections.singletonList(1)); + for (int i = 1; i < row; i++) { + List list = new ArrayList<>(); + for (int j = 0; j <= i; j++) { + if (j == 0) { + matrix[i][j] = matrix[i - 1][j]; + } else { + matrix[i][j] = matrix[i - 1][j] + matrix[i - 1][j - 1]; + } + list.add(matrix[i][j]); + } + res.add(list); + } + return res.get(rowIndex); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" new file mode 100644 index 0000000..d9383f6 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" @@ -0,0 +1,138 @@ +package io.github.dunwu.algorithm.graph.bipartite; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 785. 判断二分图 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 判断二分图 { + + public static void main(String[] args) { + + int[][] input = new int[][] { { 1, 2, 3 }, { 0, 2 }, { 0, 1, 3 }, { 0, 2 } }; + int[][] input2 = new int[][] { { 1, 3 }, { 0, 2 }, { 1, 3 }, { 0, 2 } }; + + Solution s = new Solution(); + Assertions.assertFalse(s.isBipartite(input)); + Assertions.assertFalse(s.isBipartite(input2)); + + Solution2 s2 = new Solution2(); + Assertions.assertFalse(s2.isBipartite(input)); + Assertions.assertFalse(s2.isBipartite(input2)); + } + + // 二分图算法(DFS 版本) + static class Solution { + + // 记录图是否符合二分图性质 + private boolean ok = true; + // 记录图中节点的颜色,false 和 true 代表两种不同颜色 + private boolean[] color; + // 记录图中节点是否被访问过 + private boolean[] visited; + + // 主函数,输入邻接表,判断是否是二分图 + public boolean isBipartite(int[][] graph) { + int n = graph.length; + color = new boolean[n]; + visited = new boolean[n]; + // 因为图不一定是联通的,可能存在多个子图 + // 所以要把每个节点都作为起点进行一次遍历 + // 如果发现任何一个子图不是二分图,整幅图都不算二分图 + for (int v = 0; v < n; v++) { + if (!visited[v]) { + dfs(graph, v); + } + } + return ok; + } + + // DFS 遍历框架 + private void dfs(int[][] graph, int v) { + // 如果已经确定不是二分图了,就不用浪费时间再递归遍历了 + if (!ok) return; + + visited[v] = true; + for (int w : graph[v]) { + if (!visited[w]) { + // 相邻节点 w 没有被访问过 + // 那么应该给节点 w 涂上和节点 v 不同的颜色 + color[w] = !color[v]; + // 继续遍历 w + dfs(graph, w); + } else { + // 相邻节点 w 已经被访问过 + // 根据 v 和 w 的颜色判断是否是二分图 + if (color[w] == color[v]) { + // 若相同,则此图不是二分图 + ok = false; + } + } + } + } + + } + + // 二分图算法(BFS 版本) + static class Solution2 { + + // 记录图是否符合二分图性质 + private boolean ok = true; + // 记录图中节点的颜色,false 和 true 代表两种不同颜色 + private boolean[] color; + // 记录图中节点是否被访问过 + private boolean[] visited; + + public boolean isBipartite(int[][] graph) { + int n = graph.length; + color = new boolean[n]; + visited = new boolean[n]; + + for (int v = 0; v < n; v++) { + if (!visited[v]) { + // 改为使用 BFS 函数 + bfs(graph, v); + } + } + + return ok; + } + + // 从 start 节点开始进行 BFS 遍历 + private void bfs(int[][] graph, int start) { + LinkedList q = new LinkedList<>(); + visited[start] = true; + q.offer(start); + + while (!q.isEmpty() && ok) { + int v = q.poll(); + // 从节点 v 向所有相邻节点扩散 + for (int w : graph[v]) { + if (!visited[w]) { + // 相邻节点 w 没有被访问过 + // 那么应该给节点 w 涂上和节点 v 不同的颜色 + color[w] = !color[v]; + // 标记 w 节点,并放入队列 + visited[w] = true; + q.offer(w); + } else { + // 相邻节点 w 已经被访问过 + // 根据 v 和 w 的颜色判断是否是二分图 + if (color[w] == color[v]) { + // 若相同,则此图不是二分图 + ok = false; + return; + } + } + } + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\217\257\350\203\275\347\232\204\344\272\214\345\210\206\346\263\225.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\217\257\350\203\275\347\232\204\344\272\214\345\210\206\346\263\225.java" new file mode 100644 index 0000000..4b8be13 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\217\257\350\203\275\347\232\204\344\272\214\345\210\206\346\263\225.java" @@ -0,0 +1,82 @@ +package io.github.dunwu.algorithm.graph.bipartite; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 886. 可能的二分法 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 可能的二分法 { + + public static void main(String[] args) { + + int[][] input = new int[][] { { 1, 2 }, { 1, 3 }, { 2, 4 } }; + int[][] input2 = new int[][] { { 1, 2 }, { 1, 3 }, { 2, 3 } }; + int[][] input3 = new int[][] { { 1, 2 }, { 2, 3 }, { 3, 4 }, { 4, 5 }, { 1, 5 } }; + + Solution s = new Solution(); + Assertions.assertTrue(s.possibleBipartition(4, input)); + Assertions.assertFalse(s.possibleBipartition(3, input2)); + Assertions.assertFalse(s.possibleBipartition(5, input3)); + } + + static class Solution { + + private boolean ok = true; + private boolean[] color; + private boolean[] visited; + + public boolean possibleBipartition(int n, int[][] dislikes) { + // 图节点编号从 1 开始 + color = new boolean[n + 1]; + visited = new boolean[n + 1]; + + // 转化成邻接表图结构 + List[] graph = buildGraph(n, dislikes); + + for (int v = 1; v <= n; v++) { + if (!visited[v]) { + dfs(graph, v); + } + } + + return ok; + } + + public void dfs(List[] graph, int v) { + if (!ok) return; + visited[v] = true; + for (int w : graph[v]) { + if (!visited[w]) { + color[w] = !color[v]; + dfs(graph, w); + } else { + if (color[w] == color[v]) { + ok = false; + } + } + } + } + + public List[] buildGraph(int n, int[][] data) { + List[] graph = new LinkedList[n + 1]; + for (int i = 1; i <= n; i++) { + graph[i] = new LinkedList<>(); + } + + for (int[] edge : data) { + int v = edge[1], w = edge[0]; + graph[v].add(w); + graph[w].add(v); + } + return graph; + } + + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/Dijkstra.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/Dijkstra.java new file mode 100644 index 0000000..518770b --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/Dijkstra.java @@ -0,0 +1,78 @@ +package io.github.dunwu.algorithm.graph.template; + +import io.github.dunwu.algorithm.graph.Edge; +import io.github.dunwu.algorithm.graph.Graph; + +import java.util.Arrays; +import java.util.PriorityQueue; + +/** + * Dijkstra 算法模板 + * + * @author Zhang Peng + * @date 2025-12-03 + */ +public class Dijkstra { + + // 输入不包含负权重边的加权图 graph 和起点 src + // 返回从起点 src 到其他节点的最小路径权重和 + public int[] dijkstra(Graph graph, int src) { + // 记录从起点 src 到其他节点的最小路径权重和 + // distTo[i] 表示从起点 src 到节点 i 的最小路径权重和 + int[] distTo = new int[graph.size()]; + // 都初始化为正无穷,表示未计算 + Arrays.fill(distTo, Integer.MAX_VALUE); + + // 优先级队列,distFromStart 较小的节点排在前面 + PriorityQueue pq = new PriorityQueue<>((a, b) -> { + return a.distFromStart - b.distFromStart; + }); + + // 从起点 src 开始进行 BFS + pq.offer(new State(src, 0)); + distTo[src] = 0; + + while (!pq.isEmpty()) { + State state = pq.poll(); + int curNode = state.node; + int curDistFromStart = state.distFromStart; + + if (distTo[curNode] < curDistFromStart) { + // 在 Dijkstra 算法中,队列中可能存在重复的节点 state + // 所以要在元素出队时进行判断,去除较差的重复节点 + continue; + } + + for (Edge e : graph.neighbors(curNode)) { + int nextNode = e.to; + int nextDistFromStart = curDistFromStart + e.weight; + + if (distTo[nextNode] <= nextDistFromStart) { + continue; + } + + // 将 nextNode 节点加入优先级队列 + pq.offer(new State(nextNode, nextDistFromStart)); + // 记录 nextNode 节点到起点的最小路径权重和 + distTo[nextNode] = nextDistFromStart; + } + } + + return distTo; + } + + static class State { + + // 当前节点 ID + int node; + // 从起点 s 到当前 node 节点的最小路径权重和 + int distFromStart; + + public State(int node, int distFromStart) { + this.node = node; + this.distFromStart = distFromStart; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\271\266\346\237\245\351\233\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\271\266\346\237\245\351\233\206.java" new file mode 100644 index 0000000..bc15937 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\271\266\346\237\245\351\233\206.java" @@ -0,0 +1,60 @@ +package io.github.dunwu.algorithm.graph.template; + +/** + * 并查集 + * + * @author Zhang Peng + * @date 2025-12-03 + */ +public class 并查集 { + + static class UF { + + // 连通分量个数 + private int count; + // 存储每个节点的父节点 + private int[] parent; + + // n 为图中节点的个数 + public UF(int n) { + this.count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + // 将节点 p 和节点 q 连通 + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + + if (rootP == rootQ) { return; } + + parent[rootQ] = rootP; + // 两个连通分量合并成一个连通分量 + count--; + } + + // 判断节点 p 和节点 q 是否连通 + public boolean connected(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + return rootP == rootQ; + } + + public int find(int x) { + if (parent[x] != x) { + parent[x] = find(parent[x]); + } + return parent[x]; + } + + // 返回图中的连通分量个数 + public int count() { + return count; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\250.java" index ce64e41..62c8c0d 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\250.java" @@ -4,6 +4,7 @@ import java.util.LinkedList; import java.util.List; +import java.util.Queue; /** * 207. 课程表 @@ -15,15 +16,18 @@ public class 课程表 { public static void main(String[] args) { Solution s = new Solution(); - int[][] input = new int[][] { { 1, 0 } }; - int[][] input2 = new int[][] { { 1, 0 }, { 0, 1 } }; - Assertions.assertTrue(s.canFinish(2, input)); - Assertions.assertFalse(s.canFinish(2, input2)); + Assertions.assertTrue(s.canFinish(2, new int[][] { { 1, 0 } })); + Assertions.assertFalse(s.canFinish(2, new int[][] { { 1, 0 }, { 0, 1 } })); + + Solution2 s2 = new Solution2(); + Assertions.assertTrue(s2.canFinish(2, new int[][] { { 1, 0 } })); + Assertions.assertFalse(s2.canFinish(2, new int[][] { { 1, 0 }, { 0, 1 } })); } + // 环检测算法(DFS 版本) static class Solution { - // 记录递归堆栈中的节点 + // 记录一次递归堆栈中的节点 boolean[] onPath; // 记录节点是否被遍历过 boolean[] visited; @@ -32,56 +36,99 @@ static class Solution { public boolean canFinish(int numCourses, int[][] prerequisites) { List[] graph = buildGraph(numCourses, prerequisites); - - onPath = new boolean[numCourses]; visited = new boolean[numCourses]; + onPath = new boolean[numCourses]; + // 遍历图中的所有节点 for (int i = 0; i < numCourses; i++) { - // 遍历图中的所有节点 dfs(graph, i); } // 只要没有循环依赖可以完成所有课程 return !hasCycle; } - // 图遍历函数,遍历所有路径 - void dfs(List[] graph, int s) { - if (hasCycle) { - // 如果已经找到了环,也不用再遍历了 - return; - } - - if (onPath[s]) { - // s 已经在递归路径上,说明成环了 - hasCycle = true; - return; - } - - if (visited[s]) { - // 不用再重复遍历已遍历过的节点 - return; - } + public void dfs(List[] graph, int s) { + // 找到环,或已访问,则无需再遍历 + if (onPath[s]) { hasCycle = true; } + if (hasCycle || visited[s]) { return; } - // 前序代码位置 + // 【前序】 visited[s] = true; onPath[s] = true; for (int t : graph[s]) { dfs(graph, t); } - // 后序代码位置 + // 【后序】 onPath[s] = false; } - List[] buildGraph(int numCourses, int[][] prerequisites) { - // 图中共有 numCourses 个节点 - List[] graph = new LinkedList[numCourses]; - for (int i = 0; i < numCourses; i++) { + public List[] buildGraph(int n, int[][] data) { + List[] graph = new LinkedList[n]; + for (int i = 0; i < n; i++) { graph[i] = new LinkedList<>(); } + + for (int[] edge : data) { + int from = edge[1], to = edge[0]; + graph[from].add(to); + } + return graph; + } + + } + + // 环检测算法(BFS 版本) + static class Solution2 { + + public boolean canFinish(int numCourses, int[][] prerequisites) { + // 建图,有向边代表「被依赖」关系 + List[] graph = buildGraph(numCourses, prerequisites); + // 构建入度数组 + int[] indegree = new int[numCourses]; for (int[] edge : prerequisites) { int from = edge[1], to = edge[0]; - // 添加一条从 from 指向 to 的有向边 - // 边的方向是「被依赖」关系,即修完课程 from 才能修课程 to + // 节点 to 的入度加一 + indegree[to]++; + } + + // 根据入度初始化队列中节点 + Queue q = new LinkedList<>(); + for (int i = 0; i < numCourses; i++) { + if (indegree[i] == 0) { + // 节点 i 没有入度,即没有依赖的节点 + // 可以作为拓扑排序的起点,加入队列 + q.offer(i); + } + } + + // 记录遍历的节点个数 + int count = 0; + // 开始执行 BFS 遍历 + while (!q.isEmpty()) { + // 弹出节点 cur,并将它指向的节点的入度减一 + int cur = q.poll(); + count++; + for (int next : graph[cur]) { + indegree[next]--; + if (indegree[next] == 0) { + // 如果入度变为 0,说明 next 依赖的节点都已被遍历 + q.offer(next); + } + } + } + + // 如果所有节点都被遍历过,说明不成环 + return count == numCourses; + } + + public List[] buildGraph(int n, int[][] data) { + List[] graph = new LinkedList[n]; + for (int i = 0; i < n; i++) { + graph[i] = new LinkedList<>(); + } + + for (int[] edge : data) { + int from = edge[1], to = edge[0]; graph[from].add(to); } return graph; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\2502.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\2502.java" new file mode 100644 index 0000000..718b2db --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\2502.java" @@ -0,0 +1,156 @@ +package io.github.dunwu.algorithm.graph.topological_sort; + +import org.junit.jupiter.api.Assertions; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * 210. 课程表 II + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 课程表2 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new int[] { 0, 1 }, s.findOrder(2, new int[][] { { 1, 0 } })); + Assertions.assertArrayEquals(new int[] { 0, 2, 1, 3 }, + s.findOrder(4, new int[][] { { 1, 0 }, { 2, 0 }, { 3, 1 }, { 3, 2 } })); + + Solution2 s2 = new Solution2(); + Assertions.assertArrayEquals(new int[] { 0, 1 }, s2.findOrder(2, new int[][] { { 1, 0 } })); + Assertions.assertArrayEquals(new int[] { 0, 1, 2, 3 }, + s2.findOrder(4, new int[][] { { 1, 0 }, { 2, 0 }, { 3, 1 }, { 3, 2 } })); + } + + // 拓扑排序算法(DFS 版本) + static class Solution { + + // 记录后序遍历结果 + private List preorder; + // 记录一次递归堆栈中的节点 + boolean[] onPath; + // 记录节点是否被遍历过 + boolean[] visited; + // 记录图中是否有环 + boolean hasCycle = false; + + public int[] findOrder(int numCourses, int[][] prerequisites) { + List[] graph = buildGraph(numCourses, prerequisites); + preorder = new LinkedList<>(); + visited = new boolean[numCourses]; + onPath = new boolean[numCourses]; + + for (int i = 0; i < numCourses; i++) { + dfs(graph, i); + } + + // 有环图无法进行拓扑排序 + if (hasCycle) { return new int[0]; } + + // 逆后序遍历结果即为拓扑排序结果 + Collections.reverse(preorder); + int[] order = new int[numCourses]; + for (int i = 0; i < numCourses; i++) { + order[i] = preorder.get(i); + } + return order; + } + + public void dfs(List[] graph, int s) { + // 找到环,或已访问,则无需再遍历 + if (onPath[s]) { hasCycle = true; } + if (hasCycle || visited[s]) { return; } + + // 【前序】 + visited[s] = true; + onPath[s] = true; + for (int t : graph[s]) { + dfs(graph, t); + } + // 【后序】 + preorder.add(s); + onPath[s] = false; + } + + public List[] buildGraph(int n, int[][] data) { + List[] graph = new LinkedList[n]; + for (int i = 0; i < n; i++) { + graph[i] = new LinkedList<>(); + } + + for (int[] edge : data) { + int from = edge[1], to = edge[0]; + graph[from].add(to); + } + return graph; + } + + } + + // 拓扑排序算法(BFS 版本) + static class Solution2 { + + public int[] findOrder(int numCourses, int[][] prerequisites) { + // 建图,和环检测算法相同 + List[] graph = buildGraph(numCourses, prerequisites); + // 计算入度,和环检测算法相同 + int[] indegree = new int[numCourses]; + for (int[] edge : prerequisites) { + int from = edge[1], to = edge[0]; + indegree[to]++; + } + + // 根据入度初始化队列中的节点,和环检测算法相同 + Queue q = new LinkedList<>(); + for (int i = 0; i < numCourses; i++) { + if (indegree[i] == 0) { + q.offer(i); + } + } + + // 记录拓扑排序结果 + int[] res = new int[numCourses]; + // 记录遍历节点的顺序(索引) + int count = 0; + // 开始执行 BFS 算法 + while (!q.isEmpty()) { + int cur = q.poll(); + // 弹出节点的顺序即为拓扑排序结果 + res[count] = cur; + count++; + for (int next : graph[cur]) { + indegree[next]--; + if (indegree[next] == 0) { + q.offer(next); + } + } + } + + // 存在环,拓扑排序不存在 + if (count != numCourses) { + return new int[0]; + } + return res; + } + + public List[] buildGraph(int n, int[][] data) { + List[] graph = new LinkedList[n]; + for (int i = 0; i < n; i++) { + graph[i] = new LinkedList<>(); + } + + for (int[] edge : data) { + int from = edge[1], to = edge[0]; + graph[from].add(to); + } + return graph; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\345\206\227\344\275\231\350\277\236\346\216\245.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\345\206\227\344\275\231\350\277\236\346\216\245.java" new file mode 100644 index 0000000..f3729f5 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\345\206\227\344\275\231\350\277\236\346\216\245.java" @@ -0,0 +1,84 @@ +package io.github.dunwu.algorithm.graph.union_find; + +import org.junit.jupiter.api.Assertions; + +/** + * 684. 冗余连接 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 冗余连接 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[][] input = new int[][] { { 1, 2 }, { 1, 3 }, { 2, 3 } }; + int[][] input2 = new int[][] { { 1, 2 }, { 2, 3 }, { 3, 4 }, { 1, 4 }, { 1, 5 } }; + Assertions.assertArrayEquals(new int[] { 2, 3 }, s.findRedundantConnection(input)); + Assertions.assertArrayEquals(new int[] { 1, 4 }, s.findRedundantConnection(input2)); + } + + static class Solution { + + public int[] findRedundantConnection(int[][] edges) { + int n = edges.length; + UF uf = new UF(n + 1); + for (int i = 0; i < n; i++) { + int u = edges[i][0]; + int v = edges[i][1]; + if (uf.find(u) == uf.find(v)) { + return new int[] { u, v }; + } else { + uf.union(u, v); + } + } + return new int[0]; + } + + static class UF { + + // 连通分量个数 + private int count; + // 存储每个节点的父节点 + private int[] parent; + + public UF(int n) { + this.count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + + if (rootP == rootQ) { return; } + + parent[rootQ] = rootP; + count--; + } + + public boolean connected(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + return rootP == rootQ; + } + + public int find(int x) { + if (parent[x] != x) { + parent[x] = find(parent[x]); + } + return parent[x]; + } + + public int count() { + return count; + } + + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\347\255\211\345\274\217\346\226\271\347\250\213\347\232\204\345\217\257\346\273\241\350\266\263\346\200\247.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\347\255\211\345\274\217\346\226\271\347\250\213\347\232\204\345\217\257\346\273\241\350\266\263\346\200\247.java" new file mode 100644 index 0000000..c78af57 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\347\255\211\345\274\217\346\226\271\347\250\213\347\232\204\345\217\257\346\273\241\350\266\263\346\200\247.java" @@ -0,0 +1,94 @@ +package io.github.dunwu.algorithm.graph.union_find; + +import org.junit.jupiter.api.Assertions; + +/** + * 990. 等式方程的可满足性 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 等式方程的可满足性 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertFalse(s.equationsPossible(new String[] { "a==b", "b!=a" })); + Assertions.assertTrue(s.equationsPossible(new String[] { "b==a", "a==b" })); + Assertions.assertTrue(s.equationsPossible(new String[] { "a==b", "b==c", "a==c" })); + Assertions.assertFalse(s.equationsPossible(new String[] { "a==b", "b!=c", "c==a" })); + Assertions.assertTrue(s.equationsPossible(new String[] { "c==c", "b==d", "x!=z" })); + } + + static class Solution { + + public boolean equationsPossible(String[] equations) { + UF uf = new UF(26); + for (String exp : equations) { + if (exp.contains("==")) { + String[] vals = exp.split("=="); + int a = vals[0].charAt(0) - 'a'; + int b = vals[1].charAt(0) - 'a'; + uf.union(a, b); + } + } + + for (String exp : equations) { + if (exp.contains("!=")) { + String[] vals = exp.split("!="); + int a = vals[0].charAt(0) - 'a'; + int b = vals[1].charAt(0) - 'a'; + if (uf.connected(a, b)) { + return false; + } + } + } + return true; + } + + static class UF { + + // 连通分量个数 + private int count; + // 存储每个节点的父节点 + private int[] parent; + + public UF(int n) { + this.count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + + if (rootP == rootQ) { return; } + + parent[rootQ] = rootP; + count--; + } + + public boolean connected(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + return rootP == rootQ; + } + + public int find(int x) { + if (parent[x] != x) { + parent[x] = find(parent[x]); + } + return parent[x]; + } + + public int count() { + return count; + } + + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.java" new file mode 100644 index 0000000..9e1896b --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.java" @@ -0,0 +1,134 @@ +package io.github.dunwu.algorithm.graph.union_find; + +import org.junit.jupiter.api.Assertions; + +/** + * 130. 被围绕的区域 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 被围绕的区域 { + + public static void main(String[] args) { + Solution s = new Solution(); + + char[][] input = new char[][] { + { 'X', 'X', 'X', 'X' }, + { 'X', 'O', 'O', 'X' }, + { 'X', 'X', 'O', 'X' }, + { 'X', 'O', 'X', 'X' } + }; + char[][] expect = new char[][] { + { 'X', 'X', 'X', 'X' }, + { 'X', 'X', 'X', 'X' }, + { 'X', 'X', 'X', 'X' }, + { 'X', 'O', 'X', 'X' } + }; + s.solve(input); + Assertions.assertArrayEquals(expect, input); + } + + static class Solution { + + private int m; + private int n; + + public void solve(char[][] board) { + if (board == null || board.length == 0 || board[0].length == 0) { return; } + + m = board.length; + n = board[0].length; + + int dummy = m * n; + UF uf = new UF(m * n + 1); + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + // 遇到 O 进行并查集合并操作 + if (board[i][j] == 'O') { + if (i == 0 || i == m - 1 || j == 0 || j == n - 1) { + // 边界上的 O,把它和 dummy 合并成一个连通区域. + uf.union(node(i, j), dummy); + } else { + // 和上下左右合并成一个连通区域 + if (i > 0 && board[i - 1][j] == 'O') { + uf.union(node(i, j), node(i - 1, j)); + } + if (i < m - 1 && board[i + 1][j] == 'O') { + uf.union(node(i, j), node(i + 1, j)); + } + if (j > 0 && board[i][j - 1] == 'O') { + uf.union(node(i, j), node(i, j - 1)); + } + if (j < n - 1 && board[i][j + 1] == 'O') { + uf.union(node(i, j), node(i, j + 1)); + } + } + } + } + } + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (uf.connected(node(i, j), dummy)) { + // 和 dummy 在一个连通区域的,那么就是 O + board[i][j] = 'O'; + } else { + board[i][j] = 'X'; + } + } + } + } + + int node(int i, int j) { + return i * n + j; + } + + static class UF { + + // 连通分量个数 + private int count; + // 存储每个节点的父节点 + private int[] parent; + + public UF(int n) { + this.count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + + if (rootP == rootQ) { return; } + + parent[rootQ] = rootP; + count--; + } + + public boolean connected(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + return rootP == rootQ; + } + + public int find(int x) { + if (parent[x] != x) { + parent[x] = find(parent[x]); + } + return parent[x]; + } + + public int count() { + return count; + } + + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" deleted file mode 100644 index 4324c62..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" +++ /dev/null @@ -1,72 +0,0 @@ -package io.github.dunwu.algorithm.graph; - -import org.junit.jupiter.api.Assertions; - -/** - * 785. 判断二分图 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 判断二分图 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[][] input = new int[][] { - { 1, 2, 3 }, { 0, 2 }, { 0, 1, 3 }, { 0, 2 } - }; - Assertions.assertFalse(s.isBipartite(input)); - } - - static class Solution { - - // 记录图是否符合二分图性质 - private boolean ok = true; - // 记录图中节点的颜色,false 和 true 代表两种不同颜色 - private boolean[] color; - // 记录图中节点是否被访问过 - private boolean[] visited; - - // 主函数,输入邻接表,判断是否是二分图 - public boolean isBipartite(int[][] graph) { - int n = graph.length; - color = new boolean[n]; - visited = new boolean[n]; - // 因为图不一定是联通的,可能存在多个子图 - // 所以要把每个节点都作为起点进行一次遍历 - // 如果发现任何一个子图不是二分图,整幅图都不算二分图 - for (int v = 0; v < n; v++) { - if (!visited[v]) { - traverse(graph, v); - } - } - return ok; - } - - // DFS 遍历框架 - private void traverse(int[][] graph, int v) { - // 如果已经确定不是二分图了,就不用浪费时间再递归遍历了 - if (!ok) return; - - visited[v] = true; - for (int w : graph[v]) { - if (!visited[w]) { - // 相邻节点 w 没有被访问过 - // 那么应该给节点 w 涂上和节点 v 不同的颜色 - color[w] = !color[v]; - // 继续遍历 w - traverse(graph, w); - } else { - // 相邻节点 w 已经被访问过 - // 根据 v 和 w 的颜色判断是否是二分图 - if (color[w] == color[v]) { - // 若相同,则此图不是二分图 - ok = false; - } - } - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\346\225\260\347\273\204\346\213\206\345\210\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\346\225\260\347\273\204\346\213\206\345\210\206.java" new file mode 100644 index 0000000..88d7ee5 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\346\225\260\347\273\204\346\213\206\345\210\206.java" @@ -0,0 +1,35 @@ +package io.github.dunwu.algorithm.greedy; + +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; + +/** + * 561. 数组拆分 + * + * @author Zhang Peng + * @since 2018-11-05 + */ +public class 数组拆分 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(4, s.arrayPairSum(new int[] { 1, 4, 3, 2 })); + Assertions.assertEquals(9, s.arrayPairSum(new int[] { 6, 2, 6, 5, 1, 2 })); + } + + static class Solution { + + + public int arrayPairSum(int[] nums) { + Arrays.sort(nums); + int sum = 0; + for (int i = 0; i < nums.length; i+=2) { + sum += nums[i]; + } + return sum; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/divide/\346\216\222\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/divide/\346\216\222\345\272\217\351\223\276\350\241\250.java" index cec79e6..9c6a30e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/divide/\346\216\222\345\272\217\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/divide/\346\216\222\345\272\217\351\223\276\350\241\250.java" @@ -27,12 +27,12 @@ public ListNode sortList(ListNode head) { } // 找到中间节点 head2,并断开 head2 与其前一个节点的连接 // 比如 head=[4,2,1,3],那么 middleNode 调用结束后 head=[4,2] head2=[1,3] - ListNode head2 = middleNode(head); + ListNode mid = middleNode(head); // 分治 head = sortList(head); - head2 = sortList(head2); + mid = sortList(mid); // 合并 - return mergeTwoLists(head, head2); + return mergeTwoLists(head, mid); } // 876. 链表的中间结点(快慢指针) diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" index 7cc9d0c..18143c9 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" @@ -22,36 +22,28 @@ public static void main(String[] args) { static class Solution { public ListNode reverseKGroup(ListNode head, int k) { - if (head == null) { return null; } - // 区间 [a, b) 包含 k 个待反转元素 - ListNode a = head, b = head; + if (head == null || head.next == null) { return head; } + ListNode p = head; for (int i = 0; i < k; i++) { - // 不足 k 个,不需要反转了 - if (b == null) { return head; } - b = b.next; + if (p == null) { return head; } + p = p.next; } - // 反转前 k 个元素 - ListNode newHead = reverseN(a, k); - // 此时 b 指向下一组待反转的头结点 - // 递归反转后续链表并连接起来 - a.next = reverseKGroup(b, k); + ListNode newHead = reverseN(head, k); + head.next = reverseKGroup(p, k); return newHead; } - private ListNode reverseN(ListNode head, int len) { - if (head == null || head.next == null) { return head; } - ListNode pre = null, cur = head, next = cur.next; - while (len-- > 0) { + public ListNode reverseN(ListNode head, int len) { + if (head == null) { return null; } + ListNode pre = null, cur = head; + for (int i = 0; i < len; i++) { + if (cur == null) { break; } + ListNode next = cur.next; cur.next = pre; pre = cur; cur = next; - if (next != null) { - next = next.next; - } } - // 此时的 cur 是第 n + 1 个节点,head 是反转后的尾结点 head.next = cur; - // 此时的 pre 是反转后的头结点 return pre; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/math/\344\270\221\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/math/\344\270\221\346\225\260.java" new file mode 100644 index 0000000..dace497 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/math/\344\270\221\346\225\260.java" @@ -0,0 +1,32 @@ +package io.github.dunwu.algorithm.math; + +import org.junit.jupiter.api.Assertions; + +/** + * 263. 丑数 + * + * @author Zhang Peng + * @date 2025-01-24 + */ +public class 丑数 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.isUgly(6)); + Assertions.assertTrue(s.isUgly(1)); + Assertions.assertFalse(s.isUgly(14)); + } + + static class Solution { + + public boolean isUgly(int n) { + if (n <= 0) { return false; } + while (n % 2 == 0) { n /= 2; } + while (n % 3 == 0) { n /= 3; } + while (n % 5 == 0) { n /= 5; } + return n == 1; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/math/\345\212\240\344\270\200.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/math/\345\212\240\344\270\200.java" new file mode 100644 index 0000000..334b604 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/math/\345\212\240\344\270\200.java" @@ -0,0 +1,38 @@ +package io.github.dunwu.algorithm.math; + +import org.junit.jupiter.api.Assertions; + +/** + * 66. 加一 + * + * @author Zhang Peng + * @since 2018-11-04 + */ +public class 加一 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new int[] { 1, 2, 4 }, s.plusOne(new int[] { 1, 2, 3 })); + Assertions.assertArrayEquals(new int[] { 4, 3, 2, 2 }, s.plusOne(new int[] { 4, 3, 2, 1 })); + Assertions.assertArrayEquals(new int[] { 1, 0, 0, 0, 0 }, s.plusOne(new int[] { 9, 9, 9, 9 })); + } + + static class Solution { + + public int[] plusOne(int[] digits) { + for (int i = digits.length - 1; i >= 0; i--) { + if (digits[i] == 9) { + digits[i] = 0; + } else { + digits[i]++; + return digits; + } + } + int[] res = new int[digits.length + 1]; + res[0] = 1; + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" index 1862877..6165bf4 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" @@ -3,7 +3,6 @@ import org.junit.jupiter.api.Assertions; import java.util.LinkedList; -import java.util.Stack; /** * 331. 验证二叉树的前序序列化 From c54b36871c9d638b72e9e421a101668b96d4e4ac Mon Sep 17 00:00:00 2001 From: dunwu Date: Wed, 10 Dec 2025 08:11:22 +0800 Subject: [PATCH 19/21] =?UTF-8?q?feat:=20leetcode=20=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 22 +++--- ...\346\234\200\345\244\247\345\200\274.java" | 40 ++++++----- ...\347\232\204\350\203\275\345\212\233.java" | 28 +++----- ...\347\232\204\347\217\202\347\217\202.java" | 34 ++++----- ...\347\272\277\351\201\215\345\216\206.java" | 32 ++++----- ...\344\270\215\345\217\257\345\217\230.java" | 23 +++--- .../range/\346\213\274\350\275\246.java" | 6 +- ...\350\256\242\347\273\237\350\256\241.java" | 12 +--- ...\346\211\276\346\250\241\346\235\277.java" | 70 +++++++++++++++++++ ...\346\225\260\344\271\213\345\222\214.java" | 28 ++++---- ...\346\226\207\345\255\220\344\270\262.java" | 3 - ...\347\232\204\345\205\203\347\264\240.java" | 49 +++++++++---- ...\346\223\215\344\275\234\346\225\260.java" | 14 +++- ...\345\244\215\345\255\227\347\254\246.java" | 15 ++-- ...\347\233\226\345\255\220\344\270\262.java" | 3 +- ...\351\225\277\345\255\220\344\270\262.java" | 21 +++--- ...\346\220\234\347\264\242\346\240\221.java" | 4 +- 17 files changed, 244 insertions(+), 160 deletions(-) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\344\272\214\345\210\206\346\237\245\346\211\276\346\250\241\346\235\277.java" diff --git a/README.md b/README.md index 84f4e1c..f5960e6 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ | [80. 删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/) | 💛 | ✔️ | | [344. 反转字符串](https://leetcode.cn/problems/reverse-string/) | 💚 | ✔️ | | [125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/) | 💚 | ✔️ | -| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 💛 | ❗ | +| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 💛 | ✔️ | | [75. 颜色分类](https://leetcode.cn/problems/sort-colors/) | 💛 | ✔️ | | [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/) | 💚 | ✔️ | | [977. 有序数组的平方](https://leetcode.cn/problems/squares-of-a-sorted-array/) | 💚 | ✔️ | @@ -159,11 +159,11 @@ | [3. 无重复字符的最长子串](https://leetcode.cn/problems/longest-substring-without-repeating-characters/) | 💛 | ✔️ | | [438. 找到字符串中所有字母异位词](https://leetcode.cn/problems/find-all-anagrams-in-a-string/) | 💛 | ✔️ | | [567. 字符串的排列](https://leetcode.cn/problems/permutation-in-string/) | 💛 | ✔️ | -| [76. 最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring/) | ❤️ | ❗ | -| [1658. 将 x 减到 0 的最小操作数](https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/) | 💛 | ❌ | +| [76. 最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring/) | ❤️ | ✔️ | +| [1658. 将 x 减到 0 的最小操作数](https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/) | 💛 | ✔️ | | [713. 乘积小于 K 的子数组](https://leetcode.cn/problems/subarray-product-less-than-k/) | 💛 | ✔️ | | [1004. 最大连续 1 的个数 III](https://leetcode.cn/problems/max-consecutive-ones-iii/) | 💛 | ✔️ | -| [424. 替换后的最长重复字符](https://leetcode.cn/problems/longest-repeating-character-replacement/) | 💛 | ❗ | +| [424. 替换后的最长重复字符](https://leetcode.cn/problems/longest-repeating-character-replacement/) | 💛 | ✔️ | | [217. 存在重复元素](https://leetcode.cn/problems/contains-duplicate/) | 💚 | ✔️ | | [219. 存在重复元素 II](https://leetcode.cn/problems/contains-duplicate-ii/) | 💛 | ✔️ | | [220. 存在重复元素 III](https://leetcode.cn/problems/contains-duplicate-iii/) | ❤️ | ❌ | @@ -178,10 +178,9 @@ | [35. 搜索插入位置](https://leetcode.cn/problems/search-insert-position/) | 💚 | ✔️ | | [704. 二分查找](https://leetcode.cn/problems/binary-search/) | 💚 | ✔️ | | [LCR 172. 统计目标成绩的出现次数](https://leetcode.cn/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/) | 💚 | ✔️ | -| [875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) | 💛 | ❌ | -| [1011. 在 D 天内送达包裹的能力](https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/) | 💛 | ❌ | -| [410. 分割数组的最大值](https://leetcode.cn/problems/split-array-largest-sum/) | 💛 | ❌ | -| [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | 💛 | ❌ | +| [875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) | 💛 | ❗ | +| [1011. 在 D 天内送达包裹的能力](https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/) | 💛 | ✔️ | +| [410. 分割数组的最大值](https://leetcode.cn/problems/split-array-largest-sum/) | ❤️ | ❌ | #### 前缀和数组 @@ -196,8 +195,8 @@ | 题目 | 难度 | 掌握度 | | ----------------------------------------------------------------------------- | ---- | ------ | -| [1094. 拼车](https://leetcode.cn/problems/car-pooling/) | 💛 | ❗ | -| [1109. 航班预订统计](https://leetcode.cn/problems/corporate-flight-bookings/) | 💛 | ❌ | +| [1094. 拼车](https://leetcode.cn/problems/car-pooling/) | 💛 | ✔️ | +| [1109. 航班预订统计](https://leetcode.cn/problems/corporate-flight-bookings/) | 💛 | ✔️ | ### 栈和队列 @@ -212,6 +211,7 @@ | [1670. 设计前中后队列](https://leetcode.cn/problems/design-front-middle-back-queue/) | 💛 | | | [2073. 买票需要的时间](https://leetcode.cn/problems/time-needed-to-buy-tickets/) | 💚 | ✔️ | | [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | 💛 | | +| [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | 💛 | ❌ | #### 栈 @@ -343,7 +343,7 @@ | [450. 删除二叉搜索树中的节点](https://leetcode.cn/problems/delete-node-in-a-bst/) | 💛 | ✔️ | | [700. 二叉搜索树中的搜索](https://leetcode.cn/problems/search-in-a-binary-search-tree/) | 💚 | ✔️ | | [701. 二叉搜索树中的插入操作](https://leetcode.cn/problems/insert-into-a-binary-search-tree/) | 💛 | ✔️ | -| [98. 验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree/) | 💛 | ❗ | +| [98. 验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree/) | 💛 | ✔️ | | [96. 不同的二叉搜索树](https://leetcode.cn/problems/unique-binary-search-trees/) | 💛 | ❌ | | [95. 不同的二叉搜索树 II](https://leetcode.cn/problems/unique-binary-search-trees-ii/) | 💛 | ❌ | | [108. 将有序数组转换为二叉搜索树](https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/) | 💚 | ✔️ | diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" index f302150..0c3678b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" @@ -20,38 +20,40 @@ public static void main(String[] args) { static class Solution { public int splitArray(int[] nums, int k) { - int left = 0; - int right = 1; - for (int w : nums) { - left = Math.max(left, w); - right += w; + return shipWithinDays(nums, k); + } + + public int shipWithinDays(int[] weights, int days) { + int max = 0, sum = 0; + for (int weight : weights) { + max = Math.max(max, weight); + sum += weight; } - int res = 0; + int left = max, right = sum; while (left <= right) { int mid = left + (right - left) / 2; - if (f(nums, mid) <= k) { - res = mid; + if (f(weights, mid) <= days) { + // 需要让 f(x) 的返回值大一些 right = mid - 1; - } else { + } else if (f(weights, mid) > days) { + // 需要让 f(x) 的返回值小一些 left = mid + 1; } } - return res; + return left; } - public int f(int[] nums, int x) { - int i = 0; + // 定义:当运载能力为 x 时,需要 f(x) 天运完所有货物 + // f(x) 随着 x 的增加单调递减 + int f(int[] weights, int x) { int days = 0; - while (i < nums.length) { + for (int i = 0; i < weights.length; ) { // 尽可能多装货物 int cap = x; - while (i < nums.length) { - if (cap < nums[i]) { - break; - } else { - cap -= nums[i]; - } + while (i < weights.length) { + if (cap < weights[i]) break; + else cap -= weights[i]; i++; } days++; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" index 46be717..04d948d 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" @@ -20,22 +20,18 @@ public static void main(String[] args) { static class Solution { public int shipWithinDays(int[] weights, int days) { - int left = 0; - // 注意,right 是开区间,所以额外加一 - int right = 1; - for (int w : weights) { - left = Math.max(left, w); - right += w; + int max = 0, sum = 0; + for (int weight : weights) { + max = Math.max(max, weight); + sum += weight; } - while (left < right) { + int left = max, right = sum; + while (left <= right) { int mid = left + (right - left) / 2; - if (f(weights, mid) == days) { - // 搜索左侧边界,则需要收缩右侧边界 - right = mid; - } else if (f(weights, mid) < days) { + if (f(weights, mid) <= days) { // 需要让 f(x) 的返回值大一些 - right = mid; + right = mid - 1; } else if (f(weights, mid) > days) { // 需要让 f(x) 的返回值小一些 left = mid + 1; @@ -49,13 +45,11 @@ public int shipWithinDays(int[] weights, int days) { int f(int[] weights, int x) { int days = 0; for (int i = 0; i < weights.length; ) { + // 尽可能多装货物 int cap = x; while (i < weights.length) { - if (cap < weights[i]) { - break; - } else { - cap -= weights[i]; - } + if (cap < weights[i]) break; + else cap -= weights[i]; i++; } days++; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" index bae535a..c7b5f17 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" @@ -26,38 +26,28 @@ public static void main(String[] args) { static class Solution { public int minEatingSpeed(int[] piles, int h) { - final int rightBound = 1_000_000_001; - int left = 1, right = rightBound; - while (left < right) { + int left = 1, right = 1_000_000_000; + + // right 是闭区间,所以这里改成 <= + while (left <= right) { int mid = left + (right - left) / 2; - if (f(piles, mid) == h) { - // 搜索左侧边界,则需要收缩右侧边界 - right = mid ; - } else if (f(piles, mid) < h) { - // 需要让 f(x) 的返回值大一些 - right = mid ; + if (f(piles, mid) <= h) { + // right 是闭区间,所以这里用 mid - 1 + right = mid - 1; } else if (f(piles, mid) > h) { - // 需要让 f(x) 的返回值小一些 left = mid + 1; } } - if (left < 0 || left > rightBound) { return -1; } return left; } - public int f(int[] nums, int x) { - int res = 0; + long f(int[] nums, int x) { + long h = 0; for (int num : nums) { - if (num <= x) { - res++; - } else { - res += num / x; - if (num % x != 0) { - res++; - } - } + h += num / x; + if (num % x > 0) { h++; } } - return res; + return h; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" index d39a10e..9d3c672 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" @@ -2,9 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.LinkedList; -import java.util.List; - /** * 498. 对角线遍历 * @@ -33,31 +30,32 @@ public static void main(String[] args) { static class Solution { + // 1. 同一对角线上的元素,满足 i + j = k + // 2. k 的大小,满足递增,从 0 到 m + n - 2 + // 3. 由于,i + j = k -> i = k - j + // i = m - 1 时最大,j 最小;而 k - (m - 1) 必须大于 0 => minJ = max(0, k - (m - 1)) + // i = 0 时最小,j 最大,但不能超过 n - 1 => maxJ = Math.max(k, n -1) public int[] findDiagonalOrder(int[][] mat) { // base case if (mat == null || mat.length == 0) { return new int[0]; } + int idx = 0; int m = mat.length, n = mat[0].length; - List list = new LinkedList<>(); - for (int step = 0; step <= m + n - 2; step++) { - int min = Math.max(step - (m - 1), 0); - int max = Math.min(step, n - 1); - if (step % 2 == 0) { - for (int i = max; i >= min; i--) { - list.add(mat[i][step - i]); + int[] res = new int[m * n]; + for (int k = 0; k < m + n - 1; k++) { + int minJ = Math.max(k - (m - 1), 0); + int maxJ = Math.min(k, n - 1); + if (k % 2 == 0) { + for (int j = minJ; j <= maxJ; j++) { + res[idx++] = mat[k - j][j]; } } else { - for (int i = min; i <= max; i++) { - list.add(mat[i][step - i]); + for (int j = maxJ; j >= minJ; j--) { + res[idx++] = mat[k - j][j]; } } } - - int[] res = new int[list.size()]; - for (int k = 0; k < list.size(); k++) { - res[k] = list.get(k); - } return res; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" index fc55e9b..61ece6f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" @@ -19,25 +19,32 @@ public static void main(String[] args) { { 1, 0, 3, 0, 5 } }); Assertions.assertEquals(8, numMatrix.sumRegion(2, 1, 4, 3)); + Assertions.assertEquals(11, numMatrix.sumRegion(1, 1, 2, 2)); + Assertions.assertEquals(12, numMatrix.sumRegion(1, 2, 2, 4)); } static class NumMatrix { + // preSum[i][j] 记录矩阵 [0, 0, i-1, j-1] 的元素和 private int[][] preSum; public NumMatrix(int[][] matrix) { - final int M = matrix.length; - final int N = matrix[0].length; - preSum = new int[M + 1][N + 1]; - for (int i = 1; i <= M; i++) { - for (int j = 1; j <= N; j++) { - preSum[i][j] = preSum[i][j - 1] + preSum[i - 1][j] - preSum[i - 1][j - 1] + matrix[i - 1][j - 1]; + int m = matrix.length, n = matrix[0].length; + if (m == 0 || n == 0) return; + // 构造前缀和矩阵 + preSum = new int[m + 1][n + 1]; + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= n; j++) { + // 计算每个矩阵 [0, 0, i, j] 的元素和 + preSum[i][j] = preSum[i - 1][j] + preSum[i][j - 1] + matrix[i - 1][j - 1] - preSum[i - 1][j - 1]; } } } - public int sumRegion(int row1, int col1, int row2, int col2) { - return preSum[row2 + 1][col2 + 1] - preSum[row1][col2 + 1] - preSum[row2 + 1][col1] + preSum[row1][col1]; + // 计算子矩阵 [x1, y1, x2, y2] 的元素和 + public int sumRegion(int x1, int y1, int x2, int y2) { + // 目标矩阵之和由四个相邻矩阵运算获得 + return preSum[x2 + 1][y2 + 1] - preSum[x1][y2 + 1] - preSum[x2 + 1][y1] + preSum[x1][y1]; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" index ff5a6dd..6ea1646 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" @@ -16,6 +16,8 @@ public static void main(String[] args) { Assertions.assertFalse(s.carPooling(input, 3)); int[][] input2 = { { 1, 2, 10 }, { 2, 2, 15 } }; Assertions.assertTrue(s.carPooling(input2, 5)); + int[][] input3 = { { 2, 1, 5 }, { 3, 5, 7 } }; + Assertions.assertTrue(s.carPooling(input3, 3)); } static class Solution { @@ -50,10 +52,10 @@ public boolean carPooling(int[][] trips, int capacity) { } // 差分数组工具类 - static class Difference { + class Difference { // 差分数组 - private final int[] diff; + private int[] diff; // 输入一个初始数组,区间操作将在这个数组上进行 public Difference(int[] nums) { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" index 3ed6404..bb51080 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" @@ -24,20 +24,12 @@ public static void main(String[] args) { static class Solution { public int[] corpFlightBookings(int[][] bookings, int n) { - // nums 初始化为全 0 int[] nums = new int[n]; - // 构造差分解法 Difference df = new Difference(nums); - for (int[] booking : bookings) { - // 注意转成数组索引要减一哦 - int i = booking[0] - 1; - int j = booking[1] - 1; - int val = booking[2]; - // 对区间 nums[i..j] 增加 val - df.increment(i, j, val); + int first = booking[0], last = booking[1], seat = booking[2]; + df.increment(first - 1, last - 1, seat); } - // 返回最终的结果数组 return df.result(); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\344\272\214\345\210\206\346\237\245\346\211\276\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\344\272\214\345\210\206\346\237\245\346\211\276\346\250\241\346\235\277.java" new file mode 100644 index 0000000..7f21032 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\344\272\214\345\210\206\346\237\245\346\211\276\346\250\241\346\235\277.java" @@ -0,0 +1,70 @@ +package io.github.dunwu.algorithm.array.template; + +/** + * 二分查找模板 + * + * @author Zhang Peng + * @date 2025-12-08 + */ +public class 二分查找模板 { + + int binary_search(int[] nums, int target) { + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + if (nums[mid] < target) { + left = mid + 1; + } else if (nums[mid] > target) { + right = mid - 1; + } else if (nums[mid] == target) { + // 直接返回 + return mid; + } + } + // 直接返回 + return -1; + } + + int left_bound(int[] nums, int target) { + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + if (nums[mid] < target) { + left = mid + 1; + } else if (nums[mid] > target) { + right = mid - 1; + } else if (nums[mid] == target) { + // 别返回,锁定左侧边界 + right = mid - 1; + } + } + // 判断 target 是否存在于 nums 中 + if (left < 0 || left >= nums.length) { + return -1; + } + // 判断一下 nums[left] 是不是 target + return nums[left] == target ? left : -1; + } + + int right_bound(int[] nums, int target) { + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + if (nums[mid] < target) { + left = mid + 1; + } else if (nums[mid] > target) { + right = mid - 1; + } else if (nums[mid] == target) { + // 别返回,锁定右侧边界 + left = mid + 1; + } + } + // 由于 while 的结束条件是 right == left - 1,且现在在求右边界 + // 所以用 right 替代 left - 1 更好记 + if (right < 0 || right >= nums.length) { + return -1; + } + return nums[right] == target ? right : -1; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\211\346\225\260\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\211\346\225\260\344\271\213\345\222\214.java" index 74922f2..bb147b7 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\211\346\225\260\344\271\213\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\211\346\225\260\344\271\213\345\222\214.java" @@ -28,29 +28,33 @@ static class Solution { public List> threeSum(int[] nums) { if (nums == null || nums.length < 3) { return new ArrayList<>(); } + + // 数组排序 Arrays.sort(nums); + List> res = new ArrayList<>(); for (int i = 0; i < nums.length; i++) { + // 跳过重复元素 - if (i > 0 && nums[i] == nums[i - 1]) continue; + if (i > 0 && nums[i] == nums[i - 1]) { continue; } // 双指针,目标是找到 nums[l] + nums[r] = -nums[i] - int left = i + 1, right = nums.length - 1; int target = -nums[i]; + int l = i + 1, r = nums.length - 1; - while (left < right) { - int sum = nums[left] + nums[right]; + while (l < r) { + int sum = nums[l] + nums[r]; if (sum == target) { - res.add(Arrays.asList(nums[i], nums[left], nums[right])); - left++; - right--; + res.add(Arrays.asList(nums[i], nums[l], nums[r])); + l++; + r--; // 跳过重复元素 - while (left < right && nums[left] == nums[left - 1]) left++; - while (left < right && nums[right] == nums[right + 1]) right--; + while (l < r && nums[l] == nums[l - 1]) l++; + while (l < r && nums[r] == nums[r + 1]) r--; + } else if (sum > target) { + r--; } else if (sum < target) { - left++; - } else { - right--; + l++; } } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" index d891982..c42a437 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" @@ -71,14 +71,11 @@ public String longestPalindrome(String s) { } public String palindrome(String s, int l, int r) { - // 防止索引越界 while (l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r)) { - // 双指针向两边展开 l--; r++; } - // 此时 s[l+1..r-1] 就是最长回文串 return s.substring(l + 1, r); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" index a50a3d0..59232f3 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" @@ -2,7 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.Optional; import java.util.PriorityQueue; /** @@ -15,31 +14,51 @@ public class 有序矩阵中第K小的元素 { public static void main(String[] args) { + Solution s = new Solution(); + int[][] matrix = { { 1, 5, 9 }, { 10, 11, 13 }, { 12, 13, 15 } }; - Assertions.assertEquals(13, kthSmallest(matrix, 8)); + Assertions.assertEquals(13, s.kthSmallest(matrix, 8)); int[][] matrix2 = { { -5 } }; - Assertions.assertEquals(-5, kthSmallest(matrix2, 1)); + Assertions.assertEquals(-5, s.kthSmallest(matrix2, 1)); int[][] matrix3 = { { 1, 2 }, { 1, 3 } }; - Assertions.assertEquals(1, kthSmallest(matrix3, 2)); + Assertions.assertEquals(1, s.kthSmallest(matrix3, 2)); int[][] matrix4 = { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } }; - Assertions.assertEquals(3, kthSmallest(matrix4, 8)); + Assertions.assertEquals(3, s.kthSmallest(matrix4, 8)); } - public static int kthSmallest(int[][] matrix, int n) { - PriorityQueue queue = new PriorityQueue<>((a, b) -> a - b); - for (int[] row : matrix) { - for (int val : row) { - queue.offer(val); + static class Solution { + + public int kthSmallest(int[][] matrix, int k) { + // 存储二元组 (matrix[i][j], i, j) + // i, j 记录当前元素的索引位置,用于生成下一个节点 + PriorityQueue pq = new PriorityQueue<>((a, b) -> { + // 按照元素大小升序排序 + return a[0] - b[0]; + }); + + // 初始化优先级队列,把每一行的第一个元素装进去 + for (int i = 0; i < matrix.length; i++) { + pq.offer(new int[] { matrix[i][0], i, 0 }); } + + int res = -1; + while (!pq.isEmpty() && k > 0) { + int[] cur = pq.poll(); + res = cur[0]; + k--; + + // 链表中的下一个节点加入优先级队列 + int i = cur[1], j = cur[2]; + if (j + 1 < matrix[i].length) { + pq.add(new int[] { matrix[i][j + 1], i, j + 1 }); + } + } + return res; } - Integer num = null; - for (int i = 0; i < n; i++) { - num = queue.poll(); - } - return Optional.ofNullable(num).orElse(0); + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" index e03b04f..d39d1c8 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" @@ -15,15 +15,23 @@ public static void main(String[] args) { Assertions.assertEquals(2, s.minOperations(new int[] { 1, 1, 4, 2, 3 }, 5)); Assertions.assertEquals(-1, s.minOperations(new int[] { 5, 6, 7, 8, 9 }, 4)); Assertions.assertEquals(5, s.minOperations(new int[] { 3, 2, 20, 1, 1, 3 }, 10)); + Assertions.assertEquals(16, s.minOperations(new int[] { 8828, 9581, 49, 9818, 9974, 9869, 9991, + 10000, 10000, 10000, 9999, 9993, 9904, 8819, 1231, 6309 }, 134365)); } static class Solution { + // 【思路】 + // 从边缘删除掉和为 x 的元素,那剩下来的是什么?剩下来的是不是就是 nums 中的一个子数组? + // 让你尽可能少地从边缘删除元素说明什么?是不是就是说剩下来的这个子数组大小尽可能的大? + // 所以,这道题等价于让你寻找 nums 中元素和为 sum(nums) - x 的最长子数组。 + + // 1、当窗口内元素之和小于目标和 target 时,扩大窗口,让窗口内元素和增加。 + // 2、当窗口内元素之和大于目标和 target 时,缩小窗口,让窗口内元素和减小。 + // 3、当窗口内元素之和等于目标和 target 时,找到一个符合条件的子数组,我们想找的是最长的子数组长度。 public int minOperations(int[] nums, int x) { int n = nums.length, sum = 0; - for (int i = 0; i < n; i++) { - sum += nums[i]; - } + for (int num : nums) { sum += num; } // 滑动窗口需要寻找的子数组目标和 int target = sum - x; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" index 343894b..58f6ba0 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" @@ -22,10 +22,10 @@ static class Solution { public int characterReplacement(String s, int k) { int left = 0, right = 0; // 统计窗口中每个字符的出现次数 - int[] charCnt = new int[26]; + int[] windowCharCount = new int[26]; // 记录窗口中字符的最多重复次数 // 记录这个值的意义在于,最划算的替换方法肯定是把其他字符替换成出现次数最多的那个字符 - int windowMaxCnt = 0; + int windowMaxCount = 0; // 记录结果长度 int res = 0; @@ -33,17 +33,16 @@ public int characterReplacement(String s, int k) { while (right < s.length()) { // 扩大窗口 int c = s.charAt(right) - 'A'; - charCnt[c]++; - windowMaxCnt = Math.max(windowMaxCnt, charCnt[c]); + windowCharCount[c]++; + windowMaxCount = Math.max(windowMaxCount, windowCharCount[c]); right++; // 这个 while 换成 if 也可以 - while (right - left - windowMaxCnt > k) { - // 杂牌字符数量 right - left - windowMaxCnt 多于 k + while (right - left - windowMaxCount > k) { + // 杂牌字符数量 right - left - windowMaxCount 多于 k // 此时,k 次替换已经无法把窗口内的字符都替换成相同字符了 // 必须缩小窗口 - int d = s.charAt(left) - 'A'; - charCnt[d]--; + windowCharCount[s.charAt(left) - 'A']--; left++; } // 经过收缩后,此时一定是一个合法的窗口 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" index 1f2eb58..81b42a2 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" @@ -31,9 +31,8 @@ public String minWindow(String s, String t) { need.put(c, need.getOrDefault(c, 0) + 1); } - int left = 0, right = 0; - int valid = 0; + int left = 0, right = 0; // 记录最小覆盖子串的起始索引及长度 int start = 0, len = Integer.MAX_VALUE; while (right < s.length()) { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" index 3fbba47..5a8994b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" @@ -24,13 +24,14 @@ public int longestSubstring(String s, int k) { int len = 0; for (int i = 1; i <= 26; i++) { // 限制窗口中只能有 i 种不同字符 - len = Math.max(len, logestKLetterSubstr(s, k, i)); + len = Math.max(len, longestKLetterSubstring(s, k, i)); } return len; } // 寻找 s 中含有 count 种字符,且每种字符出现次数都大于 k 的子串 - int logestKLetterSubstr(String s, int k, int count) { + public int longestKLetterSubstring(String s, int k, int count) { + // 记录答案 int res = 0; // 快慢指针维护滑动窗口,左闭右开区间 @@ -44,13 +45,13 @@ int logestKLetterSubstr(String s, int k, int count) { // 滑动窗口代码模板 while (right < s.length()) { // 移入字符,扩大窗口 - char c = s.charAt(right); - if (windowCount[c - 'a'] == 0) { + int c = s.charAt(right) - 'a'; + if (windowCount[c] == 0) { // 窗口中新增了一种字符 windowUniqueCount++; } - windowCount[c - 'a']++; - if (windowCount[c - 'a'] == k) { + windowCount[c]++; + if (windowCount[c] == k) { // 窗口中新增了一种达标的字符 windowValidCount++; } @@ -59,13 +60,13 @@ int logestKLetterSubstr(String s, int k, int count) { // 当窗口中字符种类大于 count 时,缩小窗口 while (windowUniqueCount > count) { // 移出字符,缩小窗口 - char d = s.charAt(left); - if (windowCount[d - 'a'] == k) { + int d = s.charAt(left) - 'a'; + if (windowCount[d] == k) { // 窗口中减少了一种达标的字符 windowValidCount--; } - windowCount[d - 'a']--; - if (windowCount[d - 'a'] == 0) { + windowCount[d]--; + if (windowCount[d] == 0) { // 窗口中减少了一种字符 windowUniqueCount--; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" index 5fb168e..1177d66 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" @@ -17,6 +17,7 @@ public static void main(String[] args) { Assertions.assertFalse(s.isValidBST(TreeNode.buildTree(5, 1, 4, null, null, 3, 6))); Assertions.assertFalse(s.isValidBST(TreeNode.buildTree(2, 2, 2))); Assertions.assertFalse(s.isValidBST(TreeNode.buildTree(5, 4, 6, null, null, 3, 7))); + Assertions.assertTrue(s.isValidBST(TreeNode.buildTree(3, 1, 5, 0, 2, 4, 6))); } static class Solution { @@ -33,7 +34,8 @@ boolean isValidBST(TreeNode root, TreeNode min, TreeNode max) { if (min != null && root.val <= min.val) return false; if (max != null && root.val >= max.val) return false; // 限定左子树的最大值是 root.val,右子树的最小值是 root.val - return isValidBST(root.left, min, root) && isValidBST(root.right, root, max); + return isValidBST(root.left, min, root) + && isValidBST(root.right, root, max); } } From d9cf07d23469249ad90326ddd1b257c1b25334ad Mon Sep 17 00:00:00 2001 From: dunwu Date: Mon, 15 Dec 2025 08:24:04 +0800 Subject: [PATCH 20/21] =?UTF-8?q?feat:=20leetcode=20=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 129 ++++----- .../dfs/N\347\232\207\345\220\216.java" | 72 ----- .../dfs/N\347\232\207\345\220\216II.java" | 79 ------ .../permutation_combination/package-info.java | 7 + ...\345\205\250\346\216\222\345\210\227.java" | 77 ++++++ ...345\205\250\346\216\222\345\210\2272.java" | 76 ++++++ .../\345\255\220\351\233\206.java" | 70 +++++ .../\345\255\220\351\233\2062.java" | 71 +++++ .../\347\273\204\345\220\210.java" | 61 +++++ ...\345\220\210\346\200\273\345\222\214.java" | 74 ++++++ ...345\220\210\346\200\273\345\222\2142.java" | 86 ++++++ ...345\220\210\346\200\273\345\222\2143.java" | 83 ++++++ .../sudoku/N\347\232\207\345\220\216.java" | 96 +++++++ .../sudoku/N\347\232\207\345\220\2162.java" | 94 +++++++ .../algorithm/dfs/sudoku/package-info.java | 7 + ...\350\247\243\346\225\260\347\213\254.java" | 249 ++++++++++++++++++ ...\346\263\225\346\250\241\346\235\277.java" | 20 ++ ...\347\232\204\346\216\222\345\210\227.java" | 69 +++++ ...\345\205\250\346\216\222\345\210\227.java" | 54 ---- ...345\205\250\346\216\222\345\210\2272.java" | 59 ----- ...\345\233\236\346\226\207\344\270\262.java" | 72 +++++ ...\350\257\215\346\220\234\347\264\242.java" | 70 +++++ ...45\216\237IP\345\234\260\345\235\200.java" | 88 +++++++ .../dfs/\345\255\220\351\233\206.java" | 59 ----- .../dfs/\345\255\220\351\233\2062.java" | 76 ------ ...\351\233\267\347\274\226\347\240\201.java" | 64 +++++ ...\346\257\215\347\273\204\345\220\210.java" | 33 ++- .../dfs/\347\273\204\345\220\210.java" | 58 ---- ...\345\220\210\346\200\273\345\222\214.java" | 66 ----- ...345\220\210\346\200\273\345\222\2142.java" | 79 ------ ...345\220\210\346\200\273\345\222\2143.java" | 85 ------ ...\350\247\243\346\225\260\347\213\254.java" | 88 ------- ...\347\232\204\346\225\260\345\255\227.java" | 52 +++- ...\345\255\220\345\272\217\345\210\227.java" | 76 ++++++ ...\350\267\257\345\276\204\345\222\214.java" | 4 +- ...\344\272\214\345\210\206\345\233\276.java" | 3 +- ...\344\272\214\345\210\206\346\263\225.java" | 40 +-- ...\347\232\204\350\267\257\345\276\204.java" | 16 +- ...350\257\276\347\250\213\350\241\2502.java" | 2 +- ...\344\275\231\350\277\236\346\216\245.java" | 14 +- ...\347\232\204\345\214\272\345\237\237.java" | 58 ++-- ...\346\220\234\347\264\242\346\240\221.java" | 32 ++- ...346\220\234\347\264\242\346\240\2212.java" | 12 +- ...\351\224\256\345\200\274\345\222\214.java" | 3 +- ...\345\205\261\347\245\226\345\205\210.java" | 9 +- ...\345\260\217\350\267\235\347\246\273.java" | 36 ++- ...\347\202\271\346\210\220\346\236\227.java" | 33 +-- ...\344\272\214\345\217\211\346\240\221.java" | 54 ++-- ...344\272\214\345\217\211\346\240\2212.java" | 16 +- ...\344\272\214\345\217\211\346\240\221.java" | 10 +- ...\345\205\261\347\245\226\345\205\210.java" | 69 +++-- .../dunwu/algorithm/util/ArrayUtil.java | 43 ++- 52 files changed, 1898 insertions(+), 1055 deletions(-) delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/N\347\232\207\345\220\216.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/N\347\232\207\345\220\216II.java" create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/package-info.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\205\250\346\216\222\345\210\227.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\205\250\346\216\222\345\210\2272.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\255\220\351\233\206.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\255\220\351\233\2062.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\214.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\2142.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\2143.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/N\347\232\207\345\220\216.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/N\347\232\207\345\220\2162.java" create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/package-info.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/\350\247\243\346\225\260\347\213\254.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/template/\345\233\236\346\272\257\347\256\227\346\263\225\346\250\241\346\235\277.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\344\274\230\347\276\216\347\232\204\346\216\222\345\210\227.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\227.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\2272.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\210\206\345\211\262\345\233\236\346\226\207\344\270\262.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\215\225\350\257\215\346\220\234\347\264\242.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\244\215\345\216\237IP\345\234\260\345\235\200.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\206.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\2062.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\346\240\274\351\233\267\347\274\226\347\240\201.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\214.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2142.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2143.java" delete mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\247\243\346\225\260\347\213\254.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\351\235\236\351\200\222\345\207\217\345\255\220\345\272\217\345\210\227.java" diff --git a/README.md b/README.md index f5960e6..67f1048 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ | [80. 删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/) | 💛 | ✔️ | | [344. 反转字符串](https://leetcode.cn/problems/reverse-string/) | 💚 | ✔️ | | [125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/) | 💚 | ✔️ | -| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 💛 | ✔️ | +| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 💛 | ✔️ | | [75. 颜色分类](https://leetcode.cn/problems/sort-colors/) | 💛 | ✔️ | | [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/) | 💚 | ✔️ | | [977. 有序数组的平方](https://leetcode.cn/problems/squares-of-a-sorted-array/) | 💚 | ✔️ | @@ -159,11 +159,11 @@ | [3. 无重复字符的最长子串](https://leetcode.cn/problems/longest-substring-without-repeating-characters/) | 💛 | ✔️ | | [438. 找到字符串中所有字母异位词](https://leetcode.cn/problems/find-all-anagrams-in-a-string/) | 💛 | ✔️ | | [567. 字符串的排列](https://leetcode.cn/problems/permutation-in-string/) | 💛 | ✔️ | -| [76. 最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring/) | ❤️ | ✔️ | -| [1658. 将 x 减到 0 的最小操作数](https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/) | 💛 | ✔️ | +| [76. 最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring/) | ❤️ | ✔️ | +| [1658. 将 x 减到 0 的最小操作数](https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/) | 💛 | ✔️ | | [713. 乘积小于 K 的子数组](https://leetcode.cn/problems/subarray-product-less-than-k/) | 💛 | ✔️ | | [1004. 最大连续 1 的个数 III](https://leetcode.cn/problems/max-consecutive-ones-iii/) | 💛 | ✔️ | -| [424. 替换后的最长重复字符](https://leetcode.cn/problems/longest-repeating-character-replacement/) | 💛 | ✔️ | +| [424. 替换后的最长重复字符](https://leetcode.cn/problems/longest-repeating-character-replacement/) | 💛 | ✔️ | | [217. 存在重复元素](https://leetcode.cn/problems/contains-duplicate/) | 💚 | ✔️ | | [219. 存在重复元素 II](https://leetcode.cn/problems/contains-duplicate-ii/) | 💛 | ✔️ | | [220. 存在重复元素 III](https://leetcode.cn/problems/contains-duplicate-iii/) | ❤️ | ❌ | @@ -178,9 +178,9 @@ | [35. 搜索插入位置](https://leetcode.cn/problems/search-insert-position/) | 💚 | ✔️ | | [704. 二分查找](https://leetcode.cn/problems/binary-search/) | 💚 | ✔️ | | [LCR 172. 统计目标成绩的出现次数](https://leetcode.cn/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/) | 💚 | ✔️ | -| [875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) | 💛 | ❗ | -| [1011. 在 D 天内送达包裹的能力](https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/) | 💛 | ✔️ | -| [410. 分割数组的最大值](https://leetcode.cn/problems/split-array-largest-sum/) | ❤️ | ❌ | +| [875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) | 💛 | ❗ | +| [1011. 在 D 天内送达包裹的能力](https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/) | 💛 | ✔️ | +| [410. 分割数组的最大值](https://leetcode.cn/problems/split-array-largest-sum/) | ❤️ | ❌ | #### 前缀和数组 @@ -195,23 +195,23 @@ | 题目 | 难度 | 掌握度 | | ----------------------------------------------------------------------------- | ---- | ------ | -| [1094. 拼车](https://leetcode.cn/problems/car-pooling/) | 💛 | ✔️ | -| [1109. 航班预订统计](https://leetcode.cn/problems/corporate-flight-bookings/) | 💛 | ✔️ | +| [1094. 拼车](https://leetcode.cn/problems/car-pooling/) | 💛 | ✔️ | +| [1109. 航班预订统计](https://leetcode.cn/problems/corporate-flight-bookings/) | 💛 | ✔️ | ### 栈和队列 #### 队列 -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------------------------------------- | ---- | ------ | -| [225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/) | 💚 | ✔️ | -| [933. 最近的请求次数](https://leetcode.cn/problems/number-of-recent-calls/) | 💚 | ❗ | -| [622. 设计循环队列](https://leetcode.cn/problems/design-circular-queue/) | 💛 | ❌ | -| [641. 设计循环双端队列](https://leetcode.cn/problems/design-circular-deque/) | 💛 | | -| [1670. 设计前中后队列](https://leetcode.cn/problems/design-front-middle-back-queue/) | 💛 | | -| [2073. 买票需要的时间](https://leetcode.cn/problems/time-needed-to-buy-tickets/) | 💚 | ✔️ | -| [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | 💛 | | -| [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | 💛 | ❌ | +| 题目 | 难度 | 掌握度 | +| ----------------------------------------------------------------------------------------------------- | ---- | ------ | +| [225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/) | 💚 | ✔️ | +| [933. 最近的请求次数](https://leetcode.cn/problems/number-of-recent-calls/) | 💚 | ❗ | +| [622. 设计循环队列](https://leetcode.cn/problems/design-circular-queue/) | 💛 | ❌ | +| [641. 设计循环双端队列](https://leetcode.cn/problems/design-circular-deque/) | 💛 | | +| [1670. 设计前中后队列](https://leetcode.cn/problems/design-front-middle-back-queue/) | 💛 | | +| [2073. 买票需要的时间](https://leetcode.cn/problems/time-needed-to-buy-tickets/) | 💚 | ✔️ | +| [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | 💛 | | +| [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | 💛 | ❌ | #### 栈 @@ -308,8 +308,9 @@ | [1110. 删点成林](https://leetcode.cn/problems/delete-nodes-and-return-forest/) | 💛 | ❌ | | [100. 相同的树](https://leetcode.cn/problems/same-tree/) | 💛 | ✔️ | | [101. 对称二叉树](https://leetcode.cn/problems/symmetric-tree/) | 💛 | ✔️ | -| [951. 翻转等价二叉树](https://leetcode.cn/problems/flip-equivalent-binary-trees/) | 💛 | ❌ | +| [951. 翻转等价二叉树](https://leetcode.cn/problems/flip-equivalent-binary-trees/) | 💛 | ✔️ | | [124. 二叉树中的最大路径和](https://leetcode.cn/problems/binary-tree-maximum-path-sum/) | ❤️ | ❌ | +| [236. 二叉树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/) | 💛 | ❌ | #### 用「层序遍历」思维解题 @@ -343,11 +344,11 @@ | [450. 删除二叉搜索树中的节点](https://leetcode.cn/problems/delete-node-in-a-bst/) | 💛 | ✔️ | | [700. 二叉搜索树中的搜索](https://leetcode.cn/problems/search-in-a-binary-search-tree/) | 💚 | ✔️ | | [701. 二叉搜索树中的插入操作](https://leetcode.cn/problems/insert-into-a-binary-search-tree/) | 💛 | ✔️ | -| [98. 验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree/) | 💛 | ✔️ | +| [98. 验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree/) | 💛 | ✔️ | | [96. 不同的二叉搜索树](https://leetcode.cn/problems/unique-binary-search-trees/) | 💛 | ❌ | | [95. 不同的二叉搜索树 II](https://leetcode.cn/problems/unique-binary-search-trees-ii/) | 💛 | ❌ | | [108. 将有序数组转换为二叉搜索树](https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/) | 💚 | ✔️ | -| [783. 二叉搜索树节点最小距离](https://leetcode.cn/problems/minimum-distance-between-bst-nodes/) | 💚 | ❌ | +| [783. 二叉搜索树节点最小距离](https://leetcode.cn/problems/minimum-distance-between-bst-nodes/) | 💚 | ✔️ | | [235. 二叉搜索树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/) | 💛 | ❌ | | [1373. 二叉搜索子树的最大键值和](https://leetcode.cn/problems/maximum-sum-bst-in-binary-tree/) | ❤️ | ❌ | @@ -366,7 +367,7 @@ | 题目 | 难度 | 掌握度 | | ------------------------------------------------------------------------------------ | ---- | ------ | -| [797. 所有可能的路径](https://leetcode.cn/problems/all-paths-from-source-to-target/) | 💛 | ❌ | +| [797. 所有可能的路径](https://leetcode.cn/problems/all-paths-from-source-to-target/) | 💛 | ❗ | #### 环检测及拓扑排序算法 @@ -380,15 +381,15 @@ | 题目 | 难度 | 掌握度 | | :---------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | | [785. 判断二分图](https://leetcode.cn/problems/is-graph-bipartite/)
[LCR 106. 判断二分图](https://leetcode.cn/problems/vEAB3K/) | 💛 | ❌ | -| [886. 可能的二分法](https://leetcode.cn/problems/possible-bipartition/) | 💛 | ❌ | +| [886. 可能的二分法](https://leetcode.cn/problems/possible-bipartition/) | 💛 | ❗ | #### 并查集算法 | 题目 | 难度 | 掌握度 | | :-------------------------------------------------------------------------------------------- | ---- | ------ | | [130. 被围绕的区域](https://leetcode.cn/problems/surrounded-regions/) | 💛 | ❌ | -| [684. 冗余连接](https://leetcode.cn/problems/redundant-connection/) | 💛 | ❗ | -| [990. 等式方程的可满足性](https://leetcode.cn/problems/satisfiability-of-equality-equations/) | 💛 | ❗ | +| [684. 冗余连接](https://leetcode.cn/problems/redundant-connection/) | 💛 | ✔️ | +| [990. 等式方程的可满足性](https://leetcode.cn/problems/satisfiability-of-equality-equations/) | 💛 | ✔️ | #### Dijkstra 算法 @@ -400,53 +401,55 @@ | [787. K 站中转内最便宜的航班](https://leetcode.cn/problems/cheapest-flights-within-k-stops/) | 💛 | ❌ | | [1368. 使网格图至少有一条有效路径的最小代价](https://leetcode.cn/problems/minimum-cost-to-make-at-least-one-valid-path-in-a-grid/) | ❤️ | ❌ | -### DFS +### DFS / 回溯算法 -子集、组合、排列相关问题,都可以考虑使用回溯算法求解。 +#### 排列、组合、子集问题 -#### 数独、N 皇后问题 +子集、组合、排列相关问题,都可以考虑使用回溯算法求解。 -| 题目 | 掌握度 | -| :-------------------------------------------------------- | ------ | -| [37. 解数独](https://leetcode.cn/problems/sudoku-solver/) | | -| [51. N 皇后](https://leetcode.cn/problems/n-queens/) | | -| [52. N皇后 II](https://leetcode.cn/problems/n-queens-ii/) | | +| 题目 | 难度 | 掌握度 | +| :--------------------------------------------------------------------- | ---- | ------ | +| [46. 全排列](https://leetcode.cn/problems/permutations/) | 💛 | ❗ | +| [47. 全排列 II](https://leetcode.cn/problems/permutations-ii/) | 💛 | ❗ | +| [78. 子集](https://leetcode.cn/problems/subsets/) | 💛 | ❗ | +| [90. 子集 II](https://leetcode.cn/problems/subsets-ii/) | 💛 | ❗ | +| [77. 组合](https://leetcode.cn/problems/combinations/) | 💛 | ❗ | +| [39. 组合总和](https://leetcode.cn/problems/combination-sum/) | 💛 | ❗ | +| [40. 组合总和 II](https://leetcode.cn/problems/combination-sum-ii/) | 💛 | ❗ | +| [216. 组合总和 III](https://leetcode.cn/problems/combination-sum-iii/) | 💛 | ❗ | -#### 排列、组合、子集问题 +#### 岛屿问题 -| 题目 | 掌握度 | -| :--------------------------------------------------------------------- | ------ | -| [77. 组合](https://leetcode.cn/problems/combinations/) | ❌ | -| [78. 子集](https://leetcode.cn/problems/subsets/) | ❌ | -| [90. 子集 II](https://leetcode.cn/problems/subsets-ii/) | ❌ | -| [39. 组合总和](https://leetcode.cn/problems/combination-sum/) | ❌ | -| [40. 组合总和 II](https://leetcode.cn/problems/combination-sum-ii/) | ❌ | -| [216. 组合总和 III](https://leetcode.cn/problems/combination-sum-iii/) | ❌ | -| [46. 全排列](https://leetcode.cn/problems/permutations/) | ❌ | -| [47. 全排列 II](https://leetcode.cn/problems/permutations-ii/) | ❌ | +| 题目 | 难度 | 掌握度 | +| :--------------------------------------------------------------------------------- | ---- | ------ | +| [1020. 飞地的数量](https://leetcode.cn/problems/number-of-enclaves/) | 💛 | ❌ | +| [1254. 统计封闭岛屿的数目](https://leetcode.cn/problems/number-of-closed-islands/) | 💛 | ❌ | +| [1905. 统计子岛屿](https://leetcode.cn/problems/count-sub-islands/) | 💛 | ❌ | +| [200. 岛屿数量](https://leetcode.cn/problems/number-of-islands/) | 💛 | ❌ | +| [695. 岛屿的最大面积](https://leetcode.cn/problems/max-area-of-island/) | 💛 | ❌ | -#### 岛屿问题 +#### 数独、N 皇后问题 -| 题目 | 掌握度 | -| :--------------------------------------------------------------------------------- | ------ | -| [1020. 飞地的数量](https://leetcode.cn/problems/number-of-enclaves/) | ❌ | -| [1254. 统计封闭岛屿的数目](https://leetcode.cn/problems/number-of-closed-islands/) | ❌ | -| [1905. 统计子岛屿](https://leetcode.cn/problems/count-sub-islands/) | ❌ | -| [200. 岛屿数量](https://leetcode.cn/problems/number-of-islands/) | ❌ | -| [695. 岛屿的最大面积](https://leetcode.cn/problems/max-area-of-island/) | ❌ | -| [694. 不同岛屿的数量](https://leetcode.cn/problems/number-of-distinct-islands/)🔒 | | +| 题目 | 难度 | 掌握度 | +| :-------------------------------------------------------- | ---- | ------ | +| [37. 解数独](https://leetcode.cn/problems/sudoku-solver/) | ❤️ | ❌ | +| [51. N 皇后](https://leetcode.cn/problems/n-queens/) | ❤️ | ❌ | +| [52. N皇后 II](https://leetcode.cn/problems/n-queens-ii/) | ❤️ | ❌ | #### 练习 -| 题目 | 掌握度 | -| :----------------------------------------------------------------------------------------------- | ------ | -| [967. 连续差相同的数字](https://leetcode.cn/problems/numbers-with-same-consecutive-differences/) | ❌ | -| [491. 递增子序列](https://leetcode.cn/problems/non-decreasing-subsequences/) | | -| [980. 不同路径 III](https://leetcode.cn/problems/unique-paths-iii/) | | -| [131. 分割回文串](https://leetcode.cn/problems/palindrome-partitioning/) | | -| [93. 复原 IP 地址](https://leetcode.cn/problems/restore-ip-addresses/) | | -| [17. 电话号码的字母组合](https://leetcode.cn/problems/letter-combinations-of-a-phone-number/) | ❌ | -| [79. 单词搜索](https://leetcode.cn/problems/word-search/) | | +| 题目 | 难度 | 掌握度 | +| :----------------------------------------------------------------------------------------------- | ---- | ------ | +| [967. 连续差相同的数字](https://leetcode.cn/problems/numbers-with-same-consecutive-differences/) | 💛 | ❌ | +| [491. 非递减子序列](https://leetcode.cn/problems/non-decreasing-subsequences/) | 💛 | ❌ | +| [980. 不同路径 III](https://leetcode.cn/problems/unique-paths-iii/) | ❤️ | ❌ | +| [526. 优美的排列](https://leetcode.cn/problems/beautiful-arrangement/) | 💛 | ❌ | +| [131. 分割回文串](https://leetcode.cn/problems/palindrome-partitioning/) | 💛 | ❌ | +| [93. 复原 IP 地址](https://leetcode.cn/problems/restore-ip-addresses/) | 💛 | ❌ | +| [89. 格雷编码](https://leetcode.cn/problems/gray-code/) | 💛 | ❌ | +| [17. 电话号码的字母组合](https://leetcode.cn/problems/letter-combinations-of-a-phone-number/) | 💛 | ❌ | +| [79. 单词搜索](https://leetcode.cn/problems/word-search/) | 💛 | ❌ | +| [473. 火柴拼正方形](https://leetcode.cn/problems/matchsticks-to-square/) | 💛 | ❌ | ### BFS diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/N\347\232\207\345\220\216.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/N\347\232\207\345\220\216.java" deleted file mode 100644 index 60f82e0..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/N\347\232\207\345\220\216.java" +++ /dev/null @@ -1,72 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Zhang Peng - * @since 2020-07-04 - * @see 51. N皇后 - */ -public class N皇后 { - - int[] cols; - int[] first; - int[] second; - int[] queens; - List> output = new ArrayList<>(); - - public static void main(String[] args) { - N皇后 demo = new N皇后(); - List> result = demo.solveNQueens(5); - result.forEach(System.out::println); - } - - public List> solveNQueens(int n) { - queens = new int[n]; - cols = new int[n]; - first = new int[2 * n]; - second = new int[2 * n]; - backtrack(n, 0); - return output; - } - - public void backtrack(int n, int row) { - if (row >= n) { return; } - for (int col = 0; col < n; col++) { - if (cols[col] == 1 || first[row + col] == 1 || second[row - col + n - 1] == 1) { continue;} - - queens[row] = col; - cols[col] = 1; - first[row + col] = 1; - second[row - col + n - 1] = 1; - - backtrack(n, row + 1); - if (row == n - 1) { - output.add(addSolution(n)); - } - - queens[row] = 0; - cols[col] = 0; - first[row + col] = 0; - second[row - col + n - 1] = 0; - } - } - - public List addSolution(int n) { - List res = new ArrayList<>(); - for (int i = 0; i < n; i++) { - StringBuilder sb = new StringBuilder(); - for (int j = 0; j < n; j++) { - if (i == queens[j]) { - sb.append("Q"); - } else { - sb.append("."); - } - } - res.add(sb.toString()); - } - return res; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/N\347\232\207\345\220\216II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/N\347\232\207\345\220\216II.java" deleted file mode 100644 index 181842a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/N\347\232\207\345\220\216II.java" +++ /dev/null @@ -1,79 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Zhang Peng - * @see 52. N皇后II - * @since 2020-07-04 - */ -public class N皇后II { - - int[] cols; - int[] first; - int[] second; - int[] queens; - List> output = new ArrayList<>(); - - public static void main(String[] args) { - N皇后II demo = new N皇后II(); - int result = demo.totalNQueens(4); - Assertions.assertEquals(2, result); - } - - public int totalNQueens(int n) { - List> lists = solveNQueens(n); - return lists.size(); - } - - public List> solveNQueens(int n) { - queens = new int[n]; - cols = new int[n]; - first = new int[2 * n]; - second = new int[2 * n]; - backtrack(n, 0); - return output; - } - - public void backtrack(int n, int row) { - if (row >= n) { return; } - for (int col = 0; col < n; col++) { - if (cols[col] == 1 || first[row + col] == 1 || second[row - col + n - 1] == 1) { continue;} - - queens[row] = col; - cols[col] = 1; - first[row + col] = 1; - second[row - col + n - 1] = 1; - - backtrack(n, row + 1); - if (row == n - 1) { - output.add(addSolution(n)); - } - - queens[row] = 0; - cols[col] = 0; - first[row + col] = 0; - second[row - col + n - 1] = 0; - } - } - - public List addSolution(int n) { - List res = new ArrayList<>(); - for (int i = 0; i < n; i++) { - StringBuilder sb = new StringBuilder(); - for (int j = 0; j < n; j++) { - if (i == queens[j]) { - sb.append("Q"); - } else { - sb.append("."); - } - } - res.add(sb.toString()); - } - return res; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/package-info.java new file mode 100644 index 0000000..3192edb --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/package-info.java @@ -0,0 +1,7 @@ +/** + * 通过回溯算法解决排列、组合、子集类型的问题 + * + * @author Zhang Peng + * @date 2025-12-13 + */ +package io.github.dunwu.algorithm.dfs.permutation_combination; \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\205\250\346\216\222\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\205\250\346\216\222\345\210\227.java" new file mode 100644 index 0000000..6062839 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\205\250\346\216\222\345\210\227.java" @@ -0,0 +1,77 @@ +package io.github.dunwu.algorithm.dfs.permutation_combination; + +import cn.hutool.core.collection.CollectionUtil; +import io.github.dunwu.algorithm.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 46. 全排列 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 全排列 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[][] expect = { { 1, 2, 3 }, { 1, 3, 2 }, { 2, 1, 3 }, { 2, 3, 1 }, { 3, 1, 2 }, { 3, 2, 1 } }; + int[][] expect2 = { { 0, 1 }, { 1, 0 } }; + Assertions.assertArrayEquals(expect, ArrayUtil.toIntMatrixArray(s.permute(new int[] { 1, 2, 3 }))); + Assertions.assertArrayEquals(expect2, ArrayUtil.toIntMatrixArray(s.permute(new int[] { 0, 1 }))); + Assertions.assertArrayEquals(new int[][] { { 1 } }, ArrayUtil.toIntMatrixArray(s.permute(new int[] { 1 }))); + } + + static class Solution { + + // 「路径」中的元素会被标记为 true,避免重复使用 + boolean[] visited; + // 记录「路径」 + LinkedList path; + List> res; + + // 主函数,输入一组不重复的数字,返回它们的全排列 + List> permute(int[] nums) { + visited = new boolean[nums.length]; + path = new LinkedList<>(); + res = new LinkedList<>(); + backtrack(nums); + return res; + } + + // 路径:记录在 path 中 + // 选择列表:nums 中不存在于 path 的那些元素(visited[i] 为 false) + // 结束条件:nums 中的元素全都在 path 中出现 + void backtrack(int[] nums) { + // 【结束】【前序】到达决策树叶子节点,可以记录结果 + if (path.size() == nums.length) { + res.add(new LinkedList<>(path)); + System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); + return; + } + + for (int i = 0; i < nums.length; i++) { + + // 排除不合法的选择 + // nums[i] 已经在 path 中,跳过 + if (visited[i]) { continue; } + + // 【选择】 + path.add(nums[i]); + visited[i] = true; + System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); + + // 【回溯】 + backtrack(nums); + + // 【取消选择】 + path.removeLast(); + visited[i] = false; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\205\250\346\216\222\345\210\2272.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\205\250\346\216\222\345\210\2272.java" new file mode 100644 index 0000000..038cdda --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\205\250\346\216\222\345\210\2272.java" @@ -0,0 +1,76 @@ +package io.github.dunwu.algorithm.dfs.permutation_combination; + +import cn.hutool.core.collection.CollectionUtil; +import io.github.dunwu.algorithm.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 47. 全排列 II + * LCR 084. 全排列 II + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 全排列2 { + + public static void main(String[] args) { + Solution s = new Solution(); + + int[][] expect = { { 1, 1, 2 }, { 1, 2, 1 }, { 2, 1, 1 } }; + Assertions.assertArrayEquals(expect, ArrayUtil.toIntMatrixArray(s.permuteUnique(new int[] { 1, 1, 2 }))); + + int[][] expect2 = { { 1, 2, 3 }, { 1, 3, 2 }, { 2, 1, 3 }, { 2, 3, 1 }, { 3, 1, 2 }, { 3, 2, 1 } }; + Assertions.assertArrayEquals(expect2, ArrayUtil.toIntMatrixArray(s.permuteUnique(new int[] { 1, 2, 3 }))); + } + + static class Solution { + + private boolean[] visited; + private List path; + private List> res; + + public List> permuteUnique(int[] nums) { + visited = new boolean[nums.length]; + path = new LinkedList<>(); + res = new LinkedList<>(); + Arrays.sort(nums); + backtrack(nums); + return res; + } + + public void backtrack(int[] nums) { + + // 【结束】【前序】到达决策树叶子节点,可以记录结果 + if (path.size() == nums.length) { + res.add(new LinkedList<>(path)); + System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); + } + + for (int i = 0; i < nums.length; i++) { + + // 排除不合法的选择 + if (visited[i]) { continue; } + // 剪枝逻辑,固定相同的元素在排列中的相对位置 + if (i > 0 && nums[i] == nums[i - 1] && !visited[i - 1]) { continue; } + + // 【选择】 + visited[i] = true; + path.add(nums[i]); + System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); + + // 【回溯】 + backtrack(nums); + + // 【取消选择】 + path.remove(path.size() - 1); + visited[i] = false; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\255\220\351\233\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\255\220\351\233\206.java" new file mode 100644 index 0000000..ce2377e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\255\220\351\233\206.java" @@ -0,0 +1,70 @@ +package io.github.dunwu.algorithm.dfs.permutation_combination; + +import cn.hutool.core.collection.CollectionUtil; +import io.github.dunwu.algorithm.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 78. 子集 + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 子集 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[][] expect = { {}, { 1 }, { 1, 2 }, { 1, 2, 3 }, { 1, 3 }, { 2 }, { 2, 3 }, { 3 } }; + Assertions.assertArrayEquals(expect, ArrayUtil.toIntMatrixArray(s.subsets(new int[] { 1, 2, 3 }))); + Assertions.assertArrayEquals(new int[][] { {}, { 0 } }, ArrayUtil.toIntMatrixArray(s.subsets(new int[] { 0 }))); + } + + static class Solution { + + private boolean[] visited; + private List path; + private List> res; + + // 主函数 + public List> subsets(int[] nums) { + visited = new boolean[nums.length]; + path = new LinkedList<>(); + res = new LinkedList<>(); + Arrays.sort(nums); + backtrack(nums, 0); + return res; + } + + // 回溯算法核心函数,遍历子集问题的回溯树 + public void backtrack(int[] nums, int start) { + + // 【结束】【前序】到达决策树叶子节点,可以记录结果 + res.add(new LinkedList<>(path)); + System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); + + for (int i = start; i < nums.length; i++) { + + // 排除不合法的选择 + if (visited[i]) { continue; } + + // 【选择】 + visited[i] = true; + path.add(nums[i]); + System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); + + // 【回溯】 + backtrack(nums, i + 1); + + // 【取消选择】 + path.remove(path.size() - 1); + visited[i] = false; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\255\220\351\233\2062.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\255\220\351\233\2062.java" new file mode 100644 index 0000000..d09fb5e --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\255\220\351\233\2062.java" @@ -0,0 +1,71 @@ +package io.github.dunwu.algorithm.dfs.permutation_combination; + +import cn.hutool.core.collection.CollectionUtil; +import io.github.dunwu.algorithm.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 90. 子集 II + *

+ * 元素可重复,不可复选 + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 子集2 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + int[][] expect = { {}, { 1 }, { 1, 2 }, { 1, 2, 2 }, { 2 }, { 2, 2 } }; + Assertions.assertArrayEquals(expect, ArrayUtil.toIntMatrixArray(s.subsetsWithDup(new int[] { 1, 2, 2 }))); + + int[][] expect2 = { {}, { 0 } }; + Assertions.assertArrayEquals(expect2, ArrayUtil.toIntMatrixArray(s.subsetsWithDup(new int[] { 0 }))); + } + + static class Solution { + + private List> res; + private LinkedList path; + + public List> subsetsWithDup(int[] nums) { + path = new LinkedList<>(); + res = new LinkedList<>(); + // 先排序,让相同的元素靠在一起 + Arrays.sort(nums); + backtrack(nums, 0); + return res; + } + + public void backtrack(int[] nums, int start) { + + // 【结束】 + res.add(new LinkedList<>(path)); + System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); + + for (int i = start; i < nums.length; i++) { + + // 剪枝逻辑,值相同的相邻树枝,只遍历第一条 + if (i > start && nums[i] == nums[i - 1]) continue; + + // 【选择】 + path.add(nums[i]); + System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); + + // 【回溯】 + backtrack(nums, i + 1); + + // 【取消选择】 + path.remove(path.size() - 1); + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210.java" new file mode 100644 index 0000000..c29d190 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210.java" @@ -0,0 +1,61 @@ +package io.github.dunwu.algorithm.dfs.permutation_combination; + +import cn.hutool.core.collection.CollectionUtil; +import io.github.dunwu.algorithm.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 77. 组合 + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 组合 { + + public static void main(String[] args) { + Solution s = new Solution(); + int[][] expect = { { 1, 2 }, { 1, 3 }, { 1, 4 }, { 2, 3 }, { 2, 4 }, { 3, 4 } }; + Assertions.assertArrayEquals(expect, ArrayUtil.toIntMatrixArray(s.combine(4, 2))); + Assertions.assertArrayEquals(new int[][] { { 1 } }, ArrayUtil.toIntMatrixArray(s.combine(1, 1))); + } + + static class Solution { + + private List path; + private List> res; + + public List> combine(int n, int k) { + path = new LinkedList<>(); + res = new LinkedList<>(); + backtrack(n, k, 1); + return res; + } + + public void backtrack(int n, int k, int s) { + + // 【结束】 + if (path.size() == k) { + res.add(new LinkedList<>(path)); + System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); + } + + for (int i = s; i <= n; i++) { + // 【选择】 + path.add(i); + System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); + + // 【回溯】 + // 通过 start 参数控制树枝的遍历,避免产生重复的子集 + backtrack(n, k, i + 1); + + // 【取消选择】 + path.remove(path.size() - 1); + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\214.java" new file mode 100644 index 0000000..8deb466 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\214.java" @@ -0,0 +1,74 @@ +package io.github.dunwu.algorithm.dfs.permutation_combination; + +import cn.hutool.core.collection.CollectionUtil; +import io.github.dunwu.algorithm.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 39. 组合总和 + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 组合总和 { + + public static void main(String[] args) { + Solution s = new Solution(); + + List> output = s.combinationSum(new int[] { 2, 3, 6, 7 }, 7); + Assertions.assertArrayEquals(new int[][] { { 2, 2, 3 }, { 7 } }, ArrayUtil.toIntMatrixArray(output)); + + List> output2 = s.combinationSum(new int[] { 2, 3, 5 }, 8); + Assertions.assertArrayEquals(new int[][] { { 2, 2, 2, 2 }, { 2, 3, 3 }, { 3, 5 } }, + ArrayUtil.toIntMatrixArray(output2)); + } + + static class Solution { + + private int sum; + private List path; + private List> res; + + public List> combinationSum(int[] candidates, int target) { + sum = 0; + path = new LinkedList<>(); + res = new LinkedList<>(); + Arrays.sort(candidates); + backtrack(candidates, target, 0); + return res; + } + + public void backtrack(int[] nums, int target, int start) { + + // 【结束】【前序】找到目标和,记录结果 + if (sum == target) { + res.add(new LinkedList<>(path)); + System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); + return; + } + // base case,超过目标和,停止向下遍历 + if (sum > target) { return; } + + for (int i = start; i < nums.length; i++) { + // 【选择】 + sum += nums[i]; + path.add(nums[i]); + System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); + + // 【回溯】 + // 同一元素可重复使用,注意参数 + backtrack(nums, target, i); + + // 【取消选择】 + path.remove(path.size() - 1); + sum -= nums[i]; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\2142.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\2142.java" new file mode 100644 index 0000000..e57c58c --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\2142.java" @@ -0,0 +1,86 @@ +package io.github.dunwu.algorithm.dfs.permutation_combination; + +import cn.hutool.core.collection.CollectionUtil; +import io.github.dunwu.algorithm.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 40. 组合总和 II + * LCR 082. 组合总和 II + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 组合总和2 { + + public static void main(String[] args) { + + Solution s = new Solution(); + + List> output = s.combinationSum2(new int[] { 10, 1, 2, 7, 6, 1, 5 }, 8); + int[][] expect = { { 1, 1, 6 }, { 1, 2, 5 }, { 1, 7 }, { 2, 6 } }; + Assertions.assertArrayEquals(expect, ArrayUtil.toIntMatrixArray(output)); + + List> output2 = s.combinationSum2(new int[] { 2, 5, 2, 1, 2 }, 5); + int[][] expect2 = { { 1, 2, 2 }, { 5 } }; + Assertions.assertArrayEquals(expect2, ArrayUtil.toIntMatrixArray(output2)); + } + + static class Solution { + + private int sum; + private boolean[] visited; + private List path; + private List> res; + + public List> combinationSum2(int[] candidates, int target) { + sum = 0; + visited = new boolean[candidates.length]; + path = new ArrayList<>(); + res = new ArrayList<>(); + Arrays.sort(candidates); + backtrack(candidates, target, 0); + return res; + } + + public void backtrack(int[] nums, int target, int start) { + + // 【结束】【前序】找到目标和,记录结果 + if (sum == target) { + res.add(new LinkedList<>(path)); + System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); + return; + } + // base case,超过目标和,停止向下遍历 + if (sum > target) { return; } + + for (int i = start; i < nums.length; i++) { + + // 剪枝逻辑 + if (visited[i]) { continue; } + if (i > start && nums[i] == nums[i - 1] && !visited[i - 1]) { continue; } + + // 【选择】 + sum += nums[i]; + visited[i] = true; + path.add(nums[i]); + System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); + + // 【回溯】 + backtrack(nums, target, i + 1); + + // 【取消选择】 + path.remove(path.size() - 1); + visited[i] = false; + sum -= nums[i]; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\2143.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\2143.java" new file mode 100644 index 0000000..c0128a6 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\2143.java" @@ -0,0 +1,83 @@ +package io.github.dunwu.algorithm.dfs.permutation_combination; + +import cn.hutool.core.collection.CollectionUtil; +import io.github.dunwu.algorithm.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 216. 组合总和 III + * + * @author Zhang Peng + * @date 2025-11-04 + */ +public class 组合总和3 { + + public static void main(String[] args) { + Solution s = new Solution(); + + Assertions.assertArrayEquals(new int[][] { { 1, 2, 4 } }, ArrayUtil.toIntMatrixArray(s.combinationSum3(3, 7))); + + int[][] expect2 = { { 1, 2, 6 }, { 1, 3, 5 }, { 2, 3, 4 } }; + Assertions.assertArrayEquals(expect2, ArrayUtil.toIntMatrixArray(s.combinationSum3(3, 9))); + + Assertions.assertArrayEquals(new int[][] {}, ArrayUtil.toIntMatrixArray(s.combinationSum3(4, 1))); + } + + static class Solution { + + private int sum; + private boolean[] visited; + private List path; + private List> res; + + public List> combinationSum3(int k, int n) { + sum = 0; + visited = new boolean[9]; + path = new LinkedList<>(); + res = new LinkedList<>(); + int[] nums = new int[9]; + for (int i = 0; i < 9; i++) { + nums[i] = i + 1; + } + backtrack(nums, n, k, 0); + return res; + } + + public void backtrack(int[] nums, int target, int k, int s) { + + // 【结束】【前序】找到目标和,记录结果 + if (sum == target && path.size() == k) { + res.add(new LinkedList<>(path)); + System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); + return; + } + // base case,超过目标和,停止向下遍历 + if (sum > target || path.size() > k) { return; } + + for (int i = s; i < nums.length; i++) { + + if (visited[i]) { continue; } + + // 【选择】 + sum += nums[i]; + visited[i] = true; + path.add(nums[i]); + System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); + + // 【回溯】 + // 同一元素可重复使用,注意参数 + backtrack(nums, target, k, i + 1); + + // 【取消选择】 + path.remove(path.size() - 1); + visited[i] = false; + sum -= nums[i]; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/N\347\232\207\345\220\216.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/N\347\232\207\345\220\216.java" new file mode 100644 index 0000000..9e15542 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/N\347\232\207\345\220\216.java" @@ -0,0 +1,96 @@ +package io.github.dunwu.algorithm.dfs.sudoku; + +import io.github.dunwu.algorithm.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 51. N 皇后 + * + * @author Zhang Peng + * @since 2020-07-04 + */ +public class N皇后 { + + public static void main(String[] args) { + Solution s = new Solution(); + List> output = s.solveNQueens(4); + String[][] expect = { { ".Q..", "...Q", "Q...", "..Q." }, { "..Q.", "Q...", "...Q", ".Q.." } }; + Assertions.assertArrayEquals(expect, ArrayUtil.toStringMatrixArray(output)); + + List> output2 = s.solveNQueens(1); + String[][] expect2 = { { "Q" } }; + Assertions.assertArrayEquals(expect2, ArrayUtil.toStringMatrixArray(output2)); + } + + static class Solution { + + private List> res; + + // 输入棋盘边长 n,返回所有合法的放置 + public List> solveNQueens(int n) { + res = new ArrayList<>(); + // '.' 表示空,'Q' 表示皇后,初始化空棋盘。 + char[] arr = new char[n]; + Arrays.fill(arr, '.'); + String str = new String(arr); + List board = new ArrayList<>(); + for (int i = 0; i < n; i++) { + board.add(str); + } + backtrack(board, 0); + return res; + } + + // 路径:board 中小于 row 的那些行都已经成功放置了皇后 + // 选择列表:第 row 行的所有列都是放置皇后的选择 + // 结束条件:row 超过 board 的最后一行 + public void backtrack(List board, int row) { + // 触发结束条件 + if (row == board.size()) { + res.add(new ArrayList<>(board)); + return; + } + + int n = board.get(row).length(); + for (int col = 0; col < n; col++) { + // 排除不合法选择 + if (!isValid(board, row, col)) { + continue; + } + // 做选择 + char[] newRow = board.get(row).toCharArray(); + newRow[col] = 'Q'; + board.set(row, new String(newRow)); + // 进入下一行决策 + backtrack(board, row + 1); + // 撤销选择 + newRow[col] = '.'; + board.set(row, new String(newRow)); + } + } + + // 是否可以在 board[row][col] 放置皇后? + public boolean isValid(List board, int row, int col) { + int n = board.size(); + // 检查列是否有皇后互相冲突 + for (int i = 0; i < row; i++) { + if (board.get(i).charAt(col) == 'Q') { return false; } + } + // 检查右上方是否有皇后互相冲突 + for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) { + if (board.get(i).charAt(j) == 'Q') { return false; } + } + // 检查左上方是否有皇后互相冲突 + for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { + if (board.get(i).charAt(j) == 'Q') { return false; } + } + return true; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/N\347\232\207\345\220\2162.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/N\347\232\207\345\220\2162.java" new file mode 100644 index 0000000..c9a72cf --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/N\347\232\207\345\220\2162.java" @@ -0,0 +1,94 @@ +package io.github.dunwu.algorithm.dfs.sudoku; + +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 52. N皇后II + * + * @author Zhang Peng + * @since 2020-07-04 + */ +public class N皇后2 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(2, s.totalNQueens(4)); + Assertions.assertEquals(1, s.totalNQueens(1)); + } + + static class Solution { + + private List> res; + + public int totalNQueens(int n) { + return solveNQueens(n).size(); + } + + // 输入棋盘边长 n,返回所有合法的放置 + public List> solveNQueens(int n) { + res = new ArrayList<>(); + // '.' 表示空,'Q' 表示皇后,初始化空棋盘。 + char[] arr = new char[n]; + Arrays.fill(arr, '.'); + String str = new String(arr); + List board = new ArrayList<>(); + for (int i = 0; i < n; i++) { + board.add(str); + } + backtrack(board, 0); + return res; + } + + // 路径:board 中小于 row 的那些行都已经成功放置了皇后 + // 选择列表:第 row 行的所有列都是放置皇后的选择 + // 结束条件:row 超过 board 的最后一行 + public void backtrack(List board, int row) { + // 触发结束条件 + if (row == board.size()) { + res.add(new ArrayList<>(board)); + return; + } + + int n = board.get(row).length(); + for (int col = 0; col < n; col++) { + // 排除不合法选择 + if (!isValid(board, row, col)) { + continue; + } + // 做选择 + char[] newRow = board.get(row).toCharArray(); + newRow[col] = 'Q'; + board.set(row, new String(newRow)); + // 进入下一行决策 + backtrack(board, row + 1); + // 撤销选择 + newRow[col] = '.'; + board.set(row, new String(newRow)); + } + } + + // 是否可以在 board[row][col] 放置皇后? + public boolean isValid(List board, int row, int col) { + int n = board.size(); + // 检查列是否有皇后互相冲突 + for (int i = 0; i < row; i++) { + if (board.get(i).charAt(col) == 'Q') { return false; } + } + // 检查右上方是否有皇后互相冲突 + for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) { + if (board.get(i).charAt(j) == 'Q') { return false; } + } + // 检查左上方是否有皇后互相冲突 + for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { + if (board.get(i).charAt(j) == 'Q') { return false; } + } + return true; + } + + } + +} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/package-info.java new file mode 100644 index 0000000..34ca619 --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/package-info.java @@ -0,0 +1,7 @@ +/** + * 回溯算法解数独、N 皇后问题 + * + * @author Zhang Peng + * @date 2025-12-13 + */ +package io.github.dunwu.algorithm.dfs.sudoku; \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/\350\247\243\346\225\260\347\213\254.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/\350\247\243\346\225\260\347\213\254.java" new file mode 100644 index 0000000..3a198c3 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/\350\247\243\346\225\260\347\213\254.java" @@ -0,0 +1,249 @@ +package io.github.dunwu.algorithm.dfs.sudoku; + +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * 37. 解数独 + * + * @author Zhang Peng + * @date 2025-11-03 + */ +public class 解数独 { + + public static void main(String[] args) { + + char[][] expect = { + { '5', '3', '4', '6', '7', '8', '9', '1', '2' }, + { '6', '7', '2', '1', '9', '5', '3', '4', '8' }, + { '1', '9', '8', '3', '4', '2', '5', '6', '7' }, + { '8', '5', '9', '7', '6', '1', '4', '2', '3' }, + { '4', '2', '6', '8', '5', '3', '7', '9', '1' }, + { '7', '1', '3', '9', '2', '4', '8', '5', '6' }, + { '9', '6', '1', '5', '3', '7', '2', '8', '4' }, + { '2', '8', '7', '4', '1', '9', '6', '3', '5' }, + { '3', '4', '5', '2', '8', '6', '1', '7', '9' } + }; + char[][] input = { + { '5', '3', '.', '.', '7', '.', '.', '.', '.' }, + { '6', '.', '.', '1', '9', '5', '.', '.', '.' }, + { '.', '9', '8', '.', '.', '.', '.', '6', '.' }, + { '8', '.', '.', '.', '6', '.', '.', '.', '3' }, + { '4', '.', '.', '8', '.', '3', '.', '.', '1' }, + { '7', '.', '.', '.', '2', '.', '.', '.', '6' }, + { '.', '6', '.', '.', '.', '.', '2', '8', '.' }, + { '.', '.', '.', '4', '1', '9', '.', '.', '5' }, + { '.', '.', '.', '.', '8', '.', '.', '7', '9' } + }; + char[][] input2 = { + { '5', '3', '.', '.', '7', '.', '.', '.', '.' }, + { '6', '.', '.', '1', '9', '5', '.', '.', '.' }, + { '.', '9', '8', '.', '.', '.', '.', '6', '.' }, + { '8', '.', '.', '.', '6', '.', '.', '.', '3' }, + { '4', '.', '.', '8', '.', '3', '.', '.', '1' }, + { '7', '.', '.', '.', '2', '.', '.', '.', '6' }, + { '.', '6', '.', '.', '.', '.', '2', '8', '.' }, + { '.', '.', '.', '4', '1', '9', '.', '.', '5' }, + { '.', '.', '.', '.', '8', '.', '.', '7', '9' } + }; + + Solution s = new Solution(); + s.solveSudoku(input); + Assertions.assertArrayEquals(expect, input); + + Solution2 s2 = new Solution2(); + s2.solveSudoku(input2); + Assertions.assertArrayEquals(expect, input2); + } + + static class Solution { + + private int n; + // 标记是否已经找到可行解 + boolean found = false; + + public void solveSudoku(char[][] board) { + n = board.length; + backtrack(board, 0); + } + + // 路径:board 中小于 index 的位置所填的数字 + // 选择列表:数字 1~9 + // 结束条件:整个 board 都填满数字 + void backtrack(char[][] board, int index) { + if (found) { + // 已经找到一个可行解,立即结束 + return; + } + + int[] point = point(index); + int row = point[0], col = point[1]; + if (index == n * n) { + // 找到一个可行解,触发 base case + found = true; + return; + } + + if (board[row][col] != '.') { + // 如果有预设数字,不用我们穷举 + backtrack(board, index + 1); + return; + } + + for (char ch = '1'; ch <= '9'; ch++) { + // 剪枝:如果遇到不合法的数字,就跳过 + if (!isValid(board, row, col, ch)) { continue; } + + // 做选择 + board[row][col] = ch; + + backtrack(board, index + 1); + if (found) { + // 如果找到一个可行解,立即结束 + // 不要撤销选择,否则 board[i][j] 会被重置为 '.' + return; + } + + // 撤销选择 + board[row][col] = '.'; + } + } + + // 判断是否可以在 (r, c) 位置放置数字 num + boolean isValid(char[][] board, int row, int col, char num) { + for (int i = 0; i < 9; i++) { + // 判断行是否存在重复 + if (board[row][i] == num) return false; + // 判断列是否存在重复 + if (board[i][col] == num) return false; + // 判断 3 x 3 方框是否存在重复 + if (board[(row / 3) * 3 + i / 3][(col / 3) * 3 + i % 3] == num) { return false; } + } + return true; + } + + public int index(int x, int y) { + return x * n + y; + } + + public int[] point(int index) { + int x = index / n; + int y = index % n; + return new int[] { x, y }; + } + + } + + static class Solution2 { + + private int n; + + // 标记是否已经找到可行解 + private boolean found; + + // 记录每行已经出现的数字 + // 比如 rows[0] = {1, 2, 3} 表示第 0 行已经出现了数字 1, 2, 3 + private final List> rows; + + // 记录每列已经出现的数字 + private final List> cols; + + // 记录每个九宫格已经出现的数字 + private final List> boxes; + + public Solution2() { + found = false; + rows = new ArrayList<>(9); + cols = new ArrayList<>(9); + boxes = new ArrayList<>(9); + for (int i = 0; i < 9; i++) { + rows.add(new HashSet<>()); + cols.add(new HashSet<>()); + boxes.add(new HashSet<>()); + } + } + + public void solveSudoku(char[][] board) { + n = board.length; + // 将预设数字加入集合 + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + if (board[i][j] != '.') { + rows.get(i).add(board[i][j]); + cols.get(j).add(board[i][j]); + boxes.get(getBoxIndex(i, j)).add(board[i][j]); + } + } + } + backtrack(board, 0); + } + + // 路径:board 中小于 index 的位置所填的数字 + // 选择列表:数字 1~9 + // 结束条件:整个 board 都填满数字 + public void backtrack(char[][] board, int index) { + + // 已经找到一个可行解,立即结束 + if (found) { return; } + + // 找到一个可行解,触发 base case + if (index == n * n) { + found = true; + return; + } + + int row = index / n; + int col = index % n; + // 如果有预设数字,无需穷举 + if (board[row][col] != '.') { + backtrack(board, index + 1); + return; + } + + for (char ch = '1'; ch <= '9'; ch++) { + + // 【剪枝】如果遇到不合法的数字,就跳过 + if (!isValid(row, col, ch)) { continue; } + + // 【选择】把 ch 填入 board[i][j] + board[row][col] = ch; + rows.get(row).add(ch); + cols.get(col).add(ch); + boxes.get(getBoxIndex(row, col)).add(ch); + + backtrack(board, index + 1); + if (found) { + // 如果找到一个可行解,立即结束 + // 不要撤销选择,否则 board[i][j] 会被重置为 '.' + return; + } + + // 【取消选择】把 board[i][j] 重置为 '.' + board[row][col] = '.'; + rows.get(row).remove(ch); + cols.get(col).remove(ch); + boxes.get(getBoxIndex(row, col)).remove(ch); + } + } + + // 获取 (row, col) 所在的九宫格索引 + public int getBoxIndex(int row, int col) { + return (row / 3) * 3 + (col / 3); + } + + // 判断是否可以在 (row, col) 位置放置数字 num + public boolean isValid(int row, int col, char num) { + // 现在只需要查询三次哈希表即可 + if (rows.get(row).contains(num)) { return false; } + if (cols.get(col).contains(num)) { return false; } + if (boxes.get(getBoxIndex(row, col)).contains(num)) { return false; } + return true; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/template/\345\233\236\346\272\257\347\256\227\346\263\225\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/template/\345\233\236\346\272\257\347\256\227\346\263\225\346\250\241\346\235\277.java" new file mode 100644 index 0000000..24b5dd5 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/template/\345\233\236\346\272\257\347\256\227\346\263\225\346\250\241\346\235\277.java" @@ -0,0 +1,20 @@ +package io.github.dunwu.algorithm.dfs.template; + +/** + * 回溯算法模板 + * + * @author Zhang Peng + * @date 2025-12-11 + */ +public class 回溯算法模板 { + + // 【回溯算法伪代码模板】 + // for 选择 in 选择列表: + // # 做选择 + // 将该选择从选择列表移除 + // 路径.add(选择) + // backtrack(路径, 选择列表) + // # 撤销选择 + // 路径.remove(选择) + // 将该选择再加入选择列表 +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\344\274\230\347\276\216\347\232\204\346\216\222\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\344\274\230\347\276\216\347\232\204\346\216\222\345\210\227.java" new file mode 100644 index 0000000..cb4aff8 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\344\274\230\347\276\216\347\232\204\346\216\222\345\210\227.java" @@ -0,0 +1,69 @@ +package io.github.dunwu.algorithm.dfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 526. 优美的排列 + * + * @author Zhang Peng + * @date 2025-12-12 + */ +public class 优美的排列 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(1, s.countArrangement(1)); + Assertions.assertEquals(2, s.countArrangement(2)); + } + + static class Solution { + + // 记录所有的「优美排列」的个数 + private int res = 0; + // track 中的元素会被标记为 true,避免重复选择 + private boolean[] visited; + // 记录回溯算法的递归路径,即每个索引选择的元素 + private LinkedList path; + + public int countArrangement(int n) { + res = 0; + visited = new boolean[n + 1]; + path = new LinkedList<>(); + dfs(n, 1); + return res; + } + + // 回溯算法标准框架,站在索引的视角选择元素 + void dfs(int n, int index) { + // base case,到达叶子节点 + if (index > n) { + // 找到一个结果 + res += 1; + return; + } + + // 索引 index 开始选择元素 + for (int val = 1; val <= n; val++) { + // 已经被其他索引选过的元素,不能重复选择 + if (visited[val]) { + continue; + } + if (!(index % val == 0 || val % index == 0)) { + continue; + } + // 【选择】index 选择元素 elem + visited[val] = true; + path.addLast(val); + // 【回溯】 + dfs(n, index + 1); + // 【取消选择】 + path.removeLast(); + visited[val] = false; + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\227.java" deleted file mode 100644 index 9e9a5f0..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\227.java" +++ /dev/null @@ -1,54 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import java.util.LinkedList; -import java.util.List; - -/** - * 46. 全排列 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 全排列 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[] input = new int[] { 1, 2, 3 }; - List> output = s.permute(input); - System.out.println("output: " + output); - } - - static class Solution { - - private LinkedList track = null; - private LinkedList> res = null; - private boolean[] used = null; - - public List> permute(int[] nums) { - track = new LinkedList<>(); - res = new LinkedList<>(); - used = new boolean[nums.length]; - backtrack(nums); - return res; - } - - public void backtrack(int[] nums) { - if (track.size() == nums.length) { - res.add(new LinkedList<>(track)); - // System.out.printf("\t=> %s\n", res); - return; - } - - for (int i = 0; i < nums.length; i++) { - if (used[i]) { continue; } - track.addLast(nums[i]); - used[i] = true; - backtrack(nums); - track.removeLast(); - used[i] = false; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\2272.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\2272.java" deleted file mode 100644 index 3a6ac26..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\205\250\346\216\222\345\210\2272.java" +++ /dev/null @@ -1,59 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * 47. 全排列 II - * LCR 084. 全排列 II - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 全排列2 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[] input = new int[] { 1, 2, 3 }; - List> output = s.permuteUnique(input); - System.out.println("output: " + output); - } - - static class Solution { - - private LinkedList track = null; - private LinkedList> res = null; - private boolean[] used = null; - - public List> permuteUnique(int[] nums) { - track = new LinkedList<>(); - res = new LinkedList<>(); - used = new boolean[nums.length]; - Arrays.sort(nums); - backtrack(nums); - return res; - } - - public void backtrack(int[] nums) { - if (track.size() == nums.length) { - res.add(new LinkedList<>(track)); - // System.out.printf("\t=> %s\n", res); - return; - } - - for (int i = 0; i < nums.length; i++) { - if (used[i]) { continue;} - if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) { continue;} - - track.addLast(nums[i]); - used[i] = true; - backtrack(nums); - track.removeLast(); - used[i] = false; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\210\206\345\211\262\345\233\236\346\226\207\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\210\206\345\211\262\345\233\236\346\226\207\344\270\262.java" new file mode 100644 index 0000000..7c63a40 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\210\206\345\211\262\345\233\236\346\226\207\344\270\262.java" @@ -0,0 +1,72 @@ +package io.github.dunwu.algorithm.dfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 131. 分割回文串 + * + * @author Zhang Peng + * @date 2025-12-12 + */ +public class 分割回文串 { + + public static void main(String[] args) { + Solution s = new Solution(); + + String[][] expect = new String[][] { { "a", "a", "b" }, { "aa", "b" } }; + List> output = s.partition("aab"); + Assertions.assertEquals(expect.length, output.size()); + + List> output2 = s.partition("a"); + Assertions.assertEquals(1, output2.size()); + } + + static class Solution { + + private List path; + private List> res; + + public List> partition(String s) { + path = new LinkedList<>(); + res = new LinkedList<>(); + dfs(s, 0); + return res; + } + + public void dfs(String s, int start) { + if (start == s.length()) { + // base case,走到叶子节点 + // 即整个 s 被成功分割为若干个回文子串,记下答案 + res.add(new LinkedList(path)); + } + for (int i = start; i < s.length(); i++) { + if (!isPalindrome(s, start, i)) { + // s[start..i] 不是回文串,不能分割 + continue; + } + // s[start..i] 是一个回文串,可以进行分割 + // 做选择,把 s[start..i] 放入路径列表中 + path.add(s.substring(start, i + 1)); + // 进入回溯树的下一层,继续切分 s[i+1..] + dfs(s, i + 1); + // 撤销选择 + path.remove(path.size() - 1); + } + } + + // 用双指针技巧判断 s[low..high] 是否是一个回文串 + public boolean isPalindrome(String s, int low, int high) { + while (low < high) { + if (s.charAt(low) != s.charAt(high)) { return false; } + low++; + high--; + } + return true; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\215\225\350\257\215\346\220\234\347\264\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\215\225\350\257\215\346\220\234\347\264\242.java" new file mode 100644 index 0000000..ef11cfe --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\215\225\350\257\215\346\220\234\347\264\242.java" @@ -0,0 +1,70 @@ +package io.github.dunwu.algorithm.dfs; + +import org.junit.jupiter.api.Assertions; + +/** + * 79. 单词搜索 + * + * @author Zhang Peng + * @date 2025-12-12 + */ +public class 单词搜索 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue( + s.exist(new char[][] { { 'A', 'B', 'C', 'E' }, { 'S', 'F', 'C', 'S' }, { 'A', 'D', 'E', 'E' } }, "ABCCED")); + Assertions.assertTrue( + s.exist(new char[][] { { 'A', 'B', 'C', 'E' }, { 'S', 'F', 'C', 'S' }, { 'A', 'D', 'E', 'E' } }, "SEE")); + Assertions.assertFalse( + s.exist(new char[][] { { 'A', 'B', 'C', 'E' }, { 'S', 'F', 'C', 'S' }, { 'A', 'D', 'E', 'E' } }, "ABCB")); + } + + static class Solution { + + boolean found = false; + + public boolean exist(char[][] board, String word) { + found = false; + int m = board.length, n = board[0].length; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + dfs(board, i, j, word, 0); + if (found) { return true; } + } + } + return false; + } + + // 从 (i, j) 开始向四周搜索,试图匹配 word[p..] + void dfs(char[][] board, int i, int j, String word, int p) { + if (p == word.length()) { + // 整个 word 已经被匹配完,找到了一个答案 + found = true; + return; + } + if (found) { + // 已经找到了一个答案,不用再搜索了 + return; + } + int m = board.length, n = board[0].length; + if (i < 0 || j < 0 || i >= m || j >= n) { + return; + } + if (board[i][j] != word.charAt(p)) { + return; + } + + // 已经匹配过的字符,我们给它添一个负号作为标记,避免走回头路 + board[i][j] = (char) (-board[i][j]); + // word[p] 被 board[i][j] 匹配,开始向四周搜索 word[p+1..] + dfs(board, i + 1, j, word, p + 1); + dfs(board, i, j + 1, word, p + 1); + dfs(board, i - 1, j, word, p + 1); + dfs(board, i, j - 1, word, p + 1); + board[i][j] = (char) (-board[i][j]); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\244\215\345\216\237IP\345\234\260\345\235\200.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\244\215\345\216\237IP\345\234\260\345\235\200.java" new file mode 100644 index 0000000..ce16a6a --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\244\215\345\216\237IP\345\234\260\345\235\200.java" @@ -0,0 +1,88 @@ +package io.github.dunwu.algorithm.dfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 93. 复原 IP 地址 + * + * @author Zhang Peng + * @date 2025-12-12 + */ +public class 复原IP地址 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new String[] { "255.255.11.135", "255.255.111.35" }, + s.restoreIpAddresses("25525511135").toArray()); + Assertions.assertArrayEquals(new String[] { "0.0.0.0" }, s.restoreIpAddresses("0000").toArray()); + Assertions.assertArrayEquals(new String[] { "1.0.10.23", "1.0.102.3", "10.1.0.23", "10.10.2.3", "101.0.2.3" }, + s.restoreIpAddresses("101023").toArray()); + } + + static class Solution { + + private LinkedList path; + private LinkedList res; + + public List restoreIpAddresses(String s) { + path = new LinkedList<>(); + res = new LinkedList<>(); + dfs(s, 0); + return res; + } + + public void dfs(String s, int start) { + + // base case,走到叶子节点 + // 即整个 s 被成功分割为合法的四部分,记下答案 + if (start == s.length() && path.size() == 4) { + String ip = String.join(".", path); + res.add(ip); + } + + for (int i = start; i < s.length(); i++) { + + // s[start..i] 不是合法的 ip 数字,不能分割 + if (!isValid(s, start, i)) { continue; } + + // 已经分解成 4 部分了,不能再分解了 + if (path.size() >= 4) { continue; } + + // 【选择】 + // s[start..i] 是一个合法的 ip 数字,可以进行分割 + // 做选择,把 s[start..i] 放入路径列表中 + path.add(s.substring(start, i + 1)); + + // 【回溯】 + dfs(s, i + 1); + + // 【取消选择】 + path.removeLast(); + } + } + + public boolean isValid(String s, int start, int end) { + + int length = end - start + 1; + + if (length == 0 || length > 3) { return false; } + + // 如果只有一位数字,肯定是合法的 + if (length == 1) { return true; } + + // 多于一位数字,但开头是 0,肯定不合法 + if (s.charAt(start) == '0') { return false; } + + // 排除了开头是 0 的情况,那么如果是两位数,肯定是合法的 + if (length <= 2) { return true; } + + // 现在输入的一定是三位数,不能大于 255 + return Integer.parseInt(s.substring(start, start + length)) <= 255; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\206.java" deleted file mode 100644 index 20f21f2..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\206.java" +++ /dev/null @@ -1,59 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 78. 子集 - *

- * 元素不可重复,不可复选 - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 子集 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[] input = new int[] { 1, 2, 3 }; - Integer[][] expect = new Integer[][] { {}, { 1 }, { 2 }, { 1, 2 }, { 3 }, { 1, 3 }, { 2, 3 }, { 1, 2, 3 } }; - List> output = s.subsets(input); - Assertions.assertEquals(expect.length, output.size()); - System.out.println("output: " + output); - } - - static class Solution { - - // 记录回溯算法的递归路径 - LinkedList track = null; - List> res = null; - - public List> subsets(int[] nums) { - track = new LinkedList<>(); - res = new LinkedList<>(); - backtrack(nums, 0); - return res; - } - - public void backtrack(int[] nums, int start) { - - // 前序位置,每个节点的值都是一个子集 - res.add(new LinkedList<>(track)); - System.out.printf("\t=> %s\n", res); - - // 回溯算法标准框架 - for (int i = start; i < nums.length; i++) { - // 做选择 - track.addLast(nums[i]); - // 通过 start 参数控制树枝的遍历,避免产生重复的子集 - backtrack(nums, i + 1); - // 撤销选择 - track.removeLast(); - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\2062.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\2062.java" deleted file mode 100644 index 038c5ac..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\255\220\351\233\2062.java" +++ /dev/null @@ -1,76 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * 90. 子集 II - *

- * 元素可重复,不可复选 - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 子集2 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - // int[] input = new int[] { 1, 2, 2 }; - // Integer[][] expect = new Integer[][] { {}, { 1 }, { 1, 2 }, { 1, 2, 2 }, { 2 }, { 2, 2 } }; - // List> output = s.subsetsWithDup(input); - // Assertions.assertEquals(expect.length, output.size()); - // System.out.println("output: " + output); - - int[] input2 = new int[] { 4, 4, 4, 1, 4 }; - Integer[][] expect2 = - new Integer[][] { {}, { 1 }, { 1, 4 }, { 1, 4, 4 }, { 1, 4, 4, 4 }, { 1, 4, 4, 4, 4 }, { 4 }, { 4, 4 }, - { 4, 4, 4 }, { 4, 4, 4, 4 } }; - List> output2 = s.subsetsWithDup(input2); - System.out.println("output: " + output2); - Assertions.assertEquals(expect2.length, output2.size()); - } - - static class Solution { - - // 记录回溯算法的递归路径 - LinkedList track = null; - List> res = null; - - public List> subsetsWithDup(int[] nums) { - track = new LinkedList<>(); - res = new LinkedList<>(); - // 先排序,让相同的元素靠在一起 - Arrays.sort(nums); - backtrack(nums, 0); - return res; - } - - public void backtrack(int[] nums, int start) { - - // 前序位置,每个节点的值都是一个子集 - res.add(new LinkedList<>(track)); - // System.out.printf("\t=> %s\n", res); - - // 回溯算法标准框架 - for (int i = start; i < nums.length; i++) { - - // 剪枝逻辑,值相同的相邻树枝,只遍历第一条 - if (i > start && nums[i] == nums[i - 1]) { continue; } - - // 做选择 - track.addLast(nums[i]); - // 通过 start 参数控制树枝的遍历,避免产生重复的子集 - backtrack(nums, i + 1); - // 撤销选择 - track.removeLast(); - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\346\240\274\351\233\267\347\274\226\347\240\201.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\346\240\274\351\233\267\347\274\226\347\240\201.java" new file mode 100644 index 0000000..92162c4 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\346\240\274\351\233\267\347\274\226\347\240\201.java" @@ -0,0 +1,64 @@ +package io.github.dunwu.algorithm.dfs; + +import io.github.dunwu.algorithm.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; +import java.util.List; + +/** + * 526. 优美的排列 + * + * @author Zhang Peng + * @date 2025-12-12 + */ +public class 格雷编码 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertArrayEquals(new int[] { 0, 1 }, ArrayUtil.toIntArray(s.grayCode(1))); + Assertions.assertArrayEquals(new int[] { 0, 1, 3, 2 }, ArrayUtil.toIntArray(s.grayCode(2))); + } + + static class Solution { + + private boolean[] visited; + private LinkedList path; + private LinkedList res; + + public List grayCode(int n) { + visited = new boolean[n]; + path = new LinkedList<>(); + res = null; + dfs(n, 0); + return res; + } + + public void dfs(int n, int root) { + if (res != null) return; + if (path.size() == (1 << n)) { + res = new LinkedList<>(path); + return; + } + if (visited[root]) return; + + visited[root] = true; + path.addLast(root); + + for (int i = 0; i < n; i++) { + int next = flipBit(root, i); + dfs(n, next); + } + + path.removeLast(); + visited[root] = false; + } + + // 把第 i 位取反(0 变 1,1 变 0) + int flipBit(int x, int i) { + return x ^ (1 << i); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210.java" index 1583633..def2aea 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210.java" @@ -6,6 +6,7 @@ import java.util.List; /** + * 17. 电话号码的字母组合 * * @author Zhang Peng * @date 2025-11-05 @@ -16,32 +17,40 @@ public static void main(String[] args) { Solution s = new Solution(); Assertions.assertArrayEquals(new String[] { "ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf" }, s.letterCombinations("23").toArray()); - Assertions.assertArrayEquals(new String[] { "a","b","c" }, s.letterCombinations("2").toArray()); - Assertions.assertArrayEquals(new String[] { "t","u","v" }, s.letterCombinations("8").toArray()); + Assertions.assertArrayEquals(new String[] { "a", "b", "c" }, s.letterCombinations("2").toArray()); + Assertions.assertArrayEquals(new String[] { "t", "u", "v" }, s.letterCombinations("8").toArray()); } static class Solution { - List res; - StringBuilder sb; - final String[] table = new String[] { "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" }; + private StringBuilder sb; + private LinkedList res; + private final String[] options = new String[] { + "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" + }; public List letterCombinations(String digits) { + if (digits.isEmpty()) { return new LinkedList<>(); } sb = new StringBuilder(); res = new LinkedList<>(); - backtrack(digits.toCharArray(), 0); + // 从 digits[0] 开始进行回溯 + dfs(digits, 0); return res; } - public void backtrack(char[] nums, int index) { - if (sb.length() == nums.length) { + // 回溯算法主函数 + public void dfs(String digits, int start) { + // 到达回溯树底部 + if (sb.length() == digits.length()) { res.add(sb.toString()); return; } - int num = nums[index] - '0'; - for (int i = 0; i < table[num].length(); i++) { - sb.append(table[num].charAt(i)); - backtrack(nums, index + 1); + + // 回溯算法框架 + int digit = digits.charAt(start) - '0'; + for (char c : options[digit].toCharArray()) { + sb.append(c); + dfs(digits, start + 1); sb.deleteCharAt(sb.length() - 1); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210.java" deleted file mode 100644 index 32bb539..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210.java" +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import java.util.LinkedList; -import java.util.List; - -/** - * 77. 组合 - *

- * 元素不可重复,不可复选 - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 组合 { - - public static void main(String[] args) { - Solution s = new Solution(); - List> output = s.combine(4, 2); - System.out.println("output = " + output); - // Assertions.assertArrayEquals(); - } - - static class Solution { - - // 记录回溯算法的递归路径 - LinkedList track = null; - List> res = null; - - public List> combine(int n, int k) { - track = new LinkedList<>(); - res = new LinkedList<>(); - backtrack(1, n, k); - return res; - } - - public void backtrack(int start, int n, int len) { - - // 前序位置,每个节点的值都是一个子集 - if (track.size() == len) { - res.add(new LinkedList<>(track)); - // System.out.printf("\t=> %s\n", res); - return; - } - - // 回溯算法标准框架 - for (int i = start; i <= n; i++) { - // 做选择 - track.addLast(i); - // 通过 start 参数控制树枝的遍历,避免产生重复的子集 - backtrack(i + 1, n, len); - // 撤销选择 - track.removeLast(); - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\214.java" deleted file mode 100644 index c010c0f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\214.java" +++ /dev/null @@ -1,66 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import java.util.LinkedList; -import java.util.List; - -/** - * 39. 组合总和 - *

- * 元素不可重复,不可复选 - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 组合总和 { - - public static void main(String[] args) { - Solution s = new Solution(); - List> output = s.combinationSum(new int[] { 2, 3, 6, 7 }, 7); - System.out.println("output = " + output); - } - - static class Solution { - - // 记录回溯算法的递归路径 - LinkedList track = null; - List> res = null; - // 记录 track 中的元素之和 - int sum = 0; - - public List> combinationSum(int[] candidates, int target) { - track = new LinkedList<>(); - res = new LinkedList<>(); - sum = 0; - backtrack(candidates, 0, target); - return res; - } - - public void backtrack(int[] nums, int start, int taget) { - - // 前序位置,每个节点的值都是一个子集 - if (sum == taget) { - res.add(new LinkedList<>(track)); - System.out.printf("\t=> %s\n", res); - return; - } - - if (sum > taget) { - return; - } - - // 回溯算法标准框架 - for (int i = start; i < nums.length; i++) { - // 做选择 - track.addLast(nums[i]); - sum += nums[i]; - // 通过 start 参数控制树枝的遍历,避免产生重复的子集 - backtrack(nums, i, taget); - // 撤销选择 - track.removeLast(); - sum -= nums[i]; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2142.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2142.java" deleted file mode 100644 index 6faf5e4..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2142.java" +++ /dev/null @@ -1,79 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * 40. 组合总和 II - * LCR 082. 组合总和 II - *

- * 元素不可重复,不可复选 - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 组合总和2 { - - public static void main(String[] args) { - Solution s = new Solution(); - List> output = s.combinationSum2(new int[] { 10, 1, 2, 7, 6, 1, 5 }, 8); - System.out.println("output = " + output); - // 期望输出: - // [ - // [1,1,6], - // [1,2,5], - // [1,7], - // [2,6] - // ] - } - - static class Solution { - - // 记录回溯算法的递归路径 - LinkedList track = null; - List> res = null; - // 记录 track 中的元素之和 - int sum = 0; - - public List> combinationSum2(int[] candidates, int target) { - track = new LinkedList<>(); - res = new LinkedList<>(); - sum = 0; - Arrays.sort(candidates); - backtrack(candidates, 0, target); - return res; - } - - public void backtrack(int[] nums, int start, int taget) { - - // 前序位置,每个节点的值都是一个子集 - if (sum == taget) { - res.add(new LinkedList<>(track)); - // System.out.printf("\t=> %s\n", res); - return; - } - - if (sum > taget) { - return; - } - - // 回溯算法标准框架 - for (int i = start; i < nums.length; i++) { - - if (i > start && nums[i] == nums[i - 1]) { continue; } - - // 做选择 - track.addLast(nums[i]); - sum += nums[i]; - // 通过 start 参数控制树枝的遍历,避免产生重复的子集 - backtrack(nums, i + 1, taget); - // 撤销选择 - track.removeLast(); - sum -= nums[i]; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2143.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2143.java" deleted file mode 100644 index 944c523..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\273\204\345\220\210\346\200\273\345\222\2143.java" +++ /dev/null @@ -1,85 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import java.util.LinkedList; -import java.util.List; - -/** - * 216. 组合总和 III - *

- * 元素不可重复,不可复选 - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 组合总和3 { - - public static void main(String[] args) { - Solution s = new Solution(); - List> output = s.combinationSum3(3, 7); - System.out.println("output = " + output); - // 期望输出: - // [ - // [1,2,4] - // ] - - List> output2 = s.combinationSum3(3, 9); - System.out.println("output = " + output2); - // 期望输出: - // [[1,2,6], [1,3,5], [2,3,4]] - - List> output3 = s.combinationSum3(4, 1); - System.out.println("output = " + output3); - // 期望输出: - // [] - } - - static class Solution { - - // 记录回溯算法的递归路径 - LinkedList track = null; - List> res = null; - // 记录 track 中的元素之和 - int sum = 0; - - public List> combinationSum3(int k, int n) { - track = new LinkedList<>(); - res = new LinkedList<>(); - int[] nums = new int[9]; - for (int i = 0; i < 9; i++) { - nums[i] = i + 1; - } - backtrack(nums, 0, k, n); - return res; - } - - public void backtrack(int[] nums, int start, int len, int taget) { - - // 前序位置,每个节点的值都是一个子集 - if (sum == taget && track.size() == len) { - res.add(new LinkedList<>(track)); - // System.out.printf("\t=> %s\n", res); - return; - } - - // 剪枝 - if (sum > taget || track.size() > len) { - return; - } - - // 回溯算法标准框架 - for (int i = start; i < nums.length; i++) { - - // 做选择 - track.addLast(nums[i]); - sum += nums[i]; - // 通过 start 参数控制树枝的遍历,避免产生重复的子集 - backtrack(nums, i + 1, len, taget); - // 撤销选择 - track.removeLast(); - sum -= nums[i]; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\247\243\346\225\260\347\213\254.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\247\243\346\225\260\347\213\254.java" deleted file mode 100644 index 5e9a7e1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\247\243\346\225\260\347\213\254.java" +++ /dev/null @@ -1,88 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import org.junit.jupiter.api.Assertions; - -/** - * 37. 解数独 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 解数独 { - - public static void main(String[] args) { - Solution s = new Solution(); - char[][] input = new char[][] { { '5', '3', '.', '.', '7', '.', '.', '.', '.' }, - { '6', '.', '.', '1', '9', '5', '.', '.', '.' }, { '.', '9', '8', '.', '.', '.', '.', '6', '.' }, - { '8', '.', '.', '.', '6', '.', '.', '.', '3' }, { '4', '.', '.', '8', '.', '3', '.', '.', '1' }, - { '7', '.', '.', '.', '2', '.', '.', '.', '6' }, { '.', '6', '.', '.', '.', '.', '2', '8', '.' }, - { '.', '.', '.', '4', '1', '9', '.', '.', '5' }, { '.', '.', '.', '.', '8', '.', '.', '7', '9' } }; - char[][] expect = new char[][] { { '5', '3', '4', '6', '7', '8', '9', '1', '2' }, - { '6', '7', '2', '1', '9', '5', '3', '4', '8' }, { '1', '9', '8', '3', '4', '2', '5', '6', '7' }, - { '8', '5', '9', '7', '6', '1', '4', '2', '3' }, { '4', '2', '6', '8', '5', '3', '7', '9', '1' }, - { '7', '1', '3', '9', '2', '4', '8', '5', '6' }, { '9', '6', '1', '5', '3', '7', '2', '8', '4' }, - { '2', '8', '7', '4', '1', '9', '6', '3', '5' }, { '3', '4', '5', '2', '8', '6', '1', '7', '9' } }; - s.solveSudoku(input); - Assertions.assertArrayEquals(expect, input); - } - - static class Solution { - - boolean found = false; - - public void solveSudoku(char[][] nums) { - found = false; - backtrack(nums, 0); - } - - public void backtrack(char[][] nums, int index) { - - if (found) { return; } - - int m = 9, n = 9; - int i = index / n, j = index % n; - if (index == m * n) { - found = true; - return; - } - - if (nums[i][j] != '.') { - backtrack(nums, index + 1); - return; - } - - for (char ch = '1'; ch <= '9'; ch++) { - // 剪枝:如果遇到不合法的数字,就跳过 - if (!isValid(nums, i, j, ch)) { continue; } - - // 做选择 - nums[i][j] = ch; - - backtrack(nums, index + 1); - if (found) { - // 如果找到一个可行解,立即结束 - // 不要撤销选择,否则 board[i][j] 会被重置为 '.' - return; - } - - // 撤销选择 - nums[i][j] = '.'; - } - } - - // 判断是否可以在 (r, c) 位置放置数字 num - boolean isValid(char[][] board, int row, int column, char num) { - for (int i = 0; i < 9; i++) { - // 判断行是否存在重复 - if (board[row][i] == num) return false; - // 判断列是否存在重复 - if (board[i][column] == num) return false; - // 判断 3 x 3 方框是否存在重复 - if (board[(row / 3) * 3 + i / 3][(column / 3) * 3 + i % 3] == num) { return false; } - } - return true; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\277\236\347\273\255\345\267\256\347\233\270\345\220\214\347\232\204\346\225\260\345\255\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\277\236\347\273\255\345\267\256\347\233\270\345\220\214\347\232\204\346\225\260\345\255\227.java" index 01480a0..d9a0551 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\277\236\347\273\255\345\267\256\347\233\270\345\220\214\347\232\204\346\225\260\345\255\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\277\236\347\273\255\345\267\256\347\233\270\345\220\214\347\232\204\346\225\260\345\255\227.java" @@ -3,8 +3,10 @@ import org.junit.jupiter.api.Assertions; import java.util.LinkedList; +import java.util.List; /** + * 967. 连续差相同的数字 * * @author Zhang Peng * @date 2025-11-05 @@ -14,33 +16,59 @@ public class 连续差相同的数字 { public static void main(String[] args) { Solution s = new Solution(); Assertions.assertArrayEquals(new int[] { 181, 292, 707, 818, 929 }, s.numsSameConsecDiff(3, 7)); + Assertions.assertArrayEquals(new int[] { 10, 12, 21, 23, 32, 34, 43, 45, 54, 56, 65, 67, 76, 78, 87, 89, 98 }, + s.numsSameConsecDiff(2, 1)); + Assertions.assertArrayEquals(new int[] { 11, 22, 33, 44, 55, 66, 77, 88, 99 }, s.numsSameConsecDiff(2, 0)); + Assertions.assertArrayEquals(new int[] { 13, 20, 24, 31, 35, 42, 46, 53, 57, 64, 68, 75, 79, 86, 97 }, + s.numsSameConsecDiff(2, 2)); } static class Solution { - int track = 0; - int digit = 0; - LinkedList res = null; + // 记录当前路径组成的数字的值 + private int num = 0; + // 记录当前数字的位数 + private int digit = 0; + private List res; public int[] numsSameConsecDiff(int n, int k) { + + num = 0; + digit = 0; res = new LinkedList<>(); - backtrack(n, k); - return res.stream().mapToInt(Integer::intValue).toArray(); + + dfs(n, k); + + int[] arr = new int[res.size()]; + for (int i = 0; i < res.size(); i++) { + arr[i] = res.get(i); + } + return arr; } - public void backtrack(int n, int k) { + // 回溯算法核心函数 + void dfs(int n, int k) { + // base case,到达叶子节点 if (digit == n) { - res.addLast(track); + // 找到一个合法的 n 位数 + res.add(num); return; } + // 回溯算法标准框架 for (int i = 0; i <= 9; i++) { - if (digit == 0 && i == 0) { continue; } - if (digit > 0 && Math.abs(i - track % 10) != k) { continue; } + // 本题的剪枝逻辑 1,第一个数字不能是 0 + if (digit == 0 && i == 0) continue; + // 本题的剪枝逻辑 2,相邻两个数字的差的绝对值必须等于 k + if (digit > 0 && Math.abs(i - num % 10) != k) continue; + + // 做选择,在 track 尾部追加数字 i digit++; - track = track * 10 + i; - backtrack(n, k); - track = track / 10; + num = 10 * num + i; + // 进入下一层回溯树 + dfs(n, k); + // 取消选择,删除 track 尾部数字 + num = num / 10; digit--; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\351\235\236\351\200\222\345\207\217\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\351\235\236\351\200\222\345\207\217\345\255\220\345\272\217\345\210\227.java" new file mode 100644 index 0000000..0c5494d --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\351\235\236\351\200\222\345\207\217\345\255\220\345\272\217\345\210\227.java" @@ -0,0 +1,76 @@ +package io.github.dunwu.algorithm.dfs; + +import io.github.dunwu.algorithm.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; + +/** + * 491. 非递减子序列 + * + * @author Zhang Peng + * @date 2025-12-12 + */ +public class 非递减子序列 { + + public static void main(String[] args) { + Solution s = new Solution(); + + int[][] expect = new int[][] { + { 4, 6 }, { 4, 6, 7 }, { 4, 6, 7, 7 }, { 4, 7 }, { 4, 7, 7 }, { 6, 7 }, { 6, 7, 7 }, { 7, 7 } + }; + List> output = s.findSubsequences(new int[] { 4, 6, 7, 7 }); + Assertions.assertArrayEquals(expect, ArrayUtil.toIntMatrixArray(output)); + + List> output2 = s.findSubsequences(new int[] { 4, 4, 3, 2, 1 }); + Assertions.assertArrayEquals(new int[][] { { 4, 4 } }, ArrayUtil.toIntMatrixArray(output2)); + } + + static class Solution { + + private List path; + private List> res; + + public List> findSubsequences(int[] nums) { + + // base case + if (nums == null || nums.length == 0) { return new LinkedList<>(); } + + path = new LinkedList<>(); + res = new LinkedList<>(); + + dfs(nums, 0); + return res; + } + + public void dfs(int[] nums, int start) { + if (path.size() >= 2) { + res.add(new LinkedList<>(path)); + } + + // 用哈希集合防止重复选择相同元素 + HashSet visited = new HashSet<>(); + + for (int i = start; i < nums.length; i++) { + + if (!path.isEmpty() && nums[i] < path.get(path.size() - 1)) { continue; } + // 保证不要重复使用相同的元素 + if (visited.contains(nums[i])) { continue; } + + // 【选择】 + visited.add(nums[i]); + path.add(nums[i]); + + // 【递归】 + dfs(nums, i + 1); + + // 【取消选择】 + path.remove(path.size() - 1); + } + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" index 0fbde05..9d2e036 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" @@ -15,9 +15,9 @@ public class 三角形最小路径和 { public static void main(String[] args) { Solution s = new Solution(); - List> input = ArrayUtil.toListList(new int[][] { { 2 }, { 3, 4 }, { 6, 5, 7 }, { 4, 1, 8, 3 } }); + List> input = ArrayUtil.toIntMatrixList(new int[][] { { 2 }, { 3, 4 }, { 6, 5, 7 }, { 4, 1, 8, 3 } }); Assertions.assertEquals(11, s.minimumTotal(input)); - List> input2 = ArrayUtil.toListList(new int[][] { { -10 } }); + List> input2 = ArrayUtil.toIntMatrixList(new int[][] { { -10 } }); Assertions.assertEquals(-10, s.minimumTotal(input2)); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" index d9383f6..a78231e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" @@ -3,6 +3,7 @@ import org.junit.jupiter.api.Assertions; import java.util.LinkedList; +import java.util.Queue; /** * 785. 判断二分图 @@ -105,7 +106,7 @@ public boolean isBipartite(int[][] graph) { // 从 start 节点开始进行 BFS 遍历 private void bfs(int[][] graph, int start) { - LinkedList q = new LinkedList<>(); + Queue q = new LinkedList<>(); visited[start] = true; q.offer(start); diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\217\257\350\203\275\347\232\204\344\272\214\345\210\206\346\263\225.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\217\257\350\203\275\347\232\204\344\272\214\345\210\206\346\263\225.java" index 4b8be13..1dc1d9b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\217\257\350\203\275\347\232\204\344\272\214\345\210\206\346\263\225.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\217\257\350\203\275\347\232\204\344\272\214\345\210\206\346\263\225.java" @@ -35,8 +35,7 @@ public boolean possibleBipartition(int n, int[][] dislikes) { // 图节点编号从 1 开始 color = new boolean[n + 1]; visited = new boolean[n + 1]; - - // 转化成邻接表图结构 + // 转化成邻接表表示图结构 List[] graph = buildGraph(n, dislikes); for (int v = 1; v <= n; v++) { @@ -44,11 +43,30 @@ public boolean possibleBipartition(int n, int[][] dislikes) { dfs(graph, v); } } - return ok; } - public void dfs(List[] graph, int v) { + // 建图函数 + private List[] buildGraph(int n, int[][] dislikes) { + // 图节点编号为 1...n + List[] graph = new LinkedList[n + 1]; + for (int i = 1; i <= n; i++) { + graph[i] = new LinkedList<>(); + } + for (int[] edge : dislikes) { + int v = edge[1]; + int w = edge[0]; + // 「无向图」相当于「双向图」 + // v -> w + graph[v].add(w); + // w -> v + graph[w].add(v); + } + return graph; + } + + // 和之前判定二分图的 traverse 函数完全相同 + private void dfs(List[] graph, int v) { if (!ok) return; visited[v] = true; for (int w : graph[v]) { @@ -63,20 +81,6 @@ public void dfs(List[] graph, int v) { } } - public List[] buildGraph(int n, int[][] data) { - List[] graph = new LinkedList[n + 1]; - for (int i = 1; i <= n; i++) { - graph[i] = new LinkedList<>(); - } - - for (int[] edge : data) { - int v = edge[1], w = edge[0]; - graph[v].add(w); - graph[w].add(v); - } - return graph; - } - } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/dfs/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/dfs/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" index bd04a8e..b111b38 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/dfs/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/dfs/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" @@ -1,6 +1,5 @@ package io.github.dunwu.algorithm.graph.dfs; -import cn.hutool.core.collection.CollectionUtil; import org.junit.jupiter.api.Assertions; import java.util.Arrays; @@ -31,11 +30,13 @@ public static void main(String[] args) { } static class Solution { - // 记录所有路径 - List> res = new LinkedList<>(); - LinkedList path = new LinkedList<>(); + + private List path; + private List> res; public List> allPathsSourceTarget(int[][] graph) { + path = new LinkedList<>(); + res = new LinkedList<>(); dfs(graph, 0); return res; } @@ -44,14 +45,13 @@ public List> allPathsSourceTarget(int[][] graph) { void dfs(int[][] graph, int s) { // 添加节点 s 到路径 - path.addLast(s); + path.add(s); int n = graph.length; if (s == n - 1) { // 到达终点 - System.out.println("find path: " + CollectionUtil.join(path, "->")); res.add(new LinkedList<>(path)); - path.removeLast(); + path.remove(path.size() - 1); return; } @@ -61,7 +61,7 @@ void dfs(int[][] graph, int s) { } // 从路径移出节点 s - path.removeLast(); + path.remove(path.size() - 1); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\2502.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\2502.java" index 718b2db..998b686 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\2502.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\2502.java" @@ -23,7 +23,7 @@ public static void main(String[] args) { Solution2 s2 = new Solution2(); Assertions.assertArrayEquals(new int[] { 0, 1 }, s2.findOrder(2, new int[][] { { 1, 0 } })); - Assertions.assertArrayEquals(new int[] { 0, 1, 2, 3 }, + Assertions.assertArrayEquals(new int[] { 0, 2, 1, 3 }, s2.findOrder(4, new int[][] { { 1, 0 }, { 2, 0 }, { 3, 1 }, { 3, 2 } })); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\345\206\227\344\275\231\350\277\236\346\216\245.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\345\206\227\344\275\231\350\277\236\346\216\245.java" index f3729f5..8619903 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\345\206\227\344\275\231\350\277\236\346\216\245.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\345\206\227\344\275\231\350\277\236\346\216\245.java" @@ -21,15 +21,13 @@ public static void main(String[] args) { static class Solution { public int[] findRedundantConnection(int[][] edges) { - int n = edges.length; - UF uf = new UF(n + 1); - for (int i = 0; i < n; i++) { - int u = edges[i][0]; - int v = edges[i][1]; - if (uf.find(u) == uf.find(v)) { - return new int[] { u, v }; + UF uf = new UF(edges.length + 1); + for (int[] edge : edges) { + int p = edge[0], q = edge[1]; + if (uf.connected(p, q)) { + return new int[] { p, q }; } else { - uf.union(u, v); + uf.union(p, q); } } return new int[0]; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.java" index 9e1896b..ae1114a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.java" @@ -33,56 +33,58 @@ static class Solution { private int m; private int n; + int[][] direct = new int[][] { { 1, 0 }, { 0, 1 }, { 0, -1 }, { -1, 0 } }; public void solve(char[][] board) { - if (board == null || board.length == 0 || board[0].length == 0) { return; } + if (board == null || board.length == 0) return; m = board.length; n = board[0].length; - int dummy = m * n; + // 给 dummy 留一个额外位置 UF uf = new UF(m * n + 1); + int dummy = m * n; + // 将首列和末列的 O 与 dummy 连通 for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - // 遇到 O 进行并查集合并操作 + if (board[i][0] == 'O') { uf.union(index(i, 0), dummy); } + if (board[i][n - 1] == 'O') { uf.union(index(i, n - 1), dummy); } + } + + // 将首行和末行的 O 与 dummy 连通 + for (int j = 0; j < n; j++) { + if (board[0][j] == 'O') { uf.union(index(0, j), dummy); } + if (board[m - 1][j] == 'O') { uf.union(index(m - 1, j), dummy); } + } + + // 方向数组 d 是上下左右搜索的常用手法 + for (int i = 1; i < m - 1; i++) { + for (int j = 1; j < n - 1; j++) { if (board[i][j] == 'O') { - if (i == 0 || i == m - 1 || j == 0 || j == n - 1) { - // 边界上的 O,把它和 dummy 合并成一个连通区域. - uf.union(node(i, j), dummy); - } else { - // 和上下左右合并成一个连通区域 - if (i > 0 && board[i - 1][j] == 'O') { - uf.union(node(i, j), node(i - 1, j)); - } - if (i < m - 1 && board[i + 1][j] == 'O') { - uf.union(node(i, j), node(i + 1, j)); - } - if (j > 0 && board[i][j - 1] == 'O') { - uf.union(node(i, j), node(i, j - 1)); - } - if (j < n - 1 && board[i][j + 1] == 'O') { - uf.union(node(i, j), node(i, j + 1)); + // 将此 O 与上下左右的 O 连通 + for (int[] d : direct) { + int x = i + d[0], y = j + d[1]; + if (board[x][y] == 'O') { + uf.union(index(x, y), index(i, j)); } } } } } - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - if (uf.connected(node(i, j), dummy)) { - // 和 dummy 在一个连通区域的,那么就是 O - board[i][j] = 'O'; - } else { + // 所有不和 dummy 连通的 O,都要被替换 + for (int i = 1; i < m - 1; i++) { + for (int j = 1; j < n - 1; j++) { + int index = index(i, j); + if (!uf.connected(index, dummy)) { board[i][j] = 'X'; } } } } - int node(int i, int j) { - return i * n + j; + public int index(int row, int col) { + return row * n + col; } static class UF { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" index 1f5ec87..c2d9a86 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" @@ -11,9 +11,7 @@ public class 不同的二叉搜索树 { public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(5, s.numTrees(3)); Assertions.assertEquals(1, s.numTrees(1)); } @@ -23,29 +21,29 @@ static class Solution { // 备忘录 int[][] memo; - int numTrees(int n) { - // 备忘录的值初始化为 0 + // 主函数 + public int numTrees(int n) { + // 备忘录的值初始化 memo = new int[n + 1][n + 1]; + // 计算闭区间 [1, n] 组成的 BST 个数 return count(1, n); } - // 定义:返回 [begin, end] 范围内构造的不同 BST 的数量 - int count(int begin, int end) { - if (begin >= end) return 1; - // 查备忘录 - if (memo[begin][end] != 0) { - return memo[begin][end]; - } + // 计算闭区间 [lo, hi] 组成的 BST 个数 + int count(int low, int high) { + // base case + if (low > high) { return 1; } + if (memo[low][high] != 0) { return memo[low][high]; } int res = 0; - for (int mid = begin; mid <= end; mid++) { - int left = count(begin, mid - 1); - int right = count(mid + 1, end); + for (int i = low; i <= high; i++) { + // i 的值作为根节点 root + int left = count(low, i - 1); + int right = count(i + 1, high); + // 左右子树的组合数乘积是 BST 的总数 res += left * right; } - // 将结果存入备忘录 - memo[begin][end] = res; - + memo[low][high] = res; return res; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" index fee5b65..19d183b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" @@ -52,20 +52,20 @@ public List generateTrees(int n) { return build(1, n); } - // 构造闭区间 [lo, hi] 组成的 BST - List build(int lo, int hi) { + // 构造闭区间 [low, high] 组成的 BST + List build(int low, int high) { List res = new LinkedList<>(); // base case - if (lo > hi) { + if (low > high) { res.add(null); return res; } // 1、穷举 root 节点的所有可能。 - for (int i = lo; i <= hi; i++) { + for (int i = low; i <= high; i++) { // 2、递归构造出左右子树的所有合法 BST。 - List leftTree = build(lo, i - 1); - List rightTree = build(i + 1, hi); + List leftTree = build(low, i - 1); + List rightTree = build(i + 1, high); // 3、给 root 节点穷举所有左右子树的组合。 for (TreeNode left : leftTree) { for (TreeNode right : rightTree) { diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\345\255\220\346\240\221\347\232\204\346\234\200\345\244\247\351\224\256\345\200\274\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\345\255\220\346\240\221\347\232\204\346\234\200\345\244\247\351\224\256\345\200\274\345\222\214.java" index e4c8092..42aa113 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\345\255\220\346\240\221\347\232\204\346\234\200\345\244\247\351\224\256\345\200\274\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\345\255\220\346\240\221\347\232\204\346\234\200\345\244\247\351\224\256\345\200\274\345\222\214.java" @@ -24,7 +24,7 @@ public static void main(String[] args) { static class Solution { // 记录 BST 最大节点之和 - int maxSum = 0; + private int maxSum = 0; public int maxSumBST(TreeNode root) { maxSum = 0; @@ -67,7 +67,6 @@ int[] findMaxMinSum(TreeNode root) { res[0] = 0; // 其他的值都没必要计算了,因为用不到 } - // ************************ return res; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" index c705bf3..5b8039e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" @@ -29,16 +29,21 @@ public static void main(String[] args) { static class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { - if (root == null) { return null; } + if (root == null) return null; if (p.val > q.val) { + // 保证 p.val <= q.val,便于后续情况讨论 return lowestCommonAncestor(root, q, p); } - if (p.val <= root.val && root.val <= q.val) { + if (root.val >= p.val && root.val <= q.val) { + // p <= root <= q + // 即 p 和 q 分别在 root 的左右子树,那么 root 就是 LCA return root; } if (root.val > q.val) { + // p 和 q 都在 root 的左子树,那么 LCA 在左子树 return lowestCommonAncestor(root.left, p, q); } else { + // p 和 q 都在 root 的右子树,那么 LCA 在右子树 return lowestCommonAncestor(root.right, p, q); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" index a4cd7f7..884b648 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" @@ -19,35 +19,31 @@ public static void main(String[] args) { static class Solution { + private int pre; private int res; public int minDiffInBST(TreeNode root) { - res = 0; - int rightMin = getMin(root.right); - int leftMax = getMax(root.left); - res = min(root.val, rightMin, leftMax); + pre = -1; + res = Integer.MAX_VALUE; + dfs(root); return res; } - public int getMin(TreeNode root) { - if (root.left != null) { - return getMin(root.left); - } - return root.val; - } + public void dfs(TreeNode root) { + // base case + if (root == null) { return; } - public int getMax(TreeNode root) { - if (root.right != null) { - return getMax(root.right); + // 【前序】 + dfs(root.left); + + // 【中序】中序保证递增有序 + if (pre != -1) { + res = Math.min(res, Math.abs(root.val - pre)); } - return root.val; - } + pre = root.val; - public int min(int a, int b, int c) { - int min = 0; - min = Math.min(Math.abs(a - b), Math.abs(a - c)); - min = Math.min(min, Math.abs(b - c)); - return min; + // 【后序】 + dfs(root.right); } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" index 60f113b..c3a3959 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Assertions; import java.util.ArrayList; -import java.util.LinkedList; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -38,34 +38,27 @@ public static void main(String[] args) { static class Solution { - Set delSet; - // 记录森林的根节点 - List res; + private List res; public List delNodes(TreeNode root, int[] to_delete) { - if (root == null) return new LinkedList<>(); - for (int d : to_delete) { - delSet.add(d); + res = new ArrayList<>(); + Set set = new HashSet<>(); + for (int val : to_delete) { + set.add(val); } - doDelete(root, false); + delNodes(root, set, false); return res; } - // 定义:输入一棵二叉树,删除 delSet 中的节点,返回删除完成后的根节点 - private TreeNode doDelete(TreeNode root, boolean hasParent) { - if (root == null) { - return null; - } - // 判断是否需要被删除 - boolean deleted = delSet.contains(root.val); + public TreeNode delNodes(TreeNode root, Set set, boolean hasParent) { + if (root == null) { return null; } + boolean deleted = set.contains(root.val); if (!deleted && !hasParent) { - // 没有父节点且不需要被删除,就是一个新的根节点 res.add(root); } - // 去左右子树进行删除 - root.left = doDelete(root.left, !deleted); - root.right = doDelete(root.right, !deleted); - // 如果需要被删除,返回 null 给父节点 + + root.left = delNodes(root.left, set, !deleted); + root.right = delNodes(root.right, set, !deleted); return deleted ? null : root; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" index 6be6338..e943be3 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" @@ -23,41 +23,51 @@ public static void main(String[] args) { static class Solution { - LinkedList[] memo = null; + // 备忘录,记录 n 个节点能够组合成的所有可能二叉树 + List[] memo; public List allPossibleFBT(int n) { - - if (memo == null) { - memo = new LinkedList[n + 1]; + if (n % 2 == 0) { + // 题目描述的满二叉树不可能是偶数个节点 + return new LinkedList<>(); } + memo = new LinkedList[n + 1]; + return build(n); + } - LinkedList res = new LinkedList<>(); - // 根据真二叉树定义,节点数必为奇数 - if (n % 2 == 0) { + // 定义:输入一个 n,生成节点树为 n 的所有可能的满二叉树 + public List build(int n) { + List res = new LinkedList<>(); + // base case + if (n == 1) { + res.add(new TreeNode(0)); return res; } if (memo[n] != null) { + // 避免冗余计算 return memo[n]; } - if (n == 1) { - res.add(new TreeNode(0)); - memo[n] = res; - return res; - } - for (int leftNum = 1; leftNum < n; leftNum += 2) { - int rightNum = n - leftNum - 1; - List leftSubTree = allPossibleFBT(leftNum); - List rightSubTree = allPossibleFBT(rightNum); - for (TreeNode left : leftSubTree) { - for (TreeNode right : rightSubTree) { - TreeNode node = new TreeNode(0); - node.left = left; - node.right = right; - res.add(node); + // 递归生成所有符合条件的左右子树 + for (int i = 1; i < n; i += 2) { + int j = n - i - 1; + // 利用函数定义,生成左右子树 + List leftSubTrees = build(i); + List rightSubTrees = build(j); + // 左右子树的不同排列也能构成不同的二叉树 + for (TreeNode left : leftSubTrees) { + for (TreeNode right : rightSubTrees) { + // 生成根节点 + TreeNode root = new TreeNode(0); + // 组装出一种可能的二叉树形状 + root.left = left; + root.right = right; + // 加入结果列表 + res.add(root); } } } + // 存入备忘录 memo[n] = res; return res; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" index 90fb4f9..4cac6df 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" @@ -28,17 +28,19 @@ public static void main(String[] args) { static class Solution { public TreeNode insertIntoMaxTree(TreeNode root, int val) { - if (root == null) { return new TreeNode(val); } - - if (val > root.val) { - TreeNode temp = root; - root = new TreeNode(val); - root.left = temp; + if (root.val < val) { + // 如果 val 是整棵树最大的,那么原来的这棵树应该是 val 节点的左子树, + // 因为 val 节点是接在原始数组 a 的最后一个元素 + TreeNode node = new TreeNode(val); + node.left = root; + return node; } else { + // 如果 val 不是最大的,那么就应该在右子树上, + // 因为 val 节点是接在原始数组 a 的最后一个元素 root.right = insertIntoMaxTree(root.right, val); + return root; } - return root; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" index 6c7a1b7..f3d1c1f 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" @@ -22,6 +22,7 @@ public static void main(String[] args) { static class Solution { + // 定义:输入两棵二叉树,判断这两棵二叉树是否是翻转等价的 public boolean flipEquiv(TreeNode root1, TreeNode root2) { // 判断 root1 和 root2 两个节点是否能够匹配 if (root1 == null && root2 == null) { return true; } @@ -29,13 +30,8 @@ public boolean flipEquiv(TreeNode root1, TreeNode root2) { if (root1.val != root2.val) { return false; } // 根据函数定义,判断子树是否能够匹配 // 不翻转、翻转两种情况满足一种即可算是匹配 - return ( - // 不翻转子树 - flipEquiv(root1.left, root2.left) && flipEquiv(root1.right, root2.right) - ) || ( - // 反转子树 - flipEquiv(root1.left, root2.right) && flipEquiv(root1.right, root2.left) - ); + return (flipEquiv(root1.left, root2.left) && flipEquiv(root1.right, root2.right)) // 不翻转子树 + || (flipEquiv(root1.left, root2.right) && flipEquiv(root1.right, root2.left)); // 翻转子树 } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" index 47c3c79..976393b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" @@ -4,40 +4,77 @@ import org.junit.jupiter.api.Assertions; /** - * 236. 二叉树的最近公共祖先 算法实现 - * - * @see 236. 二叉树的最近公共祖先 - * @see 236. 二叉树的最近公共祖先 + * 解题思路 + * + * @author Zhang Peng + * @date 2020-01-28 */ public class 二叉树的最近公共祖先 { public static void main(String[] args) { Solution s = new Solution(); + TreeNode input = TreeNode.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); + TreeNode output1 = s.lowestCommonAncestor(input, TreeNode.find(input, 2), TreeNode.find(input, 8)); + Assertions.assertNotNull(output1); + Assertions.assertEquals(6, output1.val); + TreeNode output2 = s.lowestCommonAncestor(input, TreeNode.find(input, 2), TreeNode.find(input, 4)); + Assertions.assertNotNull(output2); + Assertions.assertEquals(2, output2.val); - TreeNode root = TreeNode.buildTree(3, 5, 1, 6, 2, 0, 8, null, null, 7, 4); - TreeNode node1 = s.lowestCommonAncestor(root, TreeNode.find(root, 5), TreeNode.find(root, 1)); - Assertions.assertNotNull(node1); - Assertions.assertEquals(3, node1.val); - - TreeNode node2 = s.lowestCommonAncestor(root, TreeNode.find(root, 5), TreeNode.find(root, 4)); - Assertions.assertNotNull(node2); - Assertions.assertEquals(5, node2.val); + Solution2 s2 = new Solution2(); + TreeNode input2 = TreeNode.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); + TreeNode output3 = s2.lowestCommonAncestor(input2, TreeNode.find(input2, 2), TreeNode.find(input2, 8)); + Assertions.assertNotNull(output3); + Assertions.assertEquals(6, output3.val); + TreeNode output4 = s2.lowestCommonAncestor(input2, TreeNode.find(input2, 2), TreeNode.find(input2, 4)); + Assertions.assertNotNull(output4); + Assertions.assertEquals(2, output4.val); } static class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { - if (root == null) { return null; } - if (root == p || root == q) { return root; } + if (root == null) return null; + if (root == p || root == q) return root; TreeNode left = lowestCommonAncestor(root.left, p, q); TreeNode right = lowestCommonAncestor(root.right, p, q); + if (left != null && right != null) { return root; } - if (left == null && right == null) { return null; } - return left == null ? right : left; + return left != null ? left : right; + } + + } + + static class Solution2 { + + private TreeNode res = null; + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + res = null; + return find(root, p.val, q.val); + } + + TreeNode find(TreeNode root, int p, int q) { + if (root == null) { return null; } + // 如果已经找到 LCA 节点,直接返回 + if (res != null) { return res; } + + if (root.val == p || root.val == q) return root; + + TreeNode left = find(root.left, p, q); + TreeNode right = find(root.right, p, q); + + if (left != null && right != null) { + // 当前节点是 LCA 节点,记录下来 + res = root; + return res; + } + return left != null ? left : right; } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java index 2a581a3..30b14d1 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java @@ -7,12 +7,23 @@ import java.util.Random; /** + * 数组工具类 + * * @author Zhang Peng */ @Slf4j public class ArrayUtil { - public static List> toListList(int[][] arr) { + public static int[] toIntArray(List list) { + if (list == null || list.isEmpty()) { return new int[0]; } + int[] res = new int[list.size()]; + for (int i = 0; i < list.size(); i++) { + res[i] = list.get(i); + } + return res; + } + + public static List> toIntMatrixList(int[][] arr) { if (arr == null || arr.length == 0) { return new ArrayList<>(); } List> listlist = new ArrayList<>(); for (int i = 0; i < arr.length; i++) { @@ -25,15 +36,31 @@ public static List> toListList(int[][] arr) { return listlist; } - public static int[][] toMatrixArray(List> listlist) { + public static int[][] toIntMatrixArray(List> listlist) { if (listlist == null || listlist.size() == 0) { return new int[0][0]; } - int[][] arr = new int[listlist.size()][listlist.get(0).size()]; - for (int i = 0; i < listlist.size(); i++) { - for (int j = 0; j < listlist.get(i).size(); j++) { - arr[i][j] = listlist.get(i).get(j); - } + List arrList = new ArrayList<>(); + for (List list : listlist) { + arrList.add(toIntArray(list)); + } + return arrList.toArray(new int[listlist.size()][]); + } + + public static String[] toStringArray(List list) { + if (list == null || list.isEmpty()) { return new String[0]; } + String[] res = new String[list.size()]; + for (int i = 0; i < list.size(); i++) { + res[i] = list.get(i); + } + return res; + } + + public static String[][] toStringMatrixArray(List> listlist) { + if (listlist == null || listlist.size() == 0) { return new String[0][0]; } + List arrList = new ArrayList<>(); + for (List list : listlist) { + arrList.add(toStringArray(list)); } - return arr; + return arrList.toArray(new String[listlist.size()][]); } public static void printArray(T[] arr, int begin, int end, String tip) { From b85ae2ea4a60b2c71b04a7d07f1a3d73370aef22 Mon Sep 17 00:00:00 2001 From: dunwu Date: Fri, 19 Dec 2025 22:02:29 +0800 Subject: [PATCH 21/21] =?UTF-8?q?feat:=20leetcode=20=E5=88=B7=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 92 +++++----- .../dunwu/algorithm/bfs/package-info.java | 7 + ...\346\263\225\346\250\241\346\235\277.java" | 51 ++++++ ...\347\237\255\350\267\257\345\276\204.java" | 70 +++++++ ...\346\217\222\345\205\245\345\231\250.java" | 48 +++-- ...\350\275\254\347\233\230\351\224\201.java" | 56 +++--- ...\345\233\240\345\217\230\345\214\226.java" | 58 ++---- ...\345\243\266\351\227\256\351\242\230.java" | 83 +++++++++ ...\347\232\204\346\251\230\345\255\220.java" | 97 +++++----- ...\346\210\267\345\220\210\345\271\266.java" | 96 +++++++++- ...\347\232\204\345\207\272\345\217\243.java" | 61 +++---- ...\345\222\214\346\210\277\351\227\264.java" | 28 +-- .../algorithm/dfs/island/package-info.java | 7 + ...\345\261\277\346\225\260\351\207\217.java" | 51 +++--- ...\345\244\247\351\235\242\347\247\257.java" | 54 +++--- ...\345\255\220\345\262\233\345\261\277.java" | 58 +++--- ...\347\232\204\346\225\260\347\233\256.java" | 68 ++++--- ...\347\232\204\346\225\260\351\207\217.java" | 58 +++--- .../dp/array/\344\270\221\346\225\2602.java" | 52 +----- .../dp/array/\344\270\221\346\225\2603.java" | 15 +- ...\344\275\216\347\245\250\344\273\267.java" | 58 ++++++ ...\346\226\271\346\241\210\346\225\260.java" | 26 +-- ...\347\240\201\346\226\271\346\263\225.java" | 103 +++++++++++ ...\351\222\261\345\205\221\346\215\242.java" | 56 +++++- ...\350\257\215\346\213\206\345\210\206.java" | 88 ++++++++- ...\351\242\230\346\250\241\346\235\277.java" | 22 +++ ...\347\232\204\350\212\202\347\202\271.java" | 42 +++++ ...\345\244\215\345\205\203\347\264\240.java" | 39 ++-- ...\347\272\247\344\270\221\346\225\260.java" | 16 +- .../stack/monotonic/package-info.java | 2 +- ...\345\244\247\345\205\203\347\264\240.java" | 17 +- ...345\244\247\345\205\203\347\264\2402.java" | 19 +- ...\345\255\220\346\225\260\347\273\204.java" | 35 ++++ ...\344\275\215\346\225\260\345\255\227.java" | 30 +-- ...\346\240\274\350\267\250\345\272\246.java" | 63 +++++-- .../monotonic/\350\275\246\344\275\215.java" | 42 +++-- ...\347\232\204\344\272\272\346\225\260.java" | 45 +++++ ...\346\263\225\346\250\241\346\235\277.java" | 172 ++++++++++++++++++ ...\345\276\204\346\200\273\345\222\214.java" | 45 ++--- .../dunwu/algorithm/util/ArrayUtil.java | 12 ++ 40 files changed, 1432 insertions(+), 610 deletions(-) create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/package-info.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/template/BFS\347\256\227\346\263\225\346\250\241\346\235\277.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\344\270\255\347\232\204\346\234\200\347\237\255\350\267\257\345\276\204.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\260\264\345\243\266\351\227\256\351\242\230.java" create mode 100644 codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/package-info.java create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\346\234\200\344\275\216\347\245\250\344\273\267.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\247\243\347\240\201\346\226\271\346\263\225.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/template/\345\212\250\346\200\201\350\247\204\345\210\222\350\247\243\350\203\214\345\214\205\351\227\256\351\242\230\346\250\241\346\235\277.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/base/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\350\212\202\347\202\271.java" rename "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" => "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\266\205\347\272\247\344\270\221\346\225\260.java" (84%) create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\351\230\237\345\210\227\344\270\255\345\217\257\344\273\245\347\234\213\345\210\260\347\232\204\344\272\272\346\225\260.java" create mode 100644 "codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/template/\345\215\225\350\260\203\346\240\210\347\256\227\346\263\225\346\250\241\346\235\277.java" diff --git a/README.md b/README.md index 67f1048..af71637 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,8 @@ | [面试题 02.01. 移除重复节点](https://leetcode.cn/problems/remove-duplicate-node-lcci/) | 💚 | ✔️ | | [203. 移除链表元素](https://leetcode.cn/problems/remove-linked-list-elements/) | 💚 | ✔️ | | [328. 奇偶链表](https://leetcode.cn/problems/odd-even-linked-list/) | 💛 | ✔️ | +| [LCR 136. 删除链表的节点](https://leetcode.cn/problems/shan-chu-lian-biao-de-jie-dian-lcof/) | 💚 | ✔️ | +| [83. 删除排序链表中的重复元素](https://leetcode.cn/problems/remove-duplicates-from-sorted-list/) | 💚 | ✔️ | | [82. 删除排序链表中的重复元素 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/) | 💛 | ✔️ | | [2. 两数相加](https://leetcode.cn/problems/add-two-numbers/) | 💛 | ✔️ | | [445. 两数相加 II](https://leetcode.cn/problems/add-two-numbers-ii/) | 💛 | ✔️ | @@ -207,10 +209,10 @@ | [225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/) | 💚 | ✔️ | | [933. 最近的请求次数](https://leetcode.cn/problems/number-of-recent-calls/) | 💚 | ❗ | | [622. 设计循环队列](https://leetcode.cn/problems/design-circular-queue/) | 💛 | ❌ | -| [641. 设计循环双端队列](https://leetcode.cn/problems/design-circular-deque/) | 💛 | | -| [1670. 设计前中后队列](https://leetcode.cn/problems/design-front-middle-back-queue/) | 💛 | | +| [641. 设计循环双端队列](https://leetcode.cn/problems/design-circular-deque/) | 💛 | ❌ | +| [1670. 设计前中后队列](https://leetcode.cn/problems/design-front-middle-back-queue/) | 💛 | ❌ | | [2073. 买票需要的时间](https://leetcode.cn/problems/time-needed-to-buy-tickets/) | 💚 | ✔️ | -| [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | 💛 | | +| [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | 💛 | ❌ | | [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | 💛 | ❌ | #### 栈 @@ -233,11 +235,11 @@ | 题目 | 难度 | 掌握度 | | ----------------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | -| [496. 下一个更大元素 I](https://leetcode.cn/problems/next-greater-element-i/) | 💚 | ❗ | -| [503. 下一个更大元素 II](https://leetcode.cn/problems/next-greater-element-ii/) | 💛 | ❗ | +| [496. 下一个更大元素 I](https://leetcode.cn/problems/next-greater-element-i/) | 💚 | ✔️ | +| [503. 下一个更大元素 II](https://leetcode.cn/problems/next-greater-element-ii/) | 💛 | ✔️ | | [739. 每日温度](https://leetcode.cn/problems/daily-temperatures/)
[剑指 Offer II 038. 每日温度](https://leetcode.cn/problems/iIQa4I/) | 💛 | ✔️ | | [1019. 链表中的下一个更大节点](https://leetcode.cn/problems/next-greater-node-in-linked-list/) | 💛 | ✔️ | -| [1944. 队列中可以看到的人数](https://leetcode.cn/problems/number-of-visible-people-in-a-queue/) | ❤️ | | +| [1944. 队列中可以看到的人数](https://leetcode.cn/problems/number-of-visible-people-in-a-queue/) | ❤️ | ❌ | | [1475. 商品折扣后的最终价格](https://leetcode.cn/problems/final-prices-with-a-special-discount-in-a-shop/) | 💛 | ✔️ | | [901. 股票价格跨度](https://leetcode.cn/problems/online-stock-span/) | 💛 | ❌ | | [402. 移掉 K 位数字](https://leetcode.cn/problems/remove-k-digits/) | 💛 | ❌ | @@ -248,11 +250,11 @@ | 题目 | 难度 | 掌握度 | | -------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | -| [LCR 184. 设计自助结算系统](https://leetcode.cn/problems/dui-lie-de-zui-da-zhi-lcof/) | 💛 | | +| [LCR 184. 设计自助结算系统](https://leetcode.cn/problems/dui-lie-de-zui-da-zhi-lcof/) | 💛 | ❌ | | [239. 滑动窗口最大值](https://leetcode.cn/problems/sliding-window-maximum/) | ❤️ | ❌ | -| [1438. 绝对差不超过限制的最长连续子数组](https://leetcode.cn/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit/) | 💛 | | -| [862. 和至少为 K 的最短子数组](https://leetcode.cn/problems/shortest-subarray-with-sum-at-least-k/) | ❤️ | | -| [918. 环形子数组的最大和](https://labuladong.online/algo/problem-set/monotonic-queue/#slug_maximum-sum-circular-subarray) | 💛 | | +| [1438. 绝对差不超过限制的最长连续子数组](https://leetcode.cn/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit/) | 💛 | ❌ | +| [862. 和至少为 K 的最短子数组](https://leetcode.cn/problems/shortest-subarray-with-sum-at-least-k/) | ❤️ | ❌ | +| [918. 环形子数组的最大和](https://labuladong.online/algo/problem-set/monotonic-queue/#slug_maximum-sum-circular-subarray) | 💛 | ❌ | ### 树 @@ -409,24 +411,24 @@ | 题目 | 难度 | 掌握度 | | :--------------------------------------------------------------------- | ---- | ------ | -| [46. 全排列](https://leetcode.cn/problems/permutations/) | 💛 | ❗ | -| [47. 全排列 II](https://leetcode.cn/problems/permutations-ii/) | 💛 | ❗ | -| [78. 子集](https://leetcode.cn/problems/subsets/) | 💛 | ❗ | -| [90. 子集 II](https://leetcode.cn/problems/subsets-ii/) | 💛 | ❗ | -| [77. 组合](https://leetcode.cn/problems/combinations/) | 💛 | ❗ | -| [39. 组合总和](https://leetcode.cn/problems/combination-sum/) | 💛 | ❗ | -| [40. 组合总和 II](https://leetcode.cn/problems/combination-sum-ii/) | 💛 | ❗ | -| [216. 组合总和 III](https://leetcode.cn/problems/combination-sum-iii/) | 💛 | ❗ | +| [46. 全排列](https://leetcode.cn/problems/permutations/) | 💛 | ✔️ | +| [47. 全排列 II](https://leetcode.cn/problems/permutations-ii/) | 💛 | ✔️ | +| [78. 子集](https://leetcode.cn/problems/subsets/) | 💛 | ✔️ | +| [90. 子集 II](https://leetcode.cn/problems/subsets-ii/) | 💛 | ✔️ | +| [77. 组合](https://leetcode.cn/problems/combinations/) | 💛 | ✔️ | +| [39. 组合总和](https://leetcode.cn/problems/combination-sum/) | 💛 | ✔️ | +| [40. 组合总和 II](https://leetcode.cn/problems/combination-sum-ii/) | 💛 | ✔️ | +| [216. 组合总和 III](https://leetcode.cn/problems/combination-sum-iii/) | 💛 | ✔️ | #### 岛屿问题 | 题目 | 难度 | 掌握度 | | :--------------------------------------------------------------------------------- | ---- | ------ | -| [1020. 飞地的数量](https://leetcode.cn/problems/number-of-enclaves/) | 💛 | ❌ | -| [1254. 统计封闭岛屿的数目](https://leetcode.cn/problems/number-of-closed-islands/) | 💛 | ❌ | +| [200. 岛屿数量](https://leetcode.cn/problems/number-of-islands/) | 💛 | ❗ | +| [1254. 统计封闭岛屿的数目](https://leetcode.cn/problems/number-of-closed-islands/) | 💛 | ❗ | +| [1020. 飞地的数量](https://leetcode.cn/problems/number-of-enclaves/) | 💛 | ❗ | +| [695. 岛屿的最大面积](https://leetcode.cn/problems/max-area-of-island/) | 💛 | ❗ | | [1905. 统计子岛屿](https://leetcode.cn/problems/count-sub-islands/) | 💛 | ❌ | -| [200. 岛屿数量](https://leetcode.cn/problems/number-of-islands/) | 💛 | ❌ | -| [695. 岛屿的最大面积](https://leetcode.cn/problems/max-area-of-island/) | 💛 | ❌ | #### 数独、N 皇后问题 @@ -449,7 +451,6 @@ | [89. 格雷编码](https://leetcode.cn/problems/gray-code/) | 💛 | ❌ | | [17. 电话号码的字母组合](https://leetcode.cn/problems/letter-combinations-of-a-phone-number/) | 💛 | ❌ | | [79. 单词搜索](https://leetcode.cn/problems/word-search/) | 💛 | ❌ | -| [473. 火柴拼正方形](https://leetcode.cn/problems/matchsticks-to-square/) | 💛 | ❌ | ### BFS @@ -457,15 +458,15 @@ | :----------------------------------------------------------------------------------------------- | :--: | ------ | | [752. 打开转盘锁](https://leetcode.cn/problems/open-the-lock/) | 💛 | ❌ | | [773. 滑动谜题](https://leetcode.cn/problems/sliding-puzzle/) | ❤️ | ❌ | -| [919. 完全二叉树插入器](https://leetcode.cn/problems/complete-binary-tree-inserter/) | 💛 | ❗ | +| [919. 完全二叉树插入器](https://leetcode.cn/problems/complete-binary-tree-inserter/) | 💛 | ✔️ | | [841. 钥匙和房间](https://leetcode.cn/problems/keys-and-rooms/) | 💛 | ✔️ | | [433. 最小基因变化](https://leetcode.cn/problems/minimum-genetic-mutation/) | 💛 | ❗ | | [1926. 迷宫中离入口最近的出口](https://leetcode.cn/problems/nearest-exit-from-entrance-in-maze/) | 💛 | ✔️ | -| [1091. 二进制矩阵中的最短路径](https://leetcode.cn/problems/shortest-path-in-binary-matrix/) | 💛 | ❌ | -| [994. 腐烂的橘子](https://leetcode.cn/problems/rotting-oranges/) | 💛 | ❌ | -| [721. 账户合并](https://leetcode.cn/problems/accounts-merge/) | 💛 | ❓ | -| [127. 单词接龙](https://leetcode.cn/problems/word-ladder/) | 🔴 | | -| [365. 水壶问题](https://leetcode.cn/problems/water-and-jug-problem/) | 💛 | ❓ | +| [1091. 二进制矩阵中的最短路径](https://leetcode.cn/problems/shortest-path-in-binary-matrix/) | 💛 | ✔️ | +| [994. 腐烂的橘子](https://leetcode.cn/problems/rotting-oranges/) | 💛 | ✔️ | +| [365. 水壶问题](https://leetcode.cn/problems/water-and-jug-problem/) | 💛 | ❌ | +| [721. 账户合并](https://leetcode.cn/problems/accounts-merge/) | 💛 | ❌ | +| [127. 单词接龙](https://leetcode.cn/problems/word-ladder/) | ❤️ | ❌ | ### 动态规划 @@ -485,12 +486,10 @@ | 题目 | 难度 | 掌握度 | | ------------------------------------------------------------------------------------------------ | :--: | :----: | | [2140. 解决智力问题](https://leetcode.cn/problems/solving-questions-with-brainpower/) | 💛 | ❌ | -| [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | 💛 | ❌ | -| [2466. 统计构造好字符串的方案数](https://leetcode.cn/problems/count-ways-to-build-good-strings/) | 💛 | | -| [91. 解码方法](https://leetcode.cn/problems/decode-ways/) | 💛 | | -| [983. 最低票价](https://leetcode.cn/problems/minimum-cost-for-tickets/) | 💛 | | -| [790. 多米诺和托米诺平铺](https://leetcode.cn/problems/domino-and-tromino-tiling/) | 💛 | | -| [264. 丑数 II](https://leetcode.cn/problems/ugly-number-ii/) | 💛 | ❌ | +| [2466. 统计构造好字符串的方案数](https://leetcode.cn/problems/count-ways-to-build-good-strings/) | 💛 | ❌ | +| [91. 解码方法](https://leetcode.cn/problems/decode-ways/) | 💛 | ❌ | +| [983. 最低票价](https://leetcode.cn/problems/minimum-cost-for-tickets/) | 💛 | ❌ | +| [264. 丑数 II](https://leetcode.cn/problems/ugly-number-ii/) | 💛 | ❗ | | [1201. 丑数 III](https://leetcode.cn/problems/ugly-number-iii/) | 💛 | ❌ | | [313. 超级丑数](https://leetcode.cn/problems/super-ugly-number/) | 💛 | ❌ | @@ -511,12 +510,12 @@ | 题目 | 难度 | 掌握度 | | ---------------------------------------------------------------------------------------------------------- | :--: | :----: | -| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 💛 | ❌ | +| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 💛 | ✔️ | | [139. 单词拆分](https://leetcode.cn/problems/word-break/) | 💛 | ❌ | -| [516. 最长回文子序列](https://leetcode.cn/problems/longest-palindromic-subsequence/) | 💛 | ❌ | | [72. 编辑距离](https://leetcode.cn/problems/edit-distance/) | 💛 | ❗ | -| [583. 两个字符串的删除操作](https://leetcode.cn/problems/delete-operation-for-two-strings/) | 💛 | | +| [583. 两个字符串的删除操作](https://leetcode.cn/problems/delete-operation-for-two-strings/) | 💛 | ❌ | | [712. 两个字符串的最小ASCII删除和](https://leetcode.cn/problems/minimum-ascii-delete-sum-for-two-strings/) | 💛 | ❌ | +| [516. 最长回文子序列](https://leetcode.cn/problems/longest-palindromic-subsequence/) | 💛 | ❌ | | [115. 不同的子序列](https://leetcode.cn/problems/distinct-subsequences/) | ❤️ | ❌ | #### 最长递增/公共子序列 @@ -532,25 +531,30 @@ | [1035. 不相交的线](https://leetcode.cn/problems/uncrossed-lines/) | 💛 | ❌ | | [1312. 让字符串成为回文串的最少插入次数](https://leetcode.cn/problems/minimum-insertion-steps-to-make-a-string-palindrome/) | ❤️ | ❌ | +#### 背包问题 + +| 题目 | 难度 | 掌握度 | +| ----------------------------------------------------------------------------- | ---- | ------ | +| [416. 分割等和子集](https://leetcode.cn/problems/partition-equal-subset-sum/) | 💛 | ❌ | +| [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | 💛 | ❌ | +| [518. 零钱兑换 II](https://leetcode.cn/problems/coin-change-ii/) | 💛 | ❌ | + #### 买卖股票的最佳时间/状态机 #### 其他 | 题目 | 难度 | 掌握度 | | ------------------------------------------------------------------------------- | ---- | ------ | -| [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | 💛 | ❌ | -| [354. 俄罗斯套娃信封问题](https://leetcode.cn/problems/russian-doll-envelopes/) | ❤️ | | | [53. 最大子数组和](https://leetcode.cn/problems/maximum-subarray/) | 💛 | ❌ | -| [416. 分割等和子集](https://leetcode.cn/problems/partition-equal-subset-sum/) | | | -| [518. 零钱兑换 II](https://leetcode.cn/problems/coin-change-ii/) | | | +| [354. 俄罗斯套娃信封问题](https://leetcode.cn/problems/russian-doll-envelopes/) | ❤️ | ❌ | ### 贪心算法 | 题目 | 难度 | 掌握度 | | -------------------------------------------------------------- | ---- | ------ | | [561. 数组拆分](https://leetcode.cn/problems/array-partition/) | 💚 | ❌ | -| [55. 跳跃游戏](https://leetcode.cn/problems/jump-game/) | 💛 | | -| [45. 跳跃游戏 II](https://leetcode.cn/problems/jump-game-ii/) | 💛 | | +| [55. 跳跃游戏](https://leetcode.cn/problems/jump-game/) | 💛 | ❌ | +| [45. 跳跃游戏 II](https://leetcode.cn/problems/jump-game-ii/) | 💛 | ❌ | ### 分治算法 diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/package-info.java new file mode 100644 index 0000000..04a66a6 --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/package-info.java @@ -0,0 +1,7 @@ +/** + * 通过 BFS 解最短路径类型问题 + * + * @author Zhang Peng + * @date 2025-12-15 + */ +package io.github.dunwu.algorithm.bfs; \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/template/BFS\347\256\227\346\263\225\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/template/BFS\347\256\227\346\263\225\346\250\241\346\235\277.java" new file mode 100644 index 0000000..0448d03 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/template/BFS\347\256\227\346\263\225\346\250\241\346\235\277.java" @@ -0,0 +1,51 @@ +package io.github.dunwu.algorithm.bfs.template; + +import io.github.dunwu.algorithm.graph.Edge; +import io.github.dunwu.algorithm.graph.Graph; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * BFS 算法模板 + * + * @author Zhang Peng + * @date 2025-12-15 + */ +public class BFS算法模板 { + + private Graph graph; + + // 从 s 开始 BFS 遍历图的所有节点,且记录遍历的步数 + // 当走到目标节点 target 时,返回步数 + int bfs(int s, int target) { + boolean[] visited = new boolean[graph.size()]; + Queue q = new LinkedList<>(); + q.offer(s); + visited[s] = true; + // 记录从 s 开始走到当前节点的步数 + int step = 0; + while (!q.isEmpty()) { + int sz = q.size(); + for (int i = 0; i < sz; i++) { + int cur = q.poll(); + System.out.println("visit " + cur + " at step " + step); + // 判断是否到达终点 + if (cur == target) { + return step; + } + // 将邻居节点加入队列,向四周扩散搜索 + for (Edge e : graph.neighbors(cur)) { + if (!visited[e.to]) { + q.offer(e.to); + visited[e.to] = true; + } + } + } + step++; + } + // 如果走到这里,说明在图中没有找到目标节点 + return -1; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\344\270\255\347\232\204\346\234\200\347\237\255\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\344\270\255\347\232\204\346\234\200\347\237\255\350\267\257\345\276\204.java" new file mode 100644 index 0000000..ca60ee9 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\344\270\255\347\232\204\346\234\200\347\237\255\350\267\257\345\276\204.java" @@ -0,0 +1,70 @@ +package io.github.dunwu.algorithm.bfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 1091. 二进制矩阵中的最短路径 + * + * @author Zhang Peng + * @date 2025-12-15 + */ +public class 二进制矩阵中的最短路径 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(2, s.shortestPathBinaryMatrix(new int[][] { { 0, 1 }, { 1, 0 } })); + Assertions.assertEquals(4, s.shortestPathBinaryMatrix(new int[][] { { 0, 0, 0 }, { 1, 1, 0 }, { 1, 1, 0 } })); + Assertions.assertEquals(-1, s.shortestPathBinaryMatrix(new int[][] { { 1, 0, 0 }, { 1, 1, 0 }, { 1, 1, 0 } })); + } + + static class Solution { + + // 八个方向偏移量(上、下、左、右、左上、右下、左下、右上) + private final int[][] directions = { + { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 }, + { -1, -1 }, { 1, 1 }, { -1, 1 }, { 1, -1 } + }; + + public int shortestPathBinaryMatrix(int[][] grid) { + + int m = grid.length, n = grid[0].length; + if (grid[0][0] == 1 || grid[m - 1][n - 1] == 1) { + return -1; + } + + // 需要记录走过的路径,避免死循环 + boolean[][] visited = new boolean[m][n]; + LinkedList queue = new LinkedList<>(); + + // 初始化队列,从 (0, 0) 出发 + visited[0][0] = true; + queue.offer(new int[] { 0, 0 }); + + int step = 1; + while (!queue.isEmpty()) { + int size = queue.size(); + for (int i = 0; i < size; i++) { + int[] cur = queue.poll(); + int x = cur[0], y = cur[1]; + if (grid[x][y] != 0) { return -1; } + // 到达底部,返回步骤数 + if (x == m - 1 && y == n - 1) { return step; } + + for (int[] d : directions) { + int nextX = x + d[0], nextY = y + d[1]; + if (nextX < 0 || nextX >= m || nextY < 0 || nextY >= n) { continue; } + if (visited[nextX][nextY] || grid[nextX][nextY] != 0) { continue; } + visited[nextX][nextY] = true; + queue.offer(new int[] { nextX, nextY }); + } + } + step++; + } + return -1; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" index e51ebae..77990db 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" @@ -23,46 +23,44 @@ public static void main(String[] args) { static class CBTInserter { private final TreeNode root; - private final LinkedList candidate; + // 这个队列只记录完全二叉树底部可以进行插入的节点 + private final LinkedList queue; public CBTInserter(TreeNode root) { this.root = root; - this.candidate = new LinkedList<>(); - - LinkedList queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - int size = queue.size(); + this.queue = new LinkedList<>(); + LinkedList tmp = new LinkedList<>(); + tmp.offer(root); + while (!tmp.isEmpty()) { + int size = tmp.size(); for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - if (node.left != null) { - queue.offer(node.left); - } - if (node.right != null) { - queue.offer(node.right); - } + TreeNode node = tmp.poll(); + if (node == null) { continue; } + if (node.left != null) { tmp.offer(node.left); } + if (node.right != null) { tmp.offer(node.right); } if (node.left == null || node.right == null) { - candidate.offer(node); + // 找到完全二叉树底部可以进行插入的节点 + queue.offer(node); } } } } public int insert(int val) { - TreeNode child = new TreeNode(val); - TreeNode node = candidate.peek(); - if (node.left == null) { - node.left = child; - } else { - node.right = child; - candidate.poll(); + TreeNode node = new TreeNode(val); + TreeNode cur = queue.peek(); + queue.offer(node); + if (cur.left == null) { + cur.left = node; + } else if (cur.right == null) { + cur.right = node; + queue.poll(); } - candidate.offer(child); - return node.val; + return cur.val; } public TreeNode get_root() { - return root; + return this.root; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\211\223\345\274\200\350\275\254\347\233\230\351\224\201.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\211\223\345\274\200\350\275\254\347\233\230\351\224\201.java" index c6e533c..8a4c291 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\211\223\345\274\200\350\275\254\347\233\230\351\224\201.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\211\223\345\274\200\350\275\254\347\233\230\351\224\201.java" @@ -2,6 +2,8 @@ import org.junit.jupiter.api.Assertions; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -22,44 +24,40 @@ public static void main(String[] args) { String[] deadends = new String[] { "0201", "0101", "0102", "1212", "2002" }; Assertions.assertEquals(6, s.openLock(deadends, "0202")); - // String[] deadends2 = new String[] { "8888" }; - // Assertions.assertEquals(1, s.openLock(deadends2, "0009")); - // - // String[] deadends3 = new String[] { "8887", "8889", "8878", "8898", "8788", "8988", "7888", "9888" }; - // Assertions.assertEquals(-1, s.openLock(deadends3, "8888")); + String[] deadends2 = new String[] { "8888" }; + Assertions.assertEquals(1, s.openLock(deadends2, "0009")); + + String[] deadends3 = new String[] { "8887", "8889", "8878", "8898", "8788", "8988", "7888", "9888" }; + Assertions.assertEquals(-1, s.openLock(deadends3, "8888")); } static class Solution { public int openLock(String[] deadends, String target) { - Set black = new HashSet<>(); - for (String d : deadends) { - black.add(d); - } - int step = 0; + + Set blackSet = new HashSet<>(); + Collections.addAll(blackSet, deadends); + + if (blackSet.contains("0000")) { return -1; } + Set visited = new HashSet<>(); LinkedList queue = new LinkedList<>(); - queue.offer("0000"); visited.add("0000"); + queue.offer("0000"); while (!queue.isEmpty()) { int size = queue.size(); - System.out.printf("step: %d\n", step); for (int i = 0; i < size; i++) { - - String node = queue.poll(); - - if (target.equals(node)) { + String cur = queue.poll(); + if (cur.equals(target)) { return step; } - List neighbors = getNeighbors(node); - System.out.printf("\tnode: %s, neighbors: %s\n", node, neighbors); - for (String neighbor : getNeighbors(node)) { - if (!visited.contains(neighbor) && !black.contains(neighbor)) { - queue.offer(neighbor); - visited.add(neighbor); + for (String neighbour : neighbours(cur)) { + if (!visited.contains(neighbour) && !blackSet.contains(neighbour)) { + visited.add(neighbour); + queue.offer(neighbour); } } } @@ -68,7 +66,7 @@ public int openLock(String[] deadends, String target) { return -1; } - String plus(String s, int i) { + public String plus(String s, int i) { char[] ch = s.toCharArray(); if (ch[i] == '9') { ch[i] = '0'; @@ -78,7 +76,7 @@ String plus(String s, int i) { return new String(ch); } - String minus(String s, int i) { + public String minus(String s, int i) { char[] ch = s.toCharArray(); if (ch[i] == '0') { ch[i] = '9'; @@ -88,13 +86,13 @@ String minus(String s, int i) { return new String(ch); } - List getNeighbors(String s) { - List neighbors = new LinkedList<>(); + public List neighbours(String s) { + List neighbours = new ArrayList<>(); for (int i = 0; i < s.length(); i++) { - neighbors.add(plus(s, i)); - neighbors.add(minus(s, i)); + neighbours.add(plus(s, i)); + neighbours.add(minus(s, i)); } - return neighbors; + return neighbours; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\234\200\345\260\217\345\237\272\345\233\240\345\217\230\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\234\200\345\260\217\345\237\272\345\233\240\345\217\230\345\214\226.java" index 72fd5e6..c52c342 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\234\200\345\260\217\345\237\272\345\233\240\345\217\230\345\214\226.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\234\200\345\260\217\345\237\272\345\233\240\345\217\230\345\214\226.java" @@ -34,41 +34,27 @@ public static void main(String[] args) { static class Solution { - final char[] options = new char[] { 'A', 'C', 'G', 'T' }; + final char[] AGCT = new char[] { 'A', 'C', 'G', 'T' }; public int minMutation(String startGene, String endGene, String[] bank) { - return bfs(startGene, endGene, bank); - } - - public int bfs(String startGene, String endGene, String[] bank) { - - Set bankSet = new HashSet<>(Arrays.asList(bank)); - // 最终结果不在有效基因集合中,直接返回 - if (!bankSet.contains(endGene)) { - return -1; - } + if (startGene.equals(endGene)) { return 0; } + int step = 0; + Set banks = new HashSet<>(Arrays.asList(bank)); Set visited = new HashSet<>(); LinkedList queue = new LinkedList<>(); queue.offer(startGene); - int step = 0; while (!queue.isEmpty()) { int size = queue.size(); for (int i = 0; i < size; i++) { - String cur = queue.poll(); - if (cur.equals(endGene)) { - return step; - } - - List neighbors = getNeighbors(cur, bankSet); - System.out.printf("%s 的邻居:%s\n", cur, neighbors); - for (String str : neighbors) { - if (visited.contains(str)) { - continue; + String curGene = queue.poll(); + if (curGene.equals(endGene)) { return step; } + for (String newGene : neighbours(curGene)) { + if (!visited.contains(newGene) && banks.contains(newGene)) { + queue.offer(newGene); + visited.add(newGene); } - visited.add(str); - queue.offer(str); } } step++; @@ -76,23 +62,19 @@ public int bfs(String startGene, String endGene, String[] bank) { return -1; } - public List getNeighbors(String s, Set bankSet) { - List list = new LinkedList<>(); - char[] ch = s.toCharArray(); + // 当前基因的每个位置都可以变异为 A/G/C/T,穷举所有可能的结构 + public List neighbours(String gene) { + List res = new LinkedList<>(); + char[] ch = gene.toCharArray(); for (int i = 0; i < ch.length; i++) { - char oldChar = ch[i]; - for (char newChar : options) { - if (oldChar != newChar) { - ch[i] = newChar; - String str = new String(ch); - if (bankSet.contains(str)) { - list.add(str); - } - } + char c = ch[i]; + for (char option : AGCT) { + ch[i] = option; + res.add(new String(ch)); } - ch[i] = oldChar; + ch[i] = c; } - return list; + return res; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\260\264\345\243\266\351\227\256\351\242\230.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\260\264\345\243\266\351\227\256\351\242\230.java" new file mode 100644 index 0000000..a70a284 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\260\264\345\243\266\351\227\256\351\242\230.java" @@ -0,0 +1,83 @@ +package io.github.dunwu.algorithm.bfs; + +import org.junit.jupiter.api.Assertions; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; + +/** + * 365. 水壶问题 + * + * @author Zhang Peng + * @date 2025-12-15 + */ +public class 水壶问题 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertTrue(s.canMeasureWater(3, 5, 4)); + Assertions.assertFalse(s.canMeasureWater(2, 6, 5)); + Assertions.assertTrue(s.canMeasureWater(1, 2, 3)); + } + + static class Solution { + + public boolean canMeasureWater(int x, int y, int t) { + // BFS 算法的队列 + LinkedList q = new LinkedList<>(); + // 用来记录已经遍历过的状态,把元组转化成数字方便存储哈希集合 + // 转化方式是 (x, y) -> (x * (y + 1) + y),和二维数组坐标转一维坐标是一样的原理 + // 因为水桶 2 的取值是 [0, y],所以需要额外加一,请类比二维数组坐标转一维坐标 + // 且考虑到题目输入的数据规模较大,相乘可能导致 int 溢出,所以使用 long 类型 + HashSet visited = new HashSet<>(); + // 添加初始状态,两个桶都没有水 + q.offer(new int[] { 0, 0 }); + visited.add((long) 0 * (0 + 1) + 0); + + while (!q.isEmpty()) { + int[] curState = q.poll(); + if (curState[0] == t || curState[1] == t + || curState[0] + curState[1] == t) { + // 如果任意一个桶的水量等于目标水量,就返回 true + return true; + } + // 计算出所有可能的下一个状态 + List nextStates = new LinkedList<>(); + // 把 1 桶灌满 + nextStates.add(new int[] { x, curState[1] }); + // 把 2 桶灌满 + nextStates.add(new int[] { curState[0], y }); + // 把 1 桶倒空 + nextStates.add(new int[] { 0, curState[1] }); + // 把 2 桶倒空 + nextStates.add(new int[] { curState[0], 0 }); + // 把 1 桶的水灌进 2 桶,直到 1 桶空了或者 2 桶满了 + nextStates.add(new int[] { + curState[0] - Math.min(curState[0], y - curState[1]), + curState[1] + Math.min(curState[0], y - curState[1]) + }); + // 把 2 桶的水灌进 1 桶,直到 2 桶空了或者 1 桶满了 + nextStates.add(new int[] { + curState[0] + Math.min(curState[1], x - curState[0]), + curState[1] - Math.min(curState[1], x - curState[0]) + }); + + // 把所有可能的下一个状态都放进队列里 + for (int[] nextState : nextStates) { + // 把二维坐标转化为数字,方便去重 + long hash = (long) nextState[0] * (y + 1) + nextState[1]; + if (visited.contains(hash)) { + // 如果这个状态之前遍历过,就跳过,避免队列永远不空陷入死循环 + continue; + } + q.offer(nextState); + visited.add(hash); + } + } + return false; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\205\220\347\203\202\347\232\204\346\251\230\345\255\220.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\205\220\347\203\202\347\232\204\346\251\230\345\255\220.java" index d81a625..0b5751b 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\205\220\347\203\202\347\232\204\346\251\230\345\255\220.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\205\220\347\203\202\347\232\204\346\251\230\345\255\220.java" @@ -3,7 +3,6 @@ import org.junit.jupiter.api.Assertions; import java.util.LinkedList; -import java.util.Queue; /** * 994. 腐烂的橘子 @@ -16,91 +15,77 @@ public class 腐烂的橘子 { public static void main(String[] args) { Solution s = new Solution(); - int[][] input1 = new int[][] { { 2, 1, 1 }, { 1, 1, 0 }, { 0, 1, 1 } }; + int[][] input1 = { { 2, 1, 1 }, { 1, 1, 0 }, { 0, 1, 1 } }; Assertions.assertEquals(4, s.orangesRotting(input1)); - int[][] input2 = new int[][] { { 2, 1, 1 }, { 0, 1, 1 }, { 1, 0, 1 } }; + int[][] input2 = { { 2, 1, 1 }, { 0, 1, 1 }, { 1, 0, 1 } }; Assertions.assertEquals(-1, s.orangesRotting(input2)); - int[][] input3 = new int[][] { { 0, 2 } }; + int[][] input3 = { { 0, 2 } }; Assertions.assertEquals(0, s.orangesRotting(input3)); - int[][] input4 = new int[][] { { 1 } }; + int[][] input4 = { { 1 } }; Assertions.assertEquals(-1, s.orangesRotting(input4)); - int[][] input5 = new int[][] { { 1, 2 } }; + int[][] input5 = { { 1, 2 } }; Assertions.assertEquals(1, s.orangesRotting(input5)); } static class Solution { // 四个方向偏移量(上、下、左、右) - private static final int[][] DIRS = { { 0, 1 }, { 0, -1 }, { -1, 0 }, { 1, 0 } }; + private static final int[][] directions = { { 0, 1 }, { 0, -1 }, { -1, 0 }, { 1, 0 } }; public int orangesRotting(int[][] grid) { int m = grid.length, n = grid[0].length; - // 1. 初始化:收集腐烂橘子,统计新鲜橘子数量 - int freshNum = 0; - Queue queue = new LinkedList<>(); - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - if (grid[i][j] == 2) { - // 腐烂橘子入队(BFS起点) - queue.offer(new int[] { i, j }); - } else if (grid[i][j] == 1) { - freshNum++; + int freshCount = 0; + boolean[][] visited = new boolean[m][n]; + LinkedList queue = new LinkedList<>(); + + // 把所有腐烂的橘子加入队列,作为 BFS 的起点 + for (int x = 0; x < m; x++) { + for (int y = 0; y < n; y++) { + if (grid[x][y] == 1) { + freshCount++; + } else if (grid[x][y] == 2) { + queue.offer(new int[] { x, y }); + visited[x][y] = true; } } } + if (freshCount == 0) { return 0; } + if (queue.isEmpty()) { return -1; } - // 边界情况:无新鲜橘子,直接返回 - if (freshNum == 0) { - return 0; - } - - // BFS 算法框架 - int step = 0; + int step = 1; while (!queue.isEmpty()) { - - // 当前分钟要处理的腐烂橘子数量 int size = queue.size(); - // 标记当前分钟是否有新鲜橘子腐烂 - boolean hasRotten = false; - - // 处理当前层级所有腐烂橘子 for (int i = 0; i < size; i++) { - int[] cur = queue.poll(); - - // 遍历四个相邻方向 - for (int[] dir : DIRS) { - int x = cur[0] + dir[0]; - int y = cur[1] + dir[1]; - - // 检查相邻单元格是否合法且为新鲜橘子 - if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1) { - freshNum--; - grid[x][y] = 2; - hasRotten = true; - queue.offer(new int[] { x, y }); + int[] point = queue.poll(); + int x = point[0], y = point[1]; + for (int[] d : directions) { + int nextX = x + d[0], nextY = y + d[1]; + // 超出边界,跳过 + if (nextX < 0 || nextX >= m || nextY < 0 || nextY >= n) { continue; } + // 已访问,跳过(避免死循环) + if (visited[nextX][nextY]) { continue; } + // 遇到空格,跳过 + if (grid[nextX][nextY] == 0) { continue; } + // 遇到新鲜橘子,被传播腐烂 + if (grid[nextX][nextY] == 1) { + grid[nextX][nextY] = 2; + freshCount--; + // 新鲜橘子数为 0,返回结果 + if (freshCount == 0) { return step; } } + visited[nextX][nextY] = true; + queue.offer(new int[] { nextX, nextY }); } } - - // 只有当前分钟有橘子腐烂时,才增加层级 - if (hasRotten) { - step++; - } - - // 提前终止:所有新鲜橘子已腐烂,无需继续遍历 - if (freshNum == 0) { - break; - } + step++; } - - // 3. 最终判断:是否所有新鲜橘子都腐烂 - return freshNum == 0 ? step : -1; + return -1; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" index b11e735..3afee28 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" @@ -1,6 +1,12 @@ package io.github.dunwu.algorithm.bfs; -import java.util.Arrays; +import io.github.dunwu.algorithm.util.ArrayUtil; +import org.junit.jupiter.api.Assertions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -13,20 +19,92 @@ public class 账户合并 { public static void main(String[] args) { + Solution solution = new Solution(); - List> input1 = new LinkedList<>(); - input1.add(Arrays.asList("John", "johnsmith@mail.com", "john00@mail.com")); - input1.add(Arrays.asList("John", "johnnybravo@mail.com")); - input1.add(Arrays.asList("John", "johnsmith@mail.com", "john_newyork@mail.com")); - input1.add(Arrays.asList("Mary", "mary@mail.com")); - List> output1 = solution.accountsMerge(input1); - System.out.println("output1: " + output1); + + String[][] input1 = { + { "John", "johnsmith@mail.com", "john00@mail.com" }, + { "John", "johnnybravo@mail.com" }, + { "John", "johnsmith@mail.com", "john_newyork@mail.com" }, + { "Mary", "mary@mail.com" } + }; + String[][] expect1 = { + { "John", "johnnybravo@mail.com" }, + { "John", "john00@mail.com", "john_newyork@mail.com", "johnsmith@mail.com" }, + { "Mary", "mary@mail.com" } + }; + List> output1 = solution.accountsMerge(ArrayUtil.toStringMatrixList(input1)); + Assertions.assertArrayEquals(expect1, ArrayUtil.toStringMatrixArray(output1)); + + String[][] input2 = { + { "Gabe", "Gabe0@m.co", "Gabe3@m.co", "Gabe1@m.co" }, + { "Kevin", "Kevin3@m.co", "Kevin5@m.co", "Kevin0@m.co" }, + { "Ethan", "Ethan5@m.co", "Ethan4@m.co", "Ethan0@m.co" }, + { "Hanzo", "Hanzo3@m.co", "Hanzo1@m.co", "Hanzo0@m.co" }, + { "Fern", "Fern5@m.co", "Fern1@m.co", "Fern0@m.co" } + }; + String[][] expect2 = { + { "Hanzo", "Hanzo0@m.co", "Hanzo1@m.co", "Hanzo3@m.co" }, + { "Fern", "Fern0@m.co", "Fern1@m.co", "Fern5@m.co" }, + { "Gabe", "Gabe0@m.co", "Gabe1@m.co", "Gabe3@m.co" }, + { "Kevin", "Kevin0@m.co", "Kevin3@m.co", "Kevin5@m.co" }, + { "Ethan", "Ethan0@m.co", "Ethan4@m.co", "Ethan5@m.co" } + }; + List> output2 = solution.accountsMerge(ArrayUtil.toStringMatrixList(input2)); + Assertions.assertArrayEquals(expect2, ArrayUtil.toStringMatrixArray(output2)); } static class Solution { public List> accountsMerge(List> accounts) { - return null; + // key: email, value: 出现该 email 的 account 的索引列表 + HashMap> emailToIdx = new HashMap<>(); + for (int i = 0; i < accounts.size(); i++) { + List account = accounts.get(i); + for (int j = 1; j < account.size(); j++) { + String email = account.get(j); + List indexes = emailToIdx.getOrDefault(email, new ArrayList<>()); + indexes.add(i); + emailToIdx.put(email, indexes); + } + } + + // 计算合并后的账户 + List> res = new ArrayList<>(); + HashSet visitedEmails = new HashSet<>(); + + for (String email : emailToIdx.keySet()) { + if (visitedEmails.contains(email)) { + continue; + } + // 合并账户,用 BFS 算法穷举所有和 email 相关联的邮箱 + LinkedList mergedEmail = new LinkedList<>(); + LinkedList queue = new LinkedList<>(); + queue.offer(email); + visitedEmails.add(email); + // BFS 算法框架 + while (!queue.isEmpty()) { + String curEmail = queue.poll(); + mergedEmail.addLast(curEmail); + List indexes = emailToIdx.get(curEmail); + for (int index : indexes) { + List account = accounts.get(index); + for (int j = 1; j < account.size(); j++) { + String nextEmail = account.get(j); + if (!visitedEmails.contains(nextEmail)) { + queue.offer(nextEmail); + visitedEmails.add(nextEmail); + } + } + } + } + String userName = accounts.get(emailToIdx.get(email).get(0)).get(0); + // mergedEmail 是 userName 的所有邮箱 + Collections.sort(mergedEmail); + mergedEmail.addFirst(userName); + res.add(mergedEmail); + } + return res; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" index 99ead5c..4782ed7 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" @@ -16,26 +16,26 @@ public static void main(String[] args) { Solution s = new Solution(); - char[][] maze1 = new char[][] { { '+', '+', '.', '+' }, { '.', '.', '.', '+' }, { '+', '+', '+', '.' } }; - int[] entrance1 = new int[] { 1, 2 }; + char[][] maze1 = { { '+', '+', '.', '+' }, { '.', '.', '.', '+' }, { '+', '+', '+', '.' } }; + int[] entrance1 = { 1, 2 }; Assertions.assertEquals(1, s.nearestExit(maze1, entrance1)); - char[][] maze2 = new char[][] { { '+', '+', '+' }, { '.', '.', '.' }, { '+', '+', '+' } }; - int[] entrance2 = new int[] { 1, 0 }; + char[][] maze2 = { { '+', '+', '+' }, { '.', '.', '.' }, { '+', '+', '+' } }; + int[] entrance2 = { 1, 0 }; Assertions.assertEquals(2, s.nearestExit(maze2, entrance2)); - char[][] maze3 = new char[][] { { '.', '+' } }; - int[] entrance3 = new int[] { 0, 0 }; + char[][] maze3 = { { '.', '+' } }; + int[] entrance3 = { 0, 0 }; Assertions.assertEquals(-1, s.nearestExit(maze3, entrance3)); - char[][] maze4 = new char[][] { + char[][] maze4 = { { '+', '.', '+', '+', '+', '+', '+' }, { '+', '.', '+', '.', '.', '.', '+' }, { '+', '.', '+', '.', '+', '.', '+' }, { '+', '.', '.', '.', '+', '.', '+' }, { '+', '+', '+', '+', '+', '+', '.' } }; - int[] entrance4 = new int[] { 0, 1 }; + int[] entrance4 = { 0, 1 }; Assertions.assertEquals(-1, s.nearestExit(maze4, entrance4)); } @@ -43,44 +43,31 @@ static class Solution { public int nearestExit(char[][] maze, int[] entrance) { - int M = maze.length, N = maze[0].length; - int[][] dirs = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } }; + int m = maze.length, n = maze[0].length; + final int[][] directions = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } }; - int step = 0; - boolean[][] visited = new boolean[M][N]; - visited[entrance[0]][entrance[1]] = true; + // BFS 算法的队列和 visited 数组 LinkedList queue = new LinkedList<>(); + boolean[][] visited = new boolean[m][n]; queue.offer(entrance); + visited[entrance[0]][entrance[1]] = true; + // 启动 BFS 算法从 entrance 开始像四周扩散 + int step = 0; while (!queue.isEmpty()) { int size = queue.size(); step++; // 扩散当前队列中的所有节点 for (int i = 0; i < size; i++) { - int[] cur = queue.poll(); + int[] point = queue.poll(); // 每个节点都会尝试向上下左右四个方向扩展一步 - for (int[] dir : dirs) { - - int row = cur[0] + dir[0]; - int column = cur[1] + dir[1]; - - // 无效路径,返回 - if (row < 0 || row >= M || column < 0 || column >= N) { - continue; - } - if (visited[row][column]) { - continue; - } - if (maze[row][column] == '+') { - continue; - } - - // 找到出口,退出 - if (row == 0 || row == M - 1 || column == 0 || column == N - 1) { - return step; - } - - visited[row][column] = true; - queue.offer(new int[] { row, column }); + for (int[] d : directions) { + int x = point[0] + d[0], y = point[1] + d[1]; + if (x < 0 || x >= m || y < 0 || y >= n) { continue; } + if (visited[x][y] || maze[x][y] == '+') { continue; } + // 走到边界(出口) + if (x == 0 || x == m - 1 || y == 0 || y == n - 1) { return step; } + visited[x][y] = true; + queue.offer(new int[] { x, y }); } } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\351\222\245\345\214\231\345\222\214\346\210\277\351\227\264.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\351\222\245\345\214\231\345\222\214\346\210\277\351\227\264.java" index 5ac816c..3464b06 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\351\222\245\345\214\231\345\222\214\346\210\277\351\227\264.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\351\222\245\345\214\231\345\222\214\346\210\277\351\227\264.java" @@ -30,27 +30,27 @@ public static void main(String[] args) { static class Solution { public boolean canVisitAllRooms(List> rooms) { + // base case + if (rooms == null || rooms.size() == 0) { return true; } + // 记录访问过的房间 Set visited = new HashSet<>(); LinkedList queue = new LinkedList<>(); + // 在队列中加入起点,启动 BFS queue.offer(0); - while (!queue.isEmpty()) { - Integer cur = queue.poll(); - if (visited.contains(cur)) { - continue; - } - visited.add(cur); - if (visited.size() == rooms.size()) { - return true; - } - - for (Integer room : rooms.get(cur)) { - queue.offer(room); + int size = queue.size(); + for (int i = 0; i < size; i++) { + Integer cur = queue.poll(); + if (!visited.contains(cur)) { + visited.add(cur); + for (int room : rooms.get(cur)) { + queue.offer(room); + } + } } } - - return false; + return visited.size() == rooms.size(); } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/package-info.java new file mode 100644 index 0000000..6b44e2d --- /dev/null +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/package-info.java @@ -0,0 +1,7 @@ +/** + * DFS 解岛屿数类型问题 + * + * @author Zhang Peng + * @date 2025-12-15 + */ +package io.github.dunwu.algorithm.dfs.island; \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\346\225\260\351\207\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\346\225\260\351\207\217.java" index 4733c62..c6bafac 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\346\225\260\351\207\217.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\346\225\260\351\207\217.java" @@ -4,8 +4,6 @@ /** * 200. 岛屿数量 - *

- * 元素不可重复,不可复选 * * @author Zhang Peng * @date 2025-11-04 @@ -15,7 +13,7 @@ public class 岛屿数量 { public static void main(String[] args) { Solution s = new Solution(); - char[][] input = new char[][] { + char[][] input = { { '1', '1', '1', '1', '0' }, { '1', '1', '0', '1', '0' }, { '1', '1', '0', '0', '0' }, @@ -23,7 +21,7 @@ public static void main(String[] args) { }; Assertions.assertEquals(1, s.numIslands(input)); - char[][] input2 = new char[][] { + char[][] input2 = { { '1', '1', '0', '0', '0' }, { '1', '1', '0', '0', '0' }, { '0', '0', '1', '0', '0' }, @@ -34,43 +32,36 @@ public static void main(String[] args) { static class Solution { - public int numIslands(char[][] grid) { - - if (grid == null || grid.length == 0 || grid[0].length == 0) { return 0; } + private final int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { return 0; } int res = 0; - int M = grid.length, N = grid[0].length; - - // 遍历 grid - for (int row = 0; row < M; row++) { - for (int column = 0; column < N; column++) { - if (grid[row][column] == '1') { + int m = grid.length, n = grid[0].length; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == '1') { // 每发现一个岛屿,岛屿数量加一 res++; - // 然后使用 dfs 将岛屿淹了 - dfs(grid, row, column); + // 然后使用 DFS 将岛屿淹了 + dfs(grid, i, j); } } } return res; } - public void dfs(char[][] grid, int row, int column) { + // 淹没与 (x, y) 相邻的陆地,并返回淹没的陆地面积 + public void dfs(char[][] grid, int x, int y) { + int m = grid.length, n = grid[0].length; + if (x < 0 || x >= m || y < 0 || y >= n) { return; } + if (grid[x][y] == '0') { return; } - // 坐标超过边界,无效 - int M = grid.length, N = grid[0].length; - if (row < 0 || row >= M || column < 0 || column >= N) { return; } - - // 已经是海水了 - if (grid[row][column] == '0') { return; } - // 将 (row, column) 变成海水 - grid[row][column] = '0'; - - // 淹没上下左右的陆地 - dfs(grid, row - 1, column); - dfs(grid, row + 1, column); - dfs(grid, row, column - 1); - dfs(grid, row, column + 1); + grid[x][y] = '0'; + for (int[] d : directions) { + int i = x + d[0], j = y + d[1]; + dfs(grid, i, j); + } } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.java" index 6fd8187..df3719e 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.java" @@ -13,7 +13,7 @@ public class 岛屿的最大面积 { public static void main(String[] args) { Solution s = new Solution(); - int[][] input = new int[][] { + int[][] input = { { 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0 }, { 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, @@ -25,43 +25,45 @@ public static void main(String[] args) { }; Assertions.assertEquals(6, s.maxAreaOfIsland(input)); - int[][] input2 = new int[][] { - { 0, 0, 0, 0, 0, 0, 0, 0 } - }; + int[][] input2 = { { 0, 0, 0, 0, 0, 0, 0, 0 } }; Assertions.assertEquals(0, s.maxAreaOfIsland(input2)); } static class Solution { + private final int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; + public int maxAreaOfIsland(int[][] grid) { - if (grid == null || grid.length == 0 || grid[0].length == 0) { return 0; } - int max = 0; - int M = grid.length, N = grid[0].length; - for (int row = 0; row < M; row++) { - for (int column = 0; column < N; column++) { - max = Math.max(max, dfs(grid, row, column)); + // base case + if (grid == null || grid.length == 0) return 0; + + int res = 0; + int m = grid.length, n = grid[0].length; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == 1) { + int size = dfs(grid, i, j); + res = Math.max(res, size); + } } } - return max; + return res; } - public int dfs(int[][] grid, int row, int column) { + // 淹没与 (x, y) 相邻的陆地,并返回淹没的陆地面积 + public int dfs(int[][] grid, int x, int y) { + int m = grid.length, n = grid[0].length; + if (x < 0 || x >= m || y < 0 || y >= n) { return 0; } + if (grid[x][y] == 0) { return 0; } - // 坐标超过边界,无效 - int M = grid.length, N = grid[0].length; - if (row < 0 || row >= M || column < 0 || column >= N) { return 0; } - - // 已经是海水了 - if (grid[row][column] == 0) { return 0; } - // 将 (row, column) 变成海水 - grid[row][column] = 0; - - // 淹没上下左右的陆地 - return 1 + dfs(grid, row - 1, column) - + dfs(grid, row + 1, column) - + dfs(grid, row, column - 1) - + dfs(grid, row, column + 1); + int cnt = 1; + grid[x][y] = 0; + for (int[] d : directions) { + int i = x + d[0], j = y + d[1]; + cnt += dfs(grid, i, j); + } + return cnt; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\255\220\345\262\233\345\261\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\255\220\345\262\233\345\261\277.java" index 2fa0742..535ae08 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\255\220\345\262\233\345\261\277.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\255\220\345\262\233\345\261\277.java" @@ -13,14 +13,14 @@ public class 统计子岛屿 { public static void main(String[] args) { Solution s = new Solution(); - int[][] gridA1 = new int[][] { + int[][] gridA1 = { { 1, 1, 1, 0, 0 }, { 0, 1, 1, 1, 1 }, { 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0 }, { 1, 1, 0, 1, 1 } }; - int[][] gridB1 = new int[][] { + int[][] gridB1 = { { 1, 1, 1, 0, 0 }, { 0, 0, 1, 1, 1 }, { 0, 1, 0, 0, 0 }, @@ -29,14 +29,14 @@ public static void main(String[] args) { }; Assertions.assertEquals(3, s.countSubIslands(gridA1, gridB1)); - int[][] gridA2 = new int[][] { + int[][] gridA2 = { { 1, 0, 1, 0, 1 }, { 1, 1, 1, 1, 1 }, { 0, 0, 0, 0, 0 }, { 1, 1, 1, 1, 1 }, { 1, 0, 1, 0, 1 } }; - int[][] gridB2 = new int[][] { + int[][] gridB2 = { { 0, 0, 0, 0, 0 }, { 1, 1, 1, 1, 1 }, { 0, 1, 0, 1, 0 }, @@ -48,44 +48,44 @@ public static void main(String[] args) { static class Solution { - public int countSubIslands(int[][] gridA, int[][] gridB) { - int M = gridB.length, N = gridB[0].length; - for (int row = 0; row < M; row++) { - for (int column = 0; column < N; column++) { - if (gridA[row][column] == 0 && gridB[row][column] == 1) { - dfs(gridB, row, column); + private final int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; + + public int countSubIslands(int[][] grid1, int[][] grid2) { + int m = grid1.length, n = grid1[0].length; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid1[i][j] == 0 && grid2[i][j] == 1) { + // 这个岛屿肯定不是子岛,淹掉 + dfs(grid2, i, j); } } } int res = 0; - for (int row = 0; row < M; row++) { - for (int column = 0; column < N; column++) { - if (gridB[row][column] == 1) { + // 现在 grid2 中剩下的岛屿都是子岛,计算岛屿数量 + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid2[i][j] == 1) { res++; - dfs(gridB, row, column); + dfs(grid2, i, j); } } } return res; } - public void dfs(int[][] grid, int row, int column) { - - // 坐标超过边界,无效 - int M = grid.length, N = grid[0].length; - if (row < 0 || row >= M || column < 0 || column >= N) { return; } + // 淹没与 (x, y) 相邻的陆地,并返回淹没的陆地面积 + public void dfs(int[][] grid, int x, int y) { + // base case + int m = grid.length, n = grid[0].length; + if (x < 0 || x >= m || y < 0 || y >= n) { return; } + if (grid[x][y] == 0) { return; } - // 已经是海水了 - if (grid[row][column] == 0) { return; } - // 将 (row, column) 变成海水 - grid[row][column] = 0; - - // 淹没上下左右的陆地 - dfs(grid, row - 1, column); - dfs(grid, row + 1, column); - dfs(grid, row, column - 1); - dfs(grid, row, column + 1); + grid[x][y] = 0; + for (int[] d : directions) { + int i = x + d[0], j = y + d[1]; + dfs(grid, i, j); + } } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\260\201\351\227\255\345\262\233\345\261\277\347\232\204\346\225\260\347\233\256.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\260\201\351\227\255\345\262\233\345\261\277\347\232\204\346\225\260\347\233\256.java" index 82283c4..20975ca 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\260\201\351\227\255\345\262\233\345\261\277\347\232\204\346\225\260\347\233\256.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\260\201\351\227\255\345\262\233\345\261\277\347\232\204\346\225\260\347\233\256.java" @@ -4,8 +4,6 @@ /** * 1254. 统计封闭岛屿的数目 - *

- * 元素不可重复,不可复选 * * @author Zhang Peng * @date 2025-11-04 @@ -15,7 +13,7 @@ public class 统计封闭岛屿的数目 { public static void main(String[] args) { Solution s = new Solution(); - int[][] input = new int[][] { + int[][] input = { { 1, 1, 1, 1, 1, 1, 1, 0 }, { 1, 0, 0, 0, 0, 1, 1, 0 }, { 1, 0, 1, 0, 1, 1, 1, 0 }, @@ -24,7 +22,7 @@ public static void main(String[] args) { }; Assertions.assertEquals(2, s.closedIsland(input)); - int[][] input2 = new int[][] { + int[][] input2 = { { 1, 1, 1, 1, 1, 1, 1 }, { 1, 0, 0, 0, 0, 0, 1 }, { 1, 0, 1, 1, 1, 0, 1 }, @@ -38,53 +36,49 @@ public static void main(String[] args) { static class Solution { - public int closedIsland(int[][] grid) { + private final int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; - if (grid == null || grid.length == 0 || grid[0].length == 0) { return 0; } + public int closedIsland(int[][] grid) { - int M = grid.length, N = grid[0].length; + // base case + if (grid == null || grid.length == 0) { return 0; } - for (int column = 0; column < N; column++) { - dfs(grid, 0, column); - dfs(grid, M - 1, column); + // 将靠边的岛屿淹没 + int m = grid.length, n = grid[0].length; + for (int j = 0; j < n; j++) { + dfs(grid, 0, j); + dfs(grid, m - 1, j); } - - for (int row = 0; row < M; row++) { - dfs(grid, row, 0); - dfs(grid, row, N - 1); + for (int i = 0; i < m; i++) { + dfs(grid, i, 0); + dfs(grid, i, n - 1); } - // 遍历 grid int res = 0; - for (int row = 0; row < M; row++) { - for (int column = 0; column < N; column++) { - if (grid[row][column] == 0) { - // 每发现一个岛屿,岛屿数量加一 + // 遍历 grid,剩下的岛屿都是封闭岛屿 + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == 0) { res++; - // 然后使用 dfs 将岛屿淹了 - dfs(grid, row, column); + dfs(grid, i, j); } } } return res; } - public void dfs(int[][] grid, int row, int column) { - - // 坐标超过边界,无效 - int M = grid.length, N = grid[0].length; - if (row < 0 || row >= M || column < 0 || column >= N) { return; } - - // 已经是海水了 - if (grid[row][column] == 1) { return; } - // 将 (row, column) 变成海水 - grid[row][column] = 1; - - // 淹没上下左右的陆地 - dfs(grid, row - 1, column); - dfs(grid, row + 1, column); - dfs(grid, row, column - 1); - dfs(grid, row, column + 1); + // 淹没与 (x, y) 相邻的陆地,并返回淹没的陆地面积 + public void dfs(int[][] grid, int x, int y) { + // base case + int m = grid.length, n = grid[0].length; + if (x < 0 || x >= m || y < 0 || y >= n) { return; } + if (grid[x][y] == 1) { return; } + + grid[x][y] = 1; + for (int[] d : directions) { + int i = x + d[0], j = y + d[1]; + dfs(grid, i, j); + } } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\351\243\236\345\234\260\347\232\204\346\225\260\351\207\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\351\243\236\345\234\260\347\232\204\346\225\260\351\207\217.java" index c24224d..7bdaa0c 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\351\243\236\345\234\260\347\232\204\346\225\260\351\207\217.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\351\243\236\345\234\260\347\232\204\346\225\260\351\207\217.java" @@ -4,8 +4,6 @@ /** * 1020. 飞地的数量/a> - *

- * 元素不可重复,不可复选 * * @author Zhang Peng * @date 2025-11-04 @@ -15,7 +13,7 @@ public class 飞地的数量 { public static void main(String[] args) { Solution s = new Solution(); - int[][] input = new int[][] { + int[][] input = { { 0, 0, 0, 0 }, { 1, 0, 1, 0 }, { 0, 1, 1, 0 }, @@ -23,7 +21,7 @@ public static void main(String[] args) { }; Assertions.assertEquals(3, s.numEnclaves(input)); - int[][] input2 = new int[][] { + int[][] input2 = { { 0, 1, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, @@ -34,45 +32,47 @@ public static void main(String[] args) { static class Solution { + private final int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; + public int numEnclaves(int[][] grid) { - int M = grid.length, N = grid[0].length; - for (int i = 0; i < M; i++) { - dfs(grid, i, 0); - dfs(grid, i, N - 1); + // base case + if (grid == null || grid.length == 0) { return 0; } + + int m = grid.length, n = grid[0].length; + for (int j = 0; j < n; j++) { + dfs(grid, 0, j); + dfs(grid, m - 1, j); } - for (int i = 0; i < N; i++) { - dfs(grid, 0, i); - dfs(grid, M - 1, i); + for (int i = 0; i < m; i++) { + dfs(grid, i, 0); + dfs(grid, i, n - 1); } int res = 0; - for (int i = 0; i < M; i++) { - for (int j = 0; j < N; j++) { + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { if (grid[i][j] == 1) { - res++; + res += dfs(grid, i, j); } } } return res; } - public void dfs(int[][] grid, int row, int column) { + // 淹没与 (x, y) 相邻的陆地,并返回淹没的陆地面积 + public int dfs(int[][] grid, int x, int y) { + int m = grid.length, n = grid[0].length; + if (x < 0 || x >= m || y < 0 || y >= n) { return 0; } + if (grid[x][y] == 0) { return 0; } - // 坐标超过边界,无效 - int M = grid.length, N = grid[0].length; - if (row < 0 || row >= M || column < 0 || column >= N) { return; } - - // 已经是海水了 - if (grid[row][column] == 0) { return; } - // 将 (row, column) 变成海水 - grid[row][column] = 0; - - // 淹没上下左右的陆地 - dfs(grid, row - 1, column); - dfs(grid, row + 1, column); - dfs(grid, row, column - 1); - dfs(grid, row, column + 1); + int cnt = 1; + grid[x][y] = 0; + for (int[] d : directions) { + int i = x + d[0], j = y + d[1]; + cnt += dfs(grid, i, j); + } + return cnt; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2602.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2602.java" index 642e338..dcb4260 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2602.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2602.java" @@ -2,10 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.HashSet; -import java.util.PriorityQueue; -import java.util.Set; - /** * 264. 丑数II * @@ -18,61 +14,29 @@ public static void main(String[] args) { Solution s = new Solution(); Assertions.assertEquals(12, s.nthUglyNumber(10)); Assertions.assertEquals(1, s.nthUglyNumber(1)); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(12, s2.nthUglyNumber(10)); - Assertions.assertEquals(1, s2.nthUglyNumber(1)); + Assertions.assertEquals(15, s.nthUglyNumber(11)); } - // 动态规划方案 static class Solution { public int nthUglyNumber(int n) { int[] dp = new int[n + 1]; dp[1] = 1; int p2 = 1, p3 = 1, p5 = 1; - for (int i = 2; i <= n; i++) { - int num2 = dp[p2] * 2; - int num3 = dp[p3] * 3; - int num5 = dp[p5] * 5; - dp[i] = min(num2, num3, num5); - if (dp[i] == num2) { p2++; } - if (dp[i] == num3) { p3++; } - if (dp[i] == num5) { p5++; } + for (int index = 2; index <= n; index++) { + int n2 = dp[p2] * 2, n3 = dp[p3] * 3, n5 = dp[p5] * 5; + dp[index] = min(n2, n3, n5); + if (dp[index] == n2) { p2++; } + if (dp[index] == n3) { p3++; } + if (dp[index] == n5) { p5++; } } return dp[n]; } - int min(int a, int b, int c) { + public int min(int a, int b, int c) { return Math.min(a, Math.min(b, c)); } } - // 优先队列(堆)方案 - static class Solution2 { - - int[] nums = new int[] { 2, 3, 5 }; - - public int nthUglyNumber(int n) { - Set set = new HashSet<>(); - PriorityQueue q = new PriorityQueue<>(); - set.add(1L); - q.add(1L); - for (int i = 1; i <= n; i++) { - long x = q.poll(); - if (i == n) return (int) x; - for (int num : nums) { - long t = num * x; - if (!set.contains(t)) { - set.add(t); - q.add(t); - } - } - } - return -1; - } - - } - } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2603.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2603.java" index dbf9eb0..1ca3fb6 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2603.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2603.java" @@ -21,15 +21,14 @@ static class Solution { public int nthUglyNumber(int n, int a, int b, int c) { int[] dp = new int[n + 1]; - int pa = 0, pb = 0, pc = 0; + int pa = 1, pb = 1, pc = 1; + dp[0] = 1; for (int i = 1; i <= n; i++) { - int numA = dp[pa] + a; - int numB = dp[pb] + b; - int numC = dp[pc] + c; - dp[i] = min(numA, numB, numC); - if (dp[i] == numA) { pa = i; } - if (dp[i] == numB) { pb = i; } - if (dp[i] == numC) { pc = i; } + int na = pa * a, nb = pb * b, nc = pc * c; + dp[i] = min(na, nb, nc); + if (dp[i] == na) { pa++; } + if (dp[i] == nb) { pb++; } + if (dp[i] == nc) { pc++; } } return dp[n]; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\346\234\200\344\275\216\347\245\250\344\273\267.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\346\234\200\344\275\216\347\245\250\344\273\267.java" new file mode 100644 index 0000000..80c922b --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\346\234\200\344\275\216\347\245\250\344\273\267.java" @@ -0,0 +1,58 @@ +package io.github.dunwu.algorithm.dp.array; + +import org.junit.jupiter.api.Assertions; + +/** + * 983. 最低票价 + * + * @author Zhang Peng + * @since 2025-11-17 + */ +public class 最低票价 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(11, s.mincostTickets(new int[] { 1, 4, 6, 7, 8, 20 }, new int[] { 2, 7, 15 })); + Assertions.assertEquals(17, + s.mincostTickets(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 30, 31 }, new int[] { 2, 7, 15 })); + } + + // 动态规划 + static class Solution { + + public int mincostTickets(int[] days, int[] costs) { + int n = days.length; + int lastDay = days[n - 1]; + boolean[] isTravel = new boolean[lastDay + 1]; + for (int d : days) { isTravel[d] = true; } + + // dp[i] 表示 1 到 i 天的最小花费 + int[] dp = new int[lastDay + 1]; + dp[0] = 0; + for (int i = 1; i <= lastDay; i++) { + if (!isTravel[i]) { + // 如果第 i 天不在 days 中,则第 i 天和第 i - 1 天花费相同 + dp[i] = dp[i - 1]; + } else { + // 如果第 i 天在 days 中 + // 则求三种不同方案最小值: + dp[i] = min( + // 在第 i 天购买为期 1 天的通行证的最小花费 + costs[0] + dp[i - 1], + // 在第 i - 7 天购买为期 7 天的通行证的最小花费(如果 i - 7 < 0,视为 0,f[0] 花费为 0) + costs[1] + dp[Math.max(0, i - 7)], + // 在第 i - 30 天购买为期 30 天的通行证的最小花费(如果 i - 30 < 0,视为 0,f[0] 花费为 0) + costs[2] + dp[Math.max(0, i - 30)] + ); + } + } + return dp[lastDay]; + } + + public int min(int a, int b, int c) { + return Math.min(a, Math.min(b, c)); + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\347\273\237\350\256\241\346\236\204\351\200\240\345\245\275\345\255\227\347\254\246\344\270\262\347\232\204\346\226\271\346\241\210\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\347\273\237\350\256\241\346\236\204\351\200\240\345\245\275\345\255\227\347\254\246\344\270\262\347\232\204\346\226\271\346\241\210\346\225\260.java" index d81d25f..107feec 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\347\273\237\350\256\241\346\236\204\351\200\240\345\245\275\345\255\227\347\254\246\344\270\262\347\232\204\346\226\271\346\241\210\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\347\273\237\350\256\241\346\236\204\351\200\240\345\245\275\345\255\227\347\254\246\344\270\262\347\232\204\346\226\271\346\241\210\346\225\260.java" @@ -2,8 +2,6 @@ import org.junit.jupiter.api.Assertions; -import java.util.Arrays; - /** * 2466. 统计构造好字符串的方案数 * @@ -20,27 +18,21 @@ public static void main(String[] args) { static class Solution { - int[] memo = null; - private static final int MOD = 1_000_000_007; - public int countGoodStrings(int low, int high, int zero, int one) { - memo = new int[high + 1]; - Arrays.fill(memo, -1); + final int MOD = 1_000_000_007; int res = 0; - for (int i = low; i <= high; i++) { - res = (res + dp(i, zero, one)) % MOD; + // dp[i] 表示构造长为 i 的字符串的方案数 + int[] dp = new int[high + 1]; + // 构造空串的方案数为 1 + dp[0] = 1; + for (int i = 1; i <= high; i++) { + if (i >= zero) dp[i] = dp[i - zero]; + if (i >= one) dp[i] = (dp[i] + dp[i - one]) % MOD; + if (i >= low) res = (res + dp[i]) % MOD; } return res; } - public int dp(int i, int zero, int one) { - if (i < 0) { return 0; } - if (i == 0) { return 1; } - if (memo[i] != -1) { return memo[i]; } - memo[i] = (dp(i - zero, zero, one) + dp(i - one, zero, one)) % MOD; - return memo[i]; - } - } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\247\243\347\240\201\346\226\271\346\263\225.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\247\243\347\240\201\346\226\271\346\263\225.java" new file mode 100644 index 0000000..d813925 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\247\243\347\240\201\346\226\271\346\263\225.java" @@ -0,0 +1,103 @@ +package io.github.dunwu.algorithm.dp.array; + +import org.junit.jupiter.api.Assertions; + +import java.util.LinkedList; + +/** + * 91. 解码方法 + * + * @author Zhang Peng + * @since 2025-11-17 + */ +public class 解码方法 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(2, s.numDecodings("12")); + Assertions.assertEquals(3, s.numDecodings("226")); + Assertions.assertEquals(0, s.numDecodings("06")); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals(2, s2.numDecodings("12")); + Assertions.assertEquals(3, s2.numDecodings("226")); + Assertions.assertEquals(0, s2.numDecodings("06")); + } + + // 回溯解法 + static class Solution { + + private StringBuilder sb; + private LinkedList res; + + public int numDecodings(String s) { + sb = new StringBuilder(); + res = new LinkedList<>(); + backtrack(s, 0); + return res.size(); + } + + public void backtrack(String s, int start) { + + // base case,走到叶子节点 + // 即整个 s 被成功分割为合法的四部分,记下答案 + if (start == s.length()) { + res.add(sb.toString()); + return; + } + + for (int i = start; i < s.length(); i++) { + + // s[start..i] 不是合法的 ip 数字,不能分割 + char letter = getLetter(s, start, i); + if (letter == '#') { continue; } + + // 【选择】 + // s[start..i] 是一个合法的 ip 数字,可以进行分割 + // 做选择,把 s[start..i] 放入路径列表中 + sb.append(letter); + + // 【回溯】 + backtrack(s, i + 1); + + // 【取消选择】 + sb.deleteCharAt(sb.length() - 1); + } + } + + public char getLetter(String s, int begin, int end) { + int len = end - begin + 1; + if (len <= 0 || len > 2) { return '#'; } + String numStr = s.substring(begin, begin + len); + if (numStr.startsWith("0")) { return '#'; } + int num = Integer.parseInt(numStr); + if (num < 1 || num > 26) { return '#'; } + return (char) ('A' + (num - 1)); + } + + } + + // 动态规划 + static class Solution2 { + + public int numDecodings(String s) { + int n = s.length(); + s = " " + s; + char[] ch = s.toCharArray(); + int[] dp = new int[n + 1]; + dp[0] = 1; + for (int i = 1; i <= n; i++) { + // a : 代表「当前位置」单独形成 item + // b : 代表「当前位置」与「前一位置」共同形成 item + int a = ch[i] - '0', b = (ch[i - 1] - '0') * 10 + (ch[i] - '0'); + // 如果 a 属于有效值,那么 dp[i] 可以由 dp[i - 1] 转移过来 + if (1 <= a && a <= 9) dp[i] = dp[i - 1]; + // 如果 b 属于有效值,那么 dp[i] 可以由 dp[i - 2] 或者 dp[i - 1] & dp[i - 2] 转移过来 + if (10 <= b && b <= 26) dp[i] += dp[i - 2]; + } + return dp[n]; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\351\233\266\351\222\261\345\205\221\346\215\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\351\233\266\351\222\261\345\205\221\346\215\242.java" index b568e1e..feeb72a 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\351\233\266\351\222\261\345\205\221\346\215\242.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\351\233\266\351\222\261\345\205\221\346\215\242.java" @@ -17,23 +17,69 @@ public static void main(String[] args) { Assertions.assertEquals(3, s.coinChange(new int[] { 1, 2, 5 }, 11)); Assertions.assertEquals(-1, s.coinChange(new int[] { 2 }, 3)); Assertions.assertEquals(0, s.coinChange(new int[] { 1 }, 0)); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals(3, s2.coinChange(new int[] { 1, 2, 5 }, 11)); + Assertions.assertEquals(-1, s2.coinChange(new int[] { 2 }, 3)); + Assertions.assertEquals(0, s2.coinChange(new int[] { 1 }, 0)); } static class Solution { + int[] memo; + + public int coinChange(int[] coins, int amount) { + memo = new int[amount + 1]; + // 备忘录初始化为一个不会被取到的特殊值,代表还未被计算 + Arrays.fill(memo, -666); + + return dp(coins, amount); + } + + int dp(int[] coins, int amount) { + if (amount == 0) return 0; + if (amount < 0) return -1; + // 查备忘录,防止重复计算 + if (memo[amount] != -666) { return memo[amount]; } + + int res = Integer.MAX_VALUE; + for (int coin : coins) { + // 计算子问题的结果 + int subProblem = dp(coins, amount - coin); + + // 子问题无解则跳过 + if (subProblem == -1) continue; + // 在子问题中选择最优解,然后加一 + res = Math.min(res, subProblem + 1); + } + // 把计算结果存入备忘录 + memo[amount] = (res == Integer.MAX_VALUE) ? -1 : res; + return memo[amount]; + } + + } + + static class Solution2 { + public int coinChange(int[] coins, int amount) { - if (coins == null || coins.length == 0) { return 0; } int[] dp = new int[amount + 1]; + // 数组大小为 amount + 1,初始值也为 amount + 1 Arrays.fill(dp, amount + 1); + + // base case dp[0] = 0; - for (int i = 1; i <= amount; i++) { + // 外层 for 循环在遍历所有状态的所有取值 + for (int i = 0; i < dp.length; i++) { + // 内层 for 循环在求所有选择的最小值 for (int coin : coins) { - if (i - coin >= 0) { - dp[i] = Math.min(dp[i], dp[i - coin] + 1); + // 子问题无解,跳过 + if (i - coin < 0) { + continue; } + dp[i] = Math.min(dp[i], 1 + dp[i - coin]); } } - return (dp[amount] > amount) ? -1 : dp[amount]; + return (dp[amount] == amount + 1) ? -1 : dp[amount]; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\345\215\225\350\257\215\346\213\206\345\210\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\345\215\225\350\257\215\346\213\206\345\210\206.java" index 582260b..97e11ea 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\345\215\225\350\257\215\346\213\206\345\210\206.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\345\215\225\350\257\215\346\213\206\345\210\206.java" @@ -4,8 +4,8 @@ import java.util.Arrays; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; -import java.util.Set; /** * 139. 单词拆分 @@ -20,23 +20,91 @@ public static void main(String[] args) { Assertions.assertTrue(s.wordBreak("leetcode", Arrays.asList("leet", "code"))); Assertions.assertTrue(s.wordBreak("applepenapple", Arrays.asList("apple", "pen"))); Assertions.assertFalse(s.wordBreak("catsandog", Arrays.asList("cats", "dog", "sand", "and", "cat"))); + + Solution2 s2 = new Solution2(); + Assertions.assertTrue(s2.wordBreak("leetcode", Arrays.asList("leet", "code"))); + Assertions.assertTrue(s2.wordBreak("applepenapple", Arrays.asList("apple", "pen"))); + Assertions.assertFalse(s2.wordBreak("catsandog", Arrays.asList("cats", "dog", "sand", "and", "cat"))); } + // 回溯解决方案 static class Solution { + // 记录是否找到一个合法的答案 + boolean found = false; + // 记录回溯算法的路径 + private LinkedList path; + + public boolean wordBreak(String s, List wordDict) { + found = false; + path = new LinkedList<>(); + backtrack(wordDict, s, 0); + return found; + } + + public void backtrack(List wordDict, String target, int start) { + + // 找到一个合法答案 + if (start == target.length()) { found = true; } + // 如果已经找到答案,就不要再递归搜索了 + if (found) { return; } + + // 回溯算法框架 + for (String word : wordDict) { + + int len = word.length(); + + // 无效情况,剪枝 + if (start + len > target.length()) { return; } + if (!target.substring(start, start + len).equals(word)) { continue; } + + // 【选择】 + path.add(word); + // 【回溯】 + backtrack(wordDict, target, start + len); + // 【取消选择】 + path.remove(path.size() - 1); + } + } + + } + + static class Solution2 { + + // 备忘录,-1 代表未计算,0 代表无法凑出,1 代表可以凑出 + private int[] memo; + // 用哈希集合方便快速判断是否存在 + HashSet wordDict; + public boolean wordBreak(String s, List wordDict) { - Set set = new HashSet<>(wordDict); - boolean[] dp = new boolean[s.length() + 1]; - dp[0] = true; - for (int i = 1; i <= s.length(); i++) { - for (int j = 0; j < i; j++) { - if (dp[j] && set.contains(s.substring(j, i))) { - dp[i] = true; - break; + this.wordDict = new HashSet<>(wordDict); + this.memo = new int[s.length()]; + Arrays.fill(memo, -1); + return dp(s, 0); + } + + public boolean dp(String s, int index) { + // base case + if (index == s.length()) { return true; } + // 避免冗余 + if (memo[index] != -1) { return memo[index] == 0 ? false : true; } + + // 遍历 s[i..] 的所有前缀 + for (int len = 1; index + len <= s.length(); len++) { + // 看看哪些前缀存在 wordDict 中 + String prefix = s.substring(index, index + len); + if (wordDict.contains(prefix)) { + // 找到一个单词匹配 s[i..i+len) + // 只要 s[i+len..] 可以被拼出,s[i..] 就能被拼出 + if (dp(s, index + len)) { + memo[index] = 1; + return true; } } } - return dp[s.length()]; + // s[i..] 无法被拼出 + memo[index] = 0; + return false; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/template/\345\212\250\346\200\201\350\247\204\345\210\222\350\247\243\350\203\214\345\214\205\351\227\256\351\242\230\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/template/\345\212\250\346\200\201\350\247\204\345\210\222\350\247\243\350\203\214\345\214\205\351\227\256\351\242\230\346\250\241\346\235\277.java" new file mode 100644 index 0000000..ded4738 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/template/\345\212\250\346\200\201\350\247\204\345\210\222\350\247\243\350\203\214\345\214\205\351\227\256\351\242\230\346\250\241\346\235\277.java" @@ -0,0 +1,22 @@ +package io.github.dunwu.algorithm.dp.template; + +/** + * 动态规划解背包问题模板 + * + * @author Zhang Peng + * @date 2025-12-17 + */ +public class 动态规划解背包问题模板 { + + // int[][] dp[N+1][W+1] + // dp[0][..] = 0 + // dp[..][0] = 0 + // + // for i in [1..N]: + // for w in [1..W]: + // dp[i][w] = max( + // 把物品 i 装进背包, + // 不把物品 i 装进背包 + // ) + // return dp[N][W] +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/base/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/base/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\350\212\202\347\202\271.java" new file mode 100644 index 0000000..97faea6 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/base/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\350\212\202\347\202\271.java" @@ -0,0 +1,42 @@ +package io.github.dunwu.algorithm.linkedlist.base; + +import io.github.dunwu.algorithm.linkedlist.ListNode; +import org.junit.jupiter.api.Assertions; + +/** + * LCR 136. 删除链表的节点 + * + * @author Zhang Peng + * @date 2025-12-18 + */ +public class 删除链表的节点 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(ListNode.buildList(4, 5, 1), s.deleteNode(ListNode.buildList(4, 5, 1, 9), 9)); + Assertions.assertEquals(ListNode.buildList(4, 1, 9), s.deleteNode(ListNode.buildList(4, 5, 1, 9), 5)); + Assertions.assertEquals(ListNode.buildList(4, 5, 9), s.deleteNode(ListNode.buildList(4, 5, 1, 9), 1)); + Assertions.assertEquals(ListNode.buildList(5, 1, 9), s.deleteNode(ListNode.buildList(4, 5, 1, 9), 4)); + } + + static class Solution { + + public ListNode deleteNode(ListNode head, int val) { + ListNode dummy = new ListNode(-1); + dummy.next = head; + ListNode pre = dummy; + while (pre != null && pre.next != null) { + ListNode cur = pre.next; + if (cur.val == val) { + pre.next = cur.next; + pre = cur.next; + } else { + pre = pre.next; + } + } + return dummy.next; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" index aaf561d..8d17469 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" @@ -3,8 +3,6 @@ import io.github.dunwu.algorithm.linkedlist.ListNode; import org.junit.jupiter.api.Assertions; -import java.util.List; - /** * 83. 删除排序链表中的重复元素 * @@ -14,32 +12,25 @@ public class 删除排序链表中的重复元素 { public static void main(String[] args) { - ListNode head = ListNode.buildList(1, 1, 2); - System.out.println(ListNode.toList(head)); - ListNode result = deleteDuplicates(head); - List list = ListNode.toList(result); - System.out.println(list); - Assertions.assertArrayEquals(new Integer[] { 1, 2 }, list.toArray(new Integer[0])); - - ListNode head2 = ListNode.buildList(1, 1, 2, 3, 3); - System.out.println(ListNode.toList(head2)); - ListNode result2 = deleteDuplicates(head2); - List list2 = ListNode.toList(result2); - System.out.println(list2); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, list2.toArray(new Integer[0])); + Solution s = new Solution(); + ListNode input = ListNode.buildList(1, 1, 2); + Assertions.assertEquals(ListNode.buildList(1, 2), s.deleteDuplicates(input)); + ListNode input2 = ListNode.buildList(1, 1, 2, 3, 3); + Assertions.assertEquals(ListNode.buildList(1, 2, 3), s.deleteDuplicates(input2)); } - public static ListNode deleteDuplicates(ListNode head) { - if (head == null || head.next == null) return head; - ListNode p = head; - while (p.next != null) { - if (p.val == p.next.val) { - p.next = p.next.next; - } else { - p = p.next; + static class Solution { + + public ListNode deleteDuplicates(ListNode head) { + ListNode pre = head, cur = head.next; + while (cur != null) { + pre.next = cur.next; + pre = cur; + cur = cur.next; } + return head; } - return head; + } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\266\205\347\272\247\344\270\221\346\225\260.java" similarity index 84% rename from "codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" rename to "codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\266\205\347\272\247\344\270\221\346\225\260.java" index 59d092a..ab5b321 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\266\205\347\272\247\344\270\221\346\225\260.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\266\205\347\272\247\344\270\221\346\225\260.java" @@ -1,4 +1,4 @@ -package io.github.dunwu.algorithm.dp.array; +package io.github.dunwu.algorithm.queue; import org.junit.jupiter.api.Assertions; @@ -33,13 +33,13 @@ public int nthSuperUglyNumber(int n, int[] primes) { set.add(1L); queue.add(1L); for (int i = 1; i <= n; i++) { - long x = queue.poll(); - if (i == n) { return (int) x; } - for (int num : primes) { - long val = num * x; - if (!set.contains(val)) { - set.add(val); - queue.add(val); + long curVal = queue.poll(); + if (i == n) { return (int) curVal; } + for (int prime : primes) { + long nextVal = curVal * prime; + if (!set.contains(nextVal)) { + set.add(nextVal); + queue.add(nextVal); } } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/package-info.java index 667252f..6a2fefd 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/package-info.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/package-info.java @@ -1,5 +1,5 @@ /** - * 单调栈 + * 通过「单调栈」解决「下一个更大元素」,「上一个更小元素」等类型问题 * * @author Zhang Peng * @date 2025-11-26 diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240.java" index d7e1501..d18dd54 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240.java" @@ -22,24 +22,25 @@ public static void main(String[] args) { Assertions.assertArrayEquals(new int[] { 3, -1 }, output2); } + // 采用单调栈解决问题,算法复杂度:O(n) static class Solution { public int[] nextGreaterElement(int[] nums1, int[] nums2) { - Stack s = new Stack<>(); + Stack stack = new Stack<>(); Map map = new HashMap<>(); for (int i = nums2.length - 1; i >= 0; i--) { - while (!s.isEmpty() && s.peek() < nums2[i]) { - s.pop(); + while (!stack.isEmpty() && stack.peek() <= nums2[i]) { + stack.pop(); } - map.put(nums2[i], s.empty() ? -1 : s.peek()); - s.push(nums2[i]); + int largerVal = stack.isEmpty() ? -1 : stack.peek(); + map.put(nums2[i], largerVal); + stack.push(nums2[i]); } - int[] res = new int[nums1.length]; for (int i = 0; i < nums1.length; i++) { - res[i] = map.getOrDefault(nums1[i], -1); + nums1[i] = map.get(nums1[i]); } - return res; + return nums1; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\2402.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\2402.java" index 88e7608..b2fe027 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\2402.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\2402.java" @@ -21,15 +21,18 @@ public static void main(String[] args) { static class Solution { public int[] nextGreaterElements(int[] nums) { - int[] res = new int[nums.length]; - Stack stack = new Stack<>(); - for (int index = 2 * nums.length - 1; index >= 0; index--) { - int i = index % nums.length; - while (!stack.isEmpty() && stack.peek() <= nums[i]) { - stack.pop(); + int n = nums.length; + int[] res = new int[n]; + Stack s = new Stack<>(); + for (int i = 2 * n - 1; i >= 0; i--) { + int index = i % n; + // 遍历栈,将小于当前元素的值都踢了 + while (!s.isEmpty() && s.peek() <= nums[index]) { + s.pop(); } - res[i] = stack.empty() ? -1 : stack.peek(); - stack.push(nums[i]); + // nums[i] 下一个更大元素在栈顶 + res[index] = s.isEmpty() ? -1 : s.peek(); + s.push(nums[index]); } return res; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\234\200\347\237\255\346\227\240\345\272\217\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\234\200\347\237\255\346\227\240\345\272\217\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204.java" index 853617d..077f1c8 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\234\200\347\237\255\346\227\240\345\272\217\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\234\200\347\237\255\346\227\240\345\272\217\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204.java" @@ -2,6 +2,7 @@ import org.junit.jupiter.api.Assertions; +import java.util.Arrays; import java.util.Stack; /** @@ -17,10 +18,44 @@ public static void main(String[] args) { Assertions.assertEquals(5, s.findUnsortedSubarray(new int[] { 2, 6, 4, 8, 10, 9, 15 })); Assertions.assertEquals(0, s.findUnsortedSubarray(new int[] { 1, 2, 3, 4 })); Assertions.assertEquals(0, s.findUnsortedSubarray(new int[] { 1 })); + + Solution2 s2 = new Solution2(); + Assertions.assertEquals(5, s2.findUnsortedSubarray(new int[] { 2, 6, 4, 8, 10, 9, 15 })); + Assertions.assertEquals(0, s2.findUnsortedSubarray(new int[] { 1, 2, 3, 4 })); + Assertions.assertEquals(0, s2.findUnsortedSubarray(new int[] { 1 })); } + // 排序解法 static class Solution { + public int findUnsortedSubarray(int[] nums) { + int[] temp = Arrays.copyOf(nums, nums.length); + Arrays.sort(temp); + int left = Integer.MAX_VALUE, right = Integer.MIN_VALUE; + for (int i = 0; i < nums.length; i++) { + if (temp[i] != nums[i]) { + left = i; + break; + } + } + for (int i = nums.length - 1; i >= 0; i--) { + if (temp[i] != nums[i]) { + right = i; + break; + } + } + if (left == Integer.MAX_VALUE && right == Integer.MIN_VALUE) { + // nums 本来就是有序的 + return 0; + } + return right - left + 1; + } + + } + + // 单调栈解法 + static class Solution2 { + public int findUnsortedSubarray(int[] nums) { int n = nums.length; int left = Integer.MAX_VALUE, right = Integer.MIN_VALUE; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.java" index 0e8c6d5..aeb64a5 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.java" @@ -15,32 +15,36 @@ public class 移掉K位数字 { public static void main(String[] args) { Solution s = new Solution(); Assertions.assertEquals("1219", s.removeKdigits("1432219", 3)); + Assertions.assertEquals("200", s.removeKdigits("10200", 1)); + Assertions.assertEquals("0", s.removeKdigits("10", 2)); } static class Solution { public String removeKdigits(String num, int k) { - Stack stack = new Stack<>(); + Stack s = new Stack<>(); for (char c : num.toCharArray()) { - while (!stack.isEmpty() && stack.peek() > c && k > 0) { - stack.pop(); + // 单调栈代码模板 + while (!s.isEmpty() && c < s.peek() && k > 0) { + s.pop(); k--; } - if (stack.isEmpty() && c == '0') { - continue; - } - stack.push(c); + // 防止 0 作为数字的开头 + if (s.isEmpty() && c == '0') { continue; } + s.push(c); } - while (k > 0 && !stack.isEmpty()) { - stack.pop(); + // 此时栈中元素单调递增,若 k 还没用完的话删掉栈顶元素 + while (!s.isEmpty() && k > 0) { + s.pop(); k--; } - + // 若最后没剩下数字,就是 0 + if (s.isEmpty()) { return "0"; } + // 将栈中字符转化成字符串 StringBuilder sb = new StringBuilder(); - while (!stack.isEmpty()) { - sb.append(stack.pop()); - } + while (!s.isEmpty()) { sb.append(s.pop()); } + // 出栈顺序和字符串顺序是反的 return sb.reverse().toString(); } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\202\241\347\245\250\344\273\267\346\240\274\350\267\250\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\202\241\347\245\250\344\273\267\346\240\274\350\267\250\345\272\246.java" index dab708e..4852eb3 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\202\241\347\245\250\344\273\267\346\240\274\350\267\250\345\272\246.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\202\241\347\245\250\344\273\267\346\240\274\350\267\250\345\272\246.java" @@ -2,6 +2,8 @@ import org.junit.jupiter.api.Assertions; +import java.util.ArrayList; +import java.util.List; import java.util.Stack; /** @@ -13,31 +15,66 @@ public class 股票价格跨度 { public static void main(String[] args) { - StockSpanner stockSpanner = new StockSpanner(); - Assertions.assertEquals(1, stockSpanner.next(100)); - Assertions.assertEquals(1, stockSpanner.next(80)); - Assertions.assertEquals(1, stockSpanner.next(60)); - Assertions.assertEquals(2, stockSpanner.next(70)); - Assertions.assertEquals(1, stockSpanner.next(60)); - Assertions.assertEquals(4, stockSpanner.next(75)); - Assertions.assertEquals(6, stockSpanner.next(85)); + StockSpanner stock = new StockSpanner(); + Assertions.assertEquals(1, stock.next(100)); + Assertions.assertEquals(1, stock.next(80)); + Assertions.assertEquals(1, stock.next(60)); + Assertions.assertEquals(2, stock.next(70)); + Assertions.assertEquals(1, stock.next(60)); + Assertions.assertEquals(4, stock.next(75)); + Assertions.assertEquals(6, stock.next(85)); + + StockSpanner2 stock2 = new StockSpanner2(); + Assertions.assertEquals(1, stock2.next(100)); + Assertions.assertEquals(1, stock2.next(80)); + Assertions.assertEquals(1, stock2.next(60)); + Assertions.assertEquals(2, stock2.next(70)); + Assertions.assertEquals(1, stock2.next(60)); + Assertions.assertEquals(4, stock2.next(75)); + Assertions.assertEquals(6, stock2.next(85)); } static class StockSpanner { - private Stack stack; + private final List l; public StockSpanner() { - stack = new Stack<>(); + l = new ArrayList<>(); + } + + public int next(int price) { + int count = 1; + for (int i = l.size() - 1; i >= 0; i--) { + if (l.get(i) > price) { + break; + } + count++; + } + l.add(price); + return count; + } + + } + + static class StockSpanner2 { + + // int[] 记录 {价格,小于等于该价格的天数} 二元组 + private final Stack s; + + public StockSpanner2() { + s = new Stack<>(); } public int next(int price) { + // 算上当天 int count = 1; - while (!stack.isEmpty() && stack.peek()[0] <= price) { - int[] prev = stack.pop(); + // 单调栈模板 + while (!s.isEmpty() && s.peek()[0] <= price) { + // 挤掉价格低于 price 的记录 + int[] prev = s.pop(); count += prev[1]; } - stack.push(new int[] { price, count }); + s.push(new int[] { price, count }); return count; } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\275\246\344\275\215.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\275\246\344\275\215.java" index 95dabe8..8005fcc 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\275\246\344\275\215.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\275\246\344\275\215.java" @@ -3,6 +3,7 @@ import org.junit.jupiter.api.Assertions; import java.util.Arrays; +import java.util.Stack; /** * 853. 车队 @@ -22,43 +23,46 @@ public static void main(String[] args) { static class Solution { public int carFleet(int target, int[] position, int[] speed) { + int n = position.length; int[][] cars = new int[n][2]; for (int i = 0; i < n; i++) { cars[i][0] = position[i]; cars[i][1] = speed[i]; } + // 按照初始位置,从小到大排序 Arrays.sort(cars, (int[] a, int[] b) -> { return Integer.compare(a[0], b[0]); }); + // 计算每辆车到达终点的时间 - double[] time = new double[n]; + double[] times = new double[n]; for (int i = 0; i < n; i++) { int[] car = cars[i]; - time[i] = (double) (target - car[0]) / car[1]; + times[i] = (double) (target - car[0]) / car[1]; } // 使用单调栈计算车队的数量 - // Stack stk = new Stack<>(); - // for (double t : time) { - // while (!stk.isEmpty() && t >= stk.peek()) { - // stk.pop(); - // } - // stk.push(t); - // } - // return stk.size(); - - // 避免使用栈模拟,倒序遍历取递增序列就是答案 - int res = 0; - double maxTime = 0; - for (int i = n - 1; i >= 0; i--) { - if (time[i] > maxTime) { - maxTime = time[i]; - res++; + Stack s = new Stack<>(); + for (double t : times) { + while (!s.isEmpty() && t >= s.peek()) { + s.pop(); } + s.push(t); } - return res; + return s.size(); + + // 避免使用栈模拟,倒序遍历取递增序列就是答案 + // int res = 0; + // double maxTime = 0; + // for (int i = n - 1; i >= 0; i--) { + // if (time[i] > maxTime) { + // maxTime = time[i]; + // res++; + // } + // } + // return res; } } diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\351\230\237\345\210\227\344\270\255\345\217\257\344\273\245\347\234\213\345\210\260\347\232\204\344\272\272\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\351\230\237\345\210\227\344\270\255\345\217\257\344\273\245\347\234\213\345\210\260\347\232\204\344\272\272\346\225\260.java" new file mode 100644 index 0000000..8257b94 --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\351\230\237\345\210\227\344\270\255\345\217\257\344\273\245\347\234\213\345\210\260\347\232\204\344\272\272\346\225\260.java" @@ -0,0 +1,45 @@ +package io.github.dunwu.algorithm.stack.monotonic; + +import org.junit.jupiter.api.Assertions; + +import java.util.Stack; + +/** + * 1944. 队列中可以看到的人数 + * + * @author Zhang Peng + * @date 2025-12-19 + */ +public class 队列中可以看到的人数 { + + public static void main(String[] args) { + Solution s = new Solution(); + Assertions.assertEquals(new int[] { 3, 1, 2, 1, 1, 0 }, s.canSeePersonsCount(new int[] { 10, 6, 8, 5, 11, 9 })); + Assertions.assertEquals(new int[] { 4, 1, 1, 1, 0 }, s.canSeePersonsCount(new int[] { 5, 1, 2, 3, 10 })); + } + + static class Solution { + + public int[] canSeePersonsCount(int[] heights) { + int n = heights.length; + int[] res = new int[n]; + // int[] 记录 {身高,小于等于该身高的人数} 二元组 + Stack stk = new Stack<>(); + for (int i = n - 1; i >= 0; i--) { + // 记录右侧比自己矮的人 + int count = 0; + // 单调栈模板,计算下一个更大或相等元素(身高) + while (!stk.isEmpty() && heights[i] > stk.peek()) { + stk.pop(); + count++; + } + // 不仅可以看到比自己矮的人,如果后面存在更高的的人,也可以看到这个高人 + res[i] = stk.isEmpty() ? count : count + 1; + stk.push(heights[i]); + } + return res; + } + + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/template/\345\215\225\350\260\203\346\240\210\347\256\227\346\263\225\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/template/\345\215\225\350\260\203\346\240\210\347\256\227\346\263\225\346\250\241\346\235\277.java" new file mode 100644 index 0000000..99192ab --- /dev/null +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/template/\345\215\225\350\260\203\346\240\210\347\256\227\346\263\225\346\250\241\346\235\277.java" @@ -0,0 +1,172 @@ +package io.github.dunwu.algorithm.stack.template; + +import java.util.Stack; + +/** + * 单调栈算法模板 + * + * @author Zhang Peng + * @date 2025-12-19 + */ +public class 单调栈算法模板 { + + /** + * 下一个更大的元素:计算 nums 中每个元素的下一个更大元素 + */ + int[] nextGreaterElement(int[] nums) { + int n = nums.length; + // 存放答案的数组 + int[] res = new int[n]; + Stack s = new Stack<>(); + // 因为是求 nums[i] 后面的元素,所以倒着往栈里放 + for (int i = n - 1; i >= 0; i--) { + // 删掉 nums[i] 后面较小的元素 + while (!s.isEmpty() && s.peek() <= nums[i]) { + s.pop(); + } + // 现在栈顶就是 nums[i] 身后的更大元素 + res[i] = s.isEmpty() ? -1 : s.peek(); + s.push(nums[i]); + } + return res; + } + + /** + * 下一个更大或相等的元素:计算 nums 中每个元素的下一个更大或相等的元素 + */ + int[] nextGreaterOrEqualElement(int[] nums) { + int n = nums.length; + int[] res = new int[n]; + Stack s = new Stack<>(); + for (int i = n - 1; i >= 0; i--) { + // 把这里改成 < 号 + while (!s.isEmpty() && s.peek() < nums[i]) { + s.pop(); + } + // 现在栈顶就是 nums[i] 身后的大于等于 nums[i] 的元素 + res[i] = s.isEmpty() ? -1 : s.peek(); + s.push(nums[i]); + } + return res; + } + + /** + * 下一个更小的元素:计算 nums 中每个元素的下一个更小的元素 + */ + int[] nextLessElement(int[] nums) { + int n = nums.length; + // 存放答案的数组 + int[] res = new int[n]; + Stack s = new Stack<>(); + // 倒着往栈里放 + for (int i = n - 1; i >= 0; i--) { + // 删掉 nums[i] 后面较大的元素 + while (!s.isEmpty() && s.peek() >= nums[i]) { + s.pop(); + } + // 现在栈顶就是 nums[i] 身后的更小元素 + res[i] = s.isEmpty() ? -1 : s.peek(); + s.push(nums[i]); + } + return res; + } + + /** + * 下一个更小或相等的元素:计算 nums 中每个元素的下一个更小或相等的元素 + */ + int[] nextLessOrEqualElement(int[] nums) { + int n = nums.length; + // 存放答案的数组 + int[] res = new int[n]; + Stack s = new Stack<>(); + // 倒着往栈里放 + for (int i = n - 1; i >= 0; i--) { + // 删掉 nums[i] 后面较大的元素 + while (!s.isEmpty() && s.peek() > nums[i]) { + s.pop(); + } + // 现在栈顶就是 nums[i] 身后的更小或相等元素 + res[i] = s.isEmpty() ? -1 : s.peek(); + s.push(nums[i]); + } + return res; + } + + /** + * 上一个更大元素:计算 nums 中每个元素的上一个更大元素 + */ + int[] prevGreaterElement(int[] nums) { + int n = nums.length; + int[] res = new int[n]; + Stack s = new Stack<>(); + // 因为是求 nums[i] 前面的元素,所以正着往栈里放 + for (int i = 0; i < n; i++) { + // 删掉 nums[i] 前面较小的元素 + while (!s.isEmpty() && s.peek() <= nums[i]) { + s.pop(); + } + // 现在栈顶就是 nums[i] 前面的更大元素 + res[i] = s.isEmpty() ? -1 : s.peek(); + s.push(nums[i]); + } + return res; + } + + /** + * 上一个更大或相等的元素:计算 nums 中每个元素的上一个更大或相等元素 + */ + int[] prevGreaterOrEqualElement(int[] nums) { + int n = nums.length; + int[] res = new int[n]; + Stack s = new Stack<>(); + for (int i = 0; i < n; i++) { + // 注意不等号 + while (!s.isEmpty() && s.peek() < nums[i]) { + s.pop(); + } + // 现在栈顶就是 nums[i] 前面的更大或相等元素 + res[i] = s.isEmpty() ? -1 : s.peek(); + s.push(nums[i]); + } + return res; + } + + /** + * 上一个更小的元素:计算 nums 中每个元素的上一个更小的元素 + */ + int[] prevLessElement(int[] nums) { + int n = nums.length; + int[] res = new int[n]; + Stack s = new Stack<>(); + for (int i = 0; i < n; i++) { + // 把 nums[i] 之前的较大元素删除 + while (!s.isEmpty() && s.peek() >= nums[i]) { + s.pop(); + } + // 现在栈顶就是 nums[i] 前面的更小元素 + res[i] = s.isEmpty() ? -1 : s.peek(); + s.push(nums[i]); + } + return res; + } + + /** + * 上一个更小或相等的元素:计算 nums 中每个元素的上一个更小或相等元素 + */ + int[] prevLessOrEqualElement(int[] nums) { + int n = nums.length; + int[] res = new int[n]; + Stack s = new Stack<>(); + for (int i = 0; i < n; i++) { + // 注意不等号 + while (!s.isEmpty() && s.peek() > nums[i]) { + s.pop(); + } + // 现在栈顶就是 nums[i] 前面的更小或相等元素 + res[i] = s.isEmpty() ? -1 : s.peek(); + s.push(nums[i]); + } + return res; + } + +} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" index 5d09719..28ae963 100644 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" +++ "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" @@ -4,43 +4,30 @@ import org.junit.jupiter.api.Assertions; /** - * 路径总和 算法实现 + * 112. 路径总和 * - *

- * 给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
- *
- * 说明: 叶子节点是指没有子节点的节点。
- *
- * 示例: 
- * 给定如下二叉树,以及目标和 sum = 22,
- *
- *               5
- *              / \
- *             4   8
- *            /   / \
- *           11  13  4
- *          /  \      \
- *         7    2      1
- * 返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
- * 
- * - * @see 112. 路径总和 + * @author Zhang Peng + * @date 2020-01-29 */ public class 路径总和 { public static void main(String[] args) { - TreeNode - tree = TreeNode.buildTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, null, null, 1); - Assertions.assertTrue(hasPathSum(tree, 22)); + Solution s = new Solution(); + TreeNode tree = TreeNode.buildTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, null, null, 1); + Assertions.assertTrue(s.hasPathSum(tree, 22)); TreeNode tree2 = TreeNode.buildTree(1, 2); - Assertions.assertFalse(hasPathSum(tree2, 1)); + Assertions.assertFalse(s.hasPathSum(tree2, 1)); } - public static boolean hasPathSum(TreeNode root, int sum) { - if (root == null) { return false; } - sum -= root.val; - if (root.left == null && root.right == null) { return sum == 0; } - return hasPathSum(root.left, sum) || hasPathSum(root.right, sum); + static class Solution { + + public boolean hasPathSum(TreeNode root, int targetSum) { + if (root == null) { return false; } + if (root.left == null && root.right == null && root.val == targetSum) { return true; } + return hasPathSum(root.left, targetSum - root.val) + || hasPathSum(root.right, targetSum - root.val); + } + } } diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java index 30b14d1..117d1b1 100644 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java +++ b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java @@ -3,6 +3,7 @@ import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Random; @@ -54,6 +55,17 @@ public static String[] toStringArray(List list) { return res; } + public static List> toStringMatrixList(String[][] arr) { + if (arr == null || arr.length == 0) { return new ArrayList<>(); } + List> listlist = new ArrayList<>(); + for (String[] strings : arr) { + List list = new ArrayList<>(); + listlist.add(list); + Collections.addAll(list, strings); + } + return listlist; + } + public static String[][] toStringMatrixArray(List> listlist) { if (listlist == null || listlist.size() == 0) { return new String[0][0]; } List arrList = new ArrayList<>();