├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── deploy.yml ├── .gitignore ├── LICENSE ├── README.md ├── codes └── algorithm │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── github │ │ │ └── dunwu │ │ │ └── algorithm │ │ │ ├── Parklot.java │ │ │ ├── Test2.java │ │ │ ├── array │ │ │ ├── ArrayDemo.java │ │ │ ├── 三数之和.java │ │ │ ├── 丑数I.java │ │ │ ├── 丑数II.java │ │ │ ├── 丑数III.java │ │ │ ├── 两数之和.java │ │ │ ├── 两数之和II.java │ │ │ ├── 二维数组.java │ │ │ ├── 二进制求和.java │ │ │ ├── 删除排序数组中的重复项.java │ │ │ ├── 加一.java │ │ │ ├── 反转字符串.java │ │ │ ├── 合并区间.java │ │ │ ├── 在排序数组中查找元素的第一个和最后一个位置.java │ │ │ ├── 在排序数组中查找数字I.java │ │ │ ├── 存在重复元素.java │ │ │ ├── 对角线遍历.java │ │ │ ├── 寻找数组的中心索引.java │ │ │ ├── 将数组分成和相等的三个部分.java │ │ │ ├── 搜索插入位置.java │ │ │ ├── 数组二分查找.java │ │ │ ├── 数组拆分1.java │ │ │ ├── 旋转数组.java │ │ │ ├── 旋转矩阵.java │ │ │ ├── 最大连续1的个数.java │ │ │ ├── 有序矩阵中第K小的元素.java │ │ │ ├── 杨辉三角.java │ │ │ ├── 杨辉三角2.java │ │ │ ├── 查找和最小的K对数字.java │ │ │ ├── 查找总价格为目标值的两个商品.java │ │ │ ├── 模拟ArrayList1.java │ │ │ ├── 模拟ArrayList2.java │ │ │ ├── 移动零.java │ │ │ ├── 移除元素.java │ │ │ ├── 至少是其他数字两倍的最大数.java │ │ │ ├── 螺旋矩阵.java │ │ │ ├── 超级丑数.java │ │ │ ├── 长度最小的子数组.java │ │ │ └── 零矩阵.java │ │ │ ├── common │ │ │ ├── IHeap.java │ │ │ ├── IList.java │ │ │ ├── IMap.java │ │ │ ├── IQueue.java │ │ │ ├── ISet.java │ │ │ ├── IStack.java │ │ │ ├── ISuffixTree.java │ │ │ └── ITree.java │ │ │ ├── dfs │ │ │ ├── N皇后.java │ │ │ └── N皇后II.java │ │ │ ├── divide │ │ │ ├── N次幂.java │ │ │ ├── package-info.java │ │ │ └── 多数元素.java │ │ │ ├── dynamic │ │ │ ├── MaxSubArray.java │ │ │ ├── package-info.java │ │ │ ├── 三角形最小路径和.java │ │ │ ├── 乘积最大子数组.java │ │ │ ├── 买卖股票的最佳时机.java │ │ │ ├── 买卖股票的最佳时机II.java │ │ │ ├── 买卖股票的最佳时机III.java │ │ │ ├── 买卖股票的最佳时机IV.java │ │ │ ├── 买卖股票的最佳时机含手续费.java │ │ │ ├── 判断子序列.java │ │ │ ├── 最佳买卖股票时机含冷冻期.java │ │ │ ├── 最大子序和.java │ │ │ ├── 最长上升子序列.java │ │ │ ├── 爬楼梯.java │ │ │ ├── 编辑距离.java │ │ │ └── 零钱兑换.java │ │ │ ├── hash │ │ │ ├── DesignHashmap.java │ │ │ ├── MyHashMap.java │ │ │ ├── MyHashSet.java │ │ │ └── MyHashSet2.java │ │ │ ├── hashtable │ │ │ ├── JewelsAndStones.java │ │ │ ├── SubdomainVisitCount.java │ │ │ └── ToLowerCase.java │ │ │ ├── heap │ │ │ ├── KthLargest.java │ │ │ ├── KthLeast.java │ │ │ └── LeastKNum.java │ │ │ ├── list │ │ │ ├── DoublyLinkedList.java │ │ │ ├── LRUBaseLinkedList.java │ │ │ ├── LRUBasedArray.java │ │ │ ├── ListNode.java │ │ │ ├── ListUtil.java │ │ │ ├── MyLinkedList.java │ │ │ ├── SinglyLinkedList.java │ │ │ ├── 两数相加.java │ │ │ ├── 两数相加II.java │ │ │ ├── 二进制链表转整数.java │ │ │ ├── 从未排序的链表中移除重复元素.java │ │ │ ├── 分隔链表.java │ │ │ ├── 删除排序链表中的重复元素.java │ │ │ ├── 删除排序链表中的重复元素II.java │ │ │ ├── 删除链表的倒数第N个结点.java │ │ │ ├── 单链表示例.java │ │ │ ├── 双链表示例.java │ │ │ ├── 反转链表.java │ │ │ ├── 反转链表II.java │ │ │ ├── 合并K个排序链表.java │ │ │ ├── 合并两个有序链表.java │ │ │ ├── 回文链表.java │ │ │ ├── 奇偶链表.java │ │ │ ├── 排序链表.java │ │ │ ├── 环形链表.java │ │ │ ├── 环形链表II.java │ │ │ ├── 相交链表.java │ │ │ ├── 移除重复节点.java │ │ │ ├── 移除链表元素.java │ │ │ ├── 设计链表.java │ │ │ ├── 返回倒数第k个节点.java │ │ │ └── 链表的中间结点.java │ │ │ ├── map │ │ │ └── LRUCache.java │ │ │ ├── queue │ │ │ ├── GenericQueue.java │ │ │ ├── MyCircularDeque.java │ │ │ ├── 动态扩容数组实现的队列.java │ │ │ ├── 数组实现的队列.java │ │ │ ├── 最近的请求次数.java │ │ │ ├── 设计循环队列.java │ │ │ └── 链表实现的队列.java │ │ │ ├── recursive │ │ │ └── 反转字符串.java │ │ │ ├── search │ │ │ ├── HashDemo.java │ │ │ ├── Search.java │ │ │ ├── SearchStrategy.java │ │ │ ├── strategy │ │ │ │ ├── BinarySearch.java │ │ │ │ └── OrderSearch.java │ │ │ ├── x的平方根.java │ │ │ ├── 搜索二维矩阵.java │ │ │ ├── 搜索插入位置.java │ │ │ └── 第一个错误的版本.java │ │ │ ├── sort │ │ │ ├── Sort.java │ │ │ ├── SortStrategy.java │ │ │ └── strategy │ │ │ │ ├── BubbleSort.java │ │ │ │ ├── BubbleSort2.java │ │ │ │ ├── HeapSort.java │ │ │ │ ├── InsertSort.java │ │ │ │ ├── MergeSort.java │ │ │ │ ├── QuickSort.java │ │ │ │ ├── SelectionSort.java │ │ │ │ └── ShellSort.java │ │ │ ├── stack │ │ │ ├── GenericStack.java │ │ │ ├── SampleBrowser.java │ │ │ ├── StackBasedOnLinkedList.java │ │ │ ├── 三合一.java │ │ │ ├── 基本计算器.java │ │ │ ├── 最小栈.java │ │ │ ├── 最小栈2.java │ │ │ ├── 有效的括号.java │ │ │ ├── 栈排序.java │ │ │ ├── 棒球比赛.java │ │ │ ├── 比较含退格的字符串.java │ │ │ ├── 用栈实现队列.java │ │ │ └── 用队列实现栈.java │ │ │ ├── str │ │ │ ├── AddBinary.java │ │ │ ├── ImplementStrstr.java │ │ │ ├── LongestCommonPrefix.java │ │ │ ├── ReverseString.java │ │ │ ├── ReverseWordsInAString.java │ │ │ ├── ReverseWordsInAString3.java │ │ │ └── StringAlgorithm.java │ │ │ ├── string │ │ │ ├── StringAlgorithm.java │ │ │ ├── ValidAnagram.java │ │ │ ├── 最小覆盖子串.java │ │ │ └── 最长回文子串.java │ │ │ ├── tree │ │ │ ├── BTree.java │ │ │ ├── BinaryTree.java │ │ │ ├── IntBTree.java │ │ │ ├── N叉树的最大深度.java │ │ │ ├── TreeNode.java │ │ │ ├── TreeUtils.java │ │ │ ├── bstree │ │ │ │ ├── package-info.java │ │ │ │ ├── 二叉搜索树中的插入操作.java │ │ │ │ ├── 二叉搜索树的最近公共祖先.java │ │ │ │ ├── 二叉搜索树节点最小距离.java │ │ │ │ ├── 将有序数组转换为二叉搜索树.java │ │ │ │ └── 验证二叉搜索树.java │ │ │ └── btree │ │ │ │ ├── package-info.java │ │ │ │ ├── 二叉树中的最大路径和.java │ │ │ │ ├── 二叉树的中序遍历.java │ │ │ │ ├── 二叉树的前序遍历.java │ │ │ │ ├── 二叉树的后序遍历.java │ │ │ │ ├── 二叉树的层次遍历.java │ │ │ │ ├── 二叉树的层次遍历2.java │ │ │ │ ├── 二叉树的序列化与反序列化.java │ │ │ │ ├── 二叉树的所有路径.java │ │ │ │ ├── 二叉树的最大深度.java │ │ │ │ ├── 二叉树的最小深度.java │ │ │ │ ├── 二叉树的最近公共祖先.java │ │ │ │ ├── 二叉树的锯齿形层次遍历.java │ │ │ │ ├── 从中序与后序遍历序列构造二叉树.java │ │ │ │ ├── 从先序遍历还原二叉树.java │ │ │ │ ├── 从前序与中序遍历序列构造二叉树.java │ │ │ │ ├── 叶子相似的树.java │ │ │ │ ├── 填充每个节点的下一个右侧节点指针.java │ │ │ │ ├── 填充每个节点的下一个右侧节点指针II.java │ │ │ │ ├── 对称二叉树.java │ │ │ │ ├── 平衡二叉树.java │ │ │ │ ├── 相同的树.java │ │ │ │ ├── 翻转二叉树.java │ │ │ │ └── 路径总和.java │ │ │ ├── trie │ │ │ ├── Trie.java │ │ │ ├── 单词搜索.java │ │ │ ├── 单词搜索II.java │ │ │ ├── 实现Trie_前缀树.java │ │ │ └── 最长公共前缀.java │ │ │ ├── util │ │ │ └── ArrayUtil.java │ │ │ └── 括号生成.java │ └── resources │ │ └── logback.xml │ └── test │ └── java │ └── io │ └── github │ └── dunwu │ └── algorithm │ ├── common │ ├── IteratorTest.java │ ├── JavaCollectionTest.java │ ├── JavaMapTest.java │ ├── ListIteratorTest.java │ ├── ListTest.java │ ├── MapTest.java │ ├── QueueTest.java │ ├── SetTest.java │ ├── StackTest.java │ ├── SuffixTreeTest.java │ ├── TreeTest.java │ └── Utils.java │ ├── list │ ├── DoubleLinkListTests.java │ └── SingleLinkListTests.java │ ├── map │ └── LRUCacheTest.java │ ├── search │ └── SearchStrategyTest.java │ ├── sort │ └── SortStrategyTest.java │ ├── str │ ├── AddBinaryTest.java │ ├── ImplementStrstrTest.java │ ├── LongestCommonPrefixTest.java │ ├── ReverseStringTest.java │ ├── ReverseWordsInAString3Test.java │ ├── ReverseWordsInAStringTest.java │ └── StringAlgorithmTest.java │ ├── string │ └── StringAlgorithmTest.java │ └── tree │ ├── BTreeDemoTests.java │ ├── BTreeTests.java │ └── BinaryTreeTests.java ├── docs ├── .vuepress │ ├── config.js │ ├── config │ │ ├── baiduCode.js │ │ ├── htmlModules.js │ │ └── sidebar.js │ ├── enhanceApp.js │ ├── plugins │ │ └── love-me │ │ │ ├── index.js │ │ │ └── love-me.js │ ├── public │ │ ├── favicon.ico │ │ ├── img │ │ │ ├── bg.gif │ │ │ ├── bg.jpeg │ │ │ ├── bg.jpg │ │ │ ├── dunwu-logo.png │ │ │ ├── favicon.ico │ │ │ ├── git.png │ │ │ ├── logo.png │ │ │ ├── more.png │ │ │ ├── other.png │ │ │ ├── panda-waving.png │ │ │ ├── python.png │ │ │ ├── ui.png │ │ │ └── web.png │ │ └── markmap │ │ │ └── 01.html │ └── styles │ │ ├── index.styl │ │ └── palette.styl ├── 01.数据结构和算法 │ ├── 00.综合 │ │ ├── 01.数据结构和算法指南.md │ │ └── 02.复杂度分析.md │ ├── 01.线性表 │ │ ├── 01.数组和链表.md │ │ ├── 02.栈和队列.md │ │ ├── 11.线性表的查找.md │ │ └── 12.线性表的排序.md │ ├── 02.树 │ │ ├── 01.树和二叉树.md │ │ ├── 02.堆.md │ │ ├── 03.B+树.md │ │ ├── 04.LSM树.md │ │ ├── 05.字典树.md │ │ └── 06.红黑树.md │ ├── 03.哈希表.md │ ├── 04.跳表.md │ └── 05.图.md ├── @pages │ ├── archivesPage.md │ ├── categoriesPage.md │ └── tagsPage.md ├── README.md ├── algorithm-template.md ├── hash-search.md ├── 算法思路.md └── 算法练习-树.md ├── package.json ├── pom.xml ├── prettier.config.js ├── scripts └── deploy.sh └── utils ├── config.yml ├── editFrontmatter.js └── modules ├── fn.js └── readFileList.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig 用于在 IDE 中检查代码的基本 Code Style 2 | # @see: https://editorconfig.org/ 3 | 4 | # 配置说明: 5 | # 所有文件换行使用 Unix 风格(LF),*.bat 文件使用 Windows 风格(CRLF) 6 | # java / sh 文件缩进 4 个空格,其他所有文件缩进 2 个空格 7 | 8 | root = true 9 | 10 | [*] 11 | end_of_line = lf 12 | indent_size = 2 13 | indent_style = space 14 | max_line_length = 120 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.{bat, cmd}] 20 | end_of_line = crlf 21 | 22 | [*.{java, gradle, groovy, kt, sh, xml}] 23 | indent_size = 4 24 | 25 | [*.md] 26 | max_line_length = 0 27 | trim_trailing_whitespace = false 28 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | # plan text 4 | *.txt text 5 | *.java text 6 | *.scala text 7 | *.groovy text 8 | *.gradle text 9 | *.xml text 10 | *.xsd text 11 | *.tld text 12 | *.yaml text 13 | *.yml text 14 | *.wsdd text 15 | *.wsdl text 16 | *.jsp text 17 | *.jspf text 18 | *.js text 19 | *.jsx text 20 | *.json text 21 | *.css text 22 | *.less text 23 | *.sql text 24 | *.properties text 25 | *.md text 26 | 27 | # unix style 28 | *.sh text eol=lf 29 | 30 | # win style 31 | *.bat text eol=crlf 32 | 33 | # don't handle 34 | *.der -text 35 | *.jks -text 36 | *.pfx -text 37 | *.map -text 38 | *.patch -text 39 | *.dat -text 40 | *.data -text 41 | *.db -text 42 | 43 | # binary 44 | *.jar binary 45 | *.war binary 46 | *.zip binary 47 | *.tar binary 48 | *.tar.gz binary 49 | *.gz binary 50 | *.apk binary 51 | *.bin binary 52 | *.exe binary 53 | 54 | # images 55 | *.png binary 56 | *.jpg binary 57 | *.ico binary 58 | *.gif binary 59 | 60 | # medias 61 | *.mp3 binary 62 | *.swf binary 63 | 64 | # fonts 65 | *.eot binary 66 | *.svg binary 67 | *.ttf binary 68 | *.woff binary 69 | 70 | # others 71 | *.pdf binary 72 | *.doc binary 73 | *.docx binary 74 | *.ppt binary 75 | *.pptx binary 76 | *.xls binary 77 | *.xlsx binary 78 | *.xmind binary 79 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | # 在master分支发生push事件时触发。 4 | on: 5 | push: 6 | branches: 7 | - master 8 | 9 | env: # 设置环境变量 10 | TZ: Asia/Shanghai # 时区(设置时区可使页面中的`最近更新时间`使用时区时间) 11 | 12 | jobs: 13 | build: # 自定义名称 14 | runs-on: ubuntu-latest # 运行在虚拟机环境ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [14.x] 19 | 20 | steps: 21 | # 使用的动作。格式:userName/repoName。作用:检出仓库,获取源码。 官方actions库:https://github.com/actions 22 | - name: Checkout 23 | uses: actions/checkout@master 24 | 25 | # 指定 nodejs 版本 26 | - name: Use Nodejs ${{ matrix.node-version }} 27 | uses: actions/setup-node@v1 28 | with: 29 | node-version: ${{ matrix.node-version }} 30 | 31 | # 部署 32 | - name: Deploy 33 | env: # 设置环境变量 34 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 35 | GITEE_TOKEN: ${{ secrets.GITEE_TOKEN }} 36 | run: npm install && npm run deploy 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------- 2 | # more gitignore templates see https://github.com/github/gitignore 3 | # --------------------------------------------------------------------- 4 | 5 | # ------------------------------- java ------------------------------- 6 | # compiled folders 7 | classes 8 | target 9 | logs 10 | .mtj.tmp/ 11 | 12 | # compiled files 13 | *.class 14 | 15 | # bluej files 16 | *.ctxt 17 | 18 | # package files # 19 | *.jar 20 | *.war 21 | *.nar 22 | *.ear 23 | *.zip 24 | *.tar.gz 25 | *.rar 26 | 27 | # virtual machine crash logs 28 | hs_err_pid* 29 | 30 | # maven plugin temp files 31 | .flattened-pom.xml 32 | 33 | 34 | # ------------------------------- javascript ------------------------------- 35 | # dependencies 36 | node_modules 37 | 38 | # temp folders 39 | build 40 | dist 41 | _book 42 | _jsdoc 43 | .temp 44 | .deploy*/ 45 | 46 | # temp files 47 | *.log 48 | npm-debug.log* 49 | yarn-debug.log* 50 | yarn-error.log* 51 | bundle*.js 52 | .DS_Store 53 | Thumbs.db 54 | db.json 55 | book.pdf 56 | package-lock.json 57 | 58 | 59 | # ------------------------------- intellij ------------------------------- 60 | .idea 61 | *.iml 62 | 63 | 64 | # ------------------------------- eclipse ------------------------------- 65 | .classpath 66 | .project 67 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/ArrayDemo.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | /** 4 | * @author Zhang Peng 5 | * @since 2020-01-20 6 | */ 7 | public class ArrayDemo { 8 | 9 | public static int maxSubArray(int[] nums) { 10 | int len = nums.length; 11 | 12 | int maxSum = nums[0]; 13 | for (int i = 1; i < len; i++) { 14 | if (nums[i - 1] > 0) nums[i] += nums[i - 1]; 15 | maxSum = Math.max(nums[i], maxSum); 16 | } 17 | return maxSum; 18 | } 19 | 20 | public static void main(String[] args) { 21 | int max = maxSubArray(new int[] { -2, 1, -3, 4, -1, 2, 1, -5, 4 }); 22 | System.out.println("max = " + max); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/丑数I.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | /** 9 | * 263. 丑数 10 | * 11 | * @author Zhang Peng 12 | * @date 2025-01-24 13 | */ 14 | public class 丑数I { 15 | 16 | public static void main(String[] args) { 17 | Assertions.assertTrue(isUgly(6)); 18 | Assertions.assertTrue(isUgly(1)); 19 | Assertions.assertFalse(isUgly(14)); 20 | } 21 | 22 | public static boolean isUgly(int n) { 23 | while (n <= 0) return false; 24 | while (n % 2 == 0) n /= 2; 25 | while (n % 3 == 0) n /= 3; 26 | while (n % 5 == 0) n /= 5; 27 | return n == 1; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/丑数II.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * 264. 丑数II 7 | * 8 | * @author Zhang Peng 9 | * @date 2025-01-24 10 | */ 11 | public class 丑数II { 12 | 13 | public static void main(String[] args) { 14 | Assertions.assertEquals(12, nthUglyNumber(10)); 15 | Assertions.assertEquals(1, nthUglyNumber(1)); 16 | } 17 | 18 | public static int nthUglyNumber(int n) { 19 | if (n == 1) { 20 | return 1; 21 | } 22 | 23 | // 可以理解为三个指向有序链表头结点的指针 24 | int p2 = 1, p3 = 1, p5 = 1; 25 | // 可以理解为三个有序链表的头节点的值 26 | int product2 = 1, product3 = 1, product5 = 1; 27 | // 可以理解为最终合并的有序链表(结果链表) 28 | int[] ugly = new int[n + 1]; 29 | // 可以理解为结果链表上的指针 30 | int u = 1; 31 | 32 | while (u <= n) { 33 | int min = Math.min(product2, Math.min(product3, product5)); 34 | ugly[u++] = min; 35 | if (min == product2) { 36 | product2 = 2 * ugly[p2]; 37 | p2++; 38 | } 39 | if (min == product3) { 40 | product3 = 3 * ugly[p3]; 41 | p3++; 42 | } 43 | if (min == product5) { 44 | product5 = 5 * ugly[p5]; 45 | p5++; 46 | } 47 | } 48 | return ugly[n]; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/丑数III.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * 264. 丑数II 7 | * 8 | * @author Zhang Peng 9 | * @date 2025-01-24 10 | */ 11 | public class 丑数III { 12 | 13 | public static void main(String[] args) { 14 | Assertions.assertEquals(4, nthUglyNumber(3, 2, 3, 5)); 15 | Assertions.assertEquals(6, nthUglyNumber(4, 2, 3, 4)); 16 | Assertions.assertEquals(10, nthUglyNumber(5, 2, 11, 13)); 17 | Assertions.assertEquals(1999999984, nthUglyNumber(1000000000, 2, 217983653, 336916467)); 18 | } 19 | 20 | public static int nthUglyNumber(int n, int a, int b, int c) { 21 | int p = 1; 22 | int vA = a, vB = b, vC = c; 23 | long min = Integer.MAX_VALUE; 24 | while (p <= n) { 25 | min = Math.min(vA, Math.min(vB, vC)); 26 | if (min == vA) { 27 | vA += a; 28 | } 29 | if (min == vB) { 30 | vB += b; 31 | } 32 | if (min == vC) { 33 | vC += c; 34 | } 35 | p++; 36 | } 37 | return (int) min; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/二维数组.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | /** 4 | * @author Zhang Peng 5 | * @since 2018-11-04 6 | */ 7 | public class 二维数组 { 8 | 9 | public static void main(String[] args) { 10 | System.out.println("Example I:"); 11 | int[][] a = new int[2][5]; 12 | printArray(a); 13 | System.out.println("Example II:"); 14 | int[][] b = new int[2][]; 15 | printArray(b); 16 | System.out.println("Example III:"); 17 | b[0] = new int[3]; 18 | b[1] = new int[5]; 19 | printArray(b); 20 | } 21 | 22 | private static void printArray(int[][] a) { 23 | for (int i = 0; i < a.length; ++i) { 24 | System.out.println(a[i]); 25 | } 26 | for (int i = 0; i < a.length; ++i) { 27 | for (int j = 0; a[i] != null && j < a[i].length; ++j) { 28 | System.out.print(a[i][j] + " "); 29 | } 30 | System.out.println(); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/二进制求和.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * 67. 二进制求和 7 | * 8 | * @author Zhang Peng 9 | * @date 2025-01-21 10 | */ 11 | public class 二进制求和 { 12 | 13 | public static void main(String[] args) { 14 | Assertions.assertEquals("100", addBinary("11", "1")); 15 | Assertions.assertEquals("10101", addBinary("1010", "1011")); 16 | } 17 | 18 | public static String addBinary(String a, String b) { 19 | 20 | if (a == null || a.length() == 0) return b; 21 | if (b == null || b.length() == 0) return a; 22 | 23 | char[] arrA = a.toCharArray(); 24 | char[] arrB = b.toCharArray(); 25 | StringBuilder sb = new StringBuilder(); 26 | int carry = 0; 27 | int i = arrA.length - 1, j = arrB.length - 1; 28 | while (i >= 0 || j >= 0) { 29 | int value = carry; 30 | if (i >= 0) { 31 | value += arrA[i--] - '0'; 32 | } 33 | if (j >= 0) { 34 | value += arrB[j--] - '0'; 35 | } 36 | carry = value / 2; 37 | value = value % 2; 38 | sb.append(value); 39 | } 40 | if (carry != 0) { 41 | sb.append(carry); 42 | } 43 | return sb.reverse().toString(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/删除排序数组中的重复项.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * 26. 删除有序数组中的重复项 7 | * 8 | * @author Zhang Peng 9 | * @since 2018-11-05 10 | */ 11 | public class 删除排序数组中的重复项 { 12 | 13 | public static void main(String[] args) { 14 | int[] nums1 = { 1, 1, 2 }; 15 | Assertions.assertEquals(2, removeDuplicates(nums1)); 16 | 17 | int[] nums2 = { 0, 0, 1, 1, 1, 2, 2, 3, 3, 4 }; 18 | Assertions.assertEquals(5, removeDuplicates(nums2)); 19 | 20 | int[] nums3 = { 1, 2 }; 21 | Assertions.assertEquals(2, removeDuplicates(nums3)); 22 | 23 | int[] nums4 = { 2, 2 }; 24 | Assertions.assertEquals(1, removeDuplicates(nums4)); 25 | } 26 | 27 | public static int removeDuplicates(int[] nums) { 28 | if (nums.length == 0) { 29 | return 0; 30 | } 31 | int slow = 0, fast = 0; 32 | while (fast < nums.length) { 33 | if (nums[slow] != nums[fast]) { 34 | slow++; 35 | nums[slow] = nums[fast]; 36 | } 37 | fast++; 38 | } 39 | return slow + 1; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/加一.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | // 【加一】 4 | 5 | // 6 | // 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 7 | // 8 | // 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。 9 | // 10 | // 你可以假设除了整数 0 之外,这个整数不会以零开头。 11 | // 12 | // 示例 1: 13 | // 14 | // 输入: [1,2,3] 15 | // 输出: [1,2,4] 16 | // 解释: 输入数组表示数字 123。 17 | // 示例 2: 18 | // 19 | // 输入: [4,3,2,1] 20 | // 输出: [4,3,2,2] 21 | // 解释: 输入数组表示数字 4321。 22 | 23 | import org.junit.jupiter.api.Assertions; 24 | 25 | /** 26 | * @author Zhang Peng 27 | * @since 2018-11-04 28 | */ 29 | public class 加一 { 30 | 31 | public static void main(String[] args) { 32 | int[] nums1 = { 1, 2, 3 }; 33 | int[] nums2 = { 4, 3, 2, 1 }; 34 | int[] nums3 = { 9, 9, 9, 9 }; 35 | 36 | int[] expected1 = { 1, 2, 4 }; 37 | int[] expected2 = { 4, 3, 2, 2 }; 38 | int[] expected3 = { 1, 0, 0, 0, 0 }; 39 | 40 | Assertions.assertArrayEquals(expected1, 加一.plusOne(nums1)); 41 | Assertions.assertArrayEquals(expected2, 加一.plusOne(nums2)); 42 | Assertions.assertArrayEquals(expected3, 加一.plusOne(nums3)); 43 | } 44 | 45 | public static int[] plusOne(int[] digits) { 46 | int n = digits.length; 47 | for (int i = n - 1; i >= 0; i--) { 48 | if (digits[i] < 9) { 49 | digits[i]++; 50 | return digits; 51 | } 52 | 53 | digits[i] = 0; 54 | } 55 | 56 | int[] newNumber = new int[n + 1]; 57 | newNumber[0] = 1; 58 | 59 | return newNumber; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/反转字符串.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * 题目:344. 反转字符串 7 | * 8 | * @author Zhang Peng 9 | * @since 2020-06-05 10 | */ 11 | public class 反转字符串 { 12 | 13 | public static void main(String[] args) { 14 | char[] s1 = new char[] { 'h', 'e', 'l', 'l', 'o' }; 15 | reverseString(s1); 16 | Assertions.assertArrayEquals(new char[] { 'o', 'l', 'l', 'e', 'h' }, s1); 17 | 18 | char[] s2 = new char[] { 'H', 'a', 'n', 'n', 'a', 'h' }; 19 | reverseString(s2); 20 | Assertions.assertArrayEquals(new char[] { 'h', 'a', 'n', 'n', 'a', 'H' }, s2); 21 | } 22 | 23 | public static void reverseString(char[] s) { 24 | int left = 0, right = s.length - 1; 25 | while (left < right) { 26 | char temp = s[left]; 27 | s[left] = s[right]; 28 | s[right] = temp; 29 | left++; 30 | right--; 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/在排序数组中查找数字I.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * @author Zhang Peng 9 | * @since 2020-06-05 10 | */ 11 | public class 在排序数组中查找数字I { 12 | 13 | public static void main(String[] args) { 14 | Assertions.assertEquals(2, count(8, new Integer[] { 7, 8, 5, 10, 7, 8 })); 15 | Assertions.assertEquals(0, count(6, new Integer[] { 5, 7, 7, 8, 8, 10 })); 16 | Assertions.assertEquals(2, count("abc", new String[] { "abc", "xyz", "lmn", "abc" })); 17 | } 18 | 19 | /** 20 | * 题目:面试题53 - I. 21 | * 在排序数组中查找数字I 22 | *

23 | * 统计一个元素在数组中出现的次数。 24 | */ 25 | public static int count(T target, T[] array) { 26 | Arrays.sort(array); 27 | 28 | int count = 0; 29 | for (T i : array) { 30 | if (target.equals(i)) { 31 | count++; 32 | continue; 33 | } 34 | 35 | if (count != 0) { break; } 36 | } 37 | return count; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/存在重复元素.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | import java.util.Arrays; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | /** 10 | * @author Zhang Peng 11 | * @since 2020-06-05 12 | */ 13 | public class 存在重复元素 { 14 | 15 | public static void main(String[] args) { 16 | Assertions.assertTrue(containsDuplicate(new Integer[] { 1, 2, 3, 1 })); 17 | Assertions.assertFalse(containsDuplicate(new Integer[] { 1, 2, 3, 4 })); 18 | Assertions.assertTrue(containsDuplicate(new Integer[] { 1, 1, 1, 3, 3, 4, 3, 2, 4, 2 })); 19 | } 20 | 21 | /** 22 | * 题目:217. 存在重复元素 23 | *

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

26 | * 如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。 27 | * 28 | * @param array 数组 29 | * @return true/false 30 | */ 31 | public static boolean containsDuplicate(T[] array) { 32 | if (array == null || array.length <= 1) { 33 | return false; 34 | } 35 | 36 | Set set = new HashSet<>(); 37 | set.addAll(Arrays.asList(array)); 38 | 39 | return set.size() != array.length; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/将数组分成和相等的三个部分.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @since 2020-06-05 8 | */ 9 | public class 将数组分成和相等的三个部分 { 10 | 11 | public static void main(String[] args) { 12 | Assertions.assertTrue(canThreePartsEqualSum(new int[] { 0, 2, 1, -6, 6, -7, 9, 1, 2, 0, 1 })); 13 | Assertions.assertTrue(canThreePartsEqualSum(new int[] { 3, 3, 6, 5, -2, 2, 5, 1, -9, 4 })); 14 | Assertions.assertFalse(canThreePartsEqualSum(new int[] { 0, 2, 1, -6, 6, 7, 9, -1, 2, 0, 1 })); 15 | } 16 | 17 | /** 18 | * 题目:1013. 19 | * 将数组分成和相等的三个部分 20 | *

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

23 | * 形式上,如果可以找出索引 i+1 < j 且满足 (A[0] + A[1] + ... + A[i] == A[i+1] + A[i+2] + ... + A[j-1] == A[j] + A[j-1] + ... + 24 | * A[A.length - 1]) 就可以将数组三等分。 25 | */ 26 | public static boolean canThreePartsEqualSum(int[] array) { 27 | return false; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/搜索插入位置.java: -------------------------------------------------------------------------------- 1 | // 35. 搜索插入位置 2 | // 3 | // 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 4 | // 5 | // 请必须使用时间复杂度为 O(log n) 的算法。 6 | // 7 | // 8 | // 9 | // 示例 1: 10 | // 11 | // 输入: nums = [1,3,5,6], target = 5 12 | // 输出: 2 13 | // 示例 2: 14 | // 15 | // 输入: nums = [1,3,5,6], target = 2 16 | // 输出: 1 17 | // 示例 3: 18 | // 19 | // 输入: nums = [1,3,5,6], target = 7 20 | // 输出: 4 21 | // 示例 4: 22 | // 23 | // 输入: nums = [1,3,5,6], target = 0 24 | // 输出: 0 25 | // 示例 5: 26 | // 27 | // 输入: nums = [1], target = 0 28 | // 输出: 0 29 | // 30 | // 31 | // 提示: 32 | // 33 | // 1 <= nums.length <= 104 34 | // -104 <= nums[i] <= 104 35 | // nums 为无重复元素的升序排列数组 36 | // -104 <= target <= 104 37 | // 38 | // 来源:力扣(LeetCode) 39 | // 链接:https://leetcode-cn.com/problems/search-insert-position 40 | 41 | package io.github.dunwu.algorithm.array; 42 | 43 | import org.junit.jupiter.api.Assertions; 44 | 45 | /** 46 | * @author Zhang Peng 47 | * @see 搜索插入位置 48 | * @since 2020-07-29 49 | */ 50 | public class 搜索插入位置 { 51 | 52 | public static void main(String[] args) { 53 | Assertions.assertEquals(0, searchInsert(new int[] { 1 }, 1)); 54 | Assertions.assertEquals(2, searchInsert(new int[] { 1, 3, 5, 6 }, 5)); 55 | Assertions.assertEquals(1, searchInsert(new int[] { 1, 3, 5, 6 }, 2)); 56 | Assertions.assertEquals(4, searchInsert(new int[] { 1, 3, 5, 6 }, 7)); 57 | Assertions.assertEquals(0, searchInsert(new int[] { 1, 3, 5, 6 }, 0)); 58 | } 59 | 60 | public static int searchInsert(int[] nums, int target) { 61 | for (int pos = 0; pos < nums.length; pos++) { 62 | if (nums[pos] >= target) { 63 | return pos; 64 | } 65 | } 66 | return nums.length; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/数组二分查找.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @since 2020-06-05 8 | */ 9 | public class 数组二分查找 { 10 | 11 | public static void main(String[] args) { 12 | Assertions.assertEquals(5, binarySearch(new int[] { 5, 7, 7, 8, 8, 10 }, 10)); 13 | Assertions.assertEquals(0, binarySearch(new int[] { 5, 7, 7, 8, 8, 10 }, 5)); 14 | Assertions.assertEquals(2, binarySearch(new int[] { 5, 7, 7, 8, 8, 10 }, 7)); 15 | } 16 | 17 | /** 18 | * 数组二分查找,要求传入的数组是有序排列 19 | *

20 | * 参考: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/ 21 | */ 22 | public static int binarySearch(int[] nums, int target) { 23 | if (nums == null || nums.length == 0) { return -1; } 24 | 25 | int left = 0, right = nums.length - 1; 26 | while (left <= right) { 27 | int mid = left + (right - left) / 2; // 防止 mid 溢出 28 | if (nums[mid] == target) { 29 | return mid; 30 | } else if (nums[mid] < target) { 31 | left = mid + 1; 32 | } else if (nums[mid] > target) { 33 | right = mid - 1; 34 | } 35 | } 36 | 37 | return -1; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/数组拆分1.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | // 【数组拆分 I】 4 | // 5 | // 给定长度为 2n 的数组, 你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), ..., (an, bn) ,使得从1 到 n 的 min(ai, bi) 总和最大。 6 | // 7 | // 示例 1: 8 | // 9 | // 输入: [1,4,3,2] 10 | // 11 | // 输出: 4 12 | // 解释: n 等于 2, 最大总和为 4 = min(1, 2) + min(3, 4). 13 | // 提示: 14 | // 15 | // n 是正整数,范围在 [1, 10000]. 16 | // 数组中的元素范围在 [-10000, 10000]. 17 | 18 | import org.junit.jupiter.api.Assertions; 19 | 20 | import java.util.Arrays; 21 | 22 | /** 23 | * @author Zhang Peng 24 | * @since 2018-11-05 25 | */ 26 | public class 数组拆分1 { 27 | 28 | public static void main(String[] args) { 29 | int[] nums1 = { 1, 4, 3, 2 }; 30 | Assertions.assertEquals(4, 数组拆分1.arrayPairSum(nums1)); 31 | } 32 | 33 | public static int arrayPairSum(int[] nums) { 34 | Arrays.sort(nums); 35 | int result = 0; 36 | for (int i = 0; i < nums.length; i += 2) { 37 | result += nums[i]; 38 | } 39 | return result; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/旋转数组.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | // 【旋转数组】 4 | 5 | // 6 | // 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 7 | // 8 | // 示例 1: 9 | // 10 | // 输入: [1,2,3,4,5,6,7] 和 k = 3 11 | // 输出: [5,6,7,1,2,3,4] 12 | // 解释: 13 | // 向右旋转 1 步: [7,1,2,3,4,5,6] 14 | // 向右旋转 2 步: [6,7,1,2,3,4,5] 15 | // 向右旋转 3 步: [5,6,7,1,2,3,4] 16 | // 示例 2: 17 | // 18 | // 输入: [-1,-100,3,99] 和 k = 2 19 | // 输出: [3,99,-1,-100] 20 | // 解释: 21 | // 向右旋转 1 步: [99,-1,-100,3] 22 | // 向右旋转 2 步: [3,99,-1,-100] 23 | // 说明: 24 | // 25 | // 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 26 | // 要求使用空间复杂度为 O(1) 的原地算法。 27 | 28 | import org.junit.jupiter.api.Assertions; 29 | 30 | /** 31 | * @author Zhang Peng 32 | * @since 2018-11-05 33 | */ 34 | public class 旋转数组 { 35 | 36 | public static void main(String[] args) { 37 | int[] nums1 = { 1, 2, 3, 4, 5, 6, 7 }; 38 | int[] expected1 = { 5, 6, 7, 1, 2, 3, 4 }; 39 | 旋转数组.rotate(nums1, 3); 40 | Assertions.assertArrayEquals(expected1, nums1); 41 | 42 | int[] nums2 = { -1, -100, 3, 99 }; 43 | int[] expected2 = { 3, 99, -1, -100 }; 44 | 旋转数组.rotate(nums2, 2); 45 | Assertions.assertArrayEquals(expected2, nums2); 46 | } 47 | 48 | public static void rotate(int[] nums, int k) { 49 | int i = 0; 50 | while (i < k) { 51 | int j = nums.length - 1; 52 | int temp = nums[nums.length - 1]; 53 | while (j > 0) { 54 | nums[j] = nums[j - 1]; 55 | j--; 56 | } 57 | nums[0] = temp; 58 | // System.out.println(ArrayUtil.getArrayString(nums, 0, nums.length - 1)); 59 | i++; 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/旋转矩阵.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @since 2020-06-05 8 | */ 9 | public class 旋转矩阵 { 10 | 11 | public static void main(String[] args) { 12 | int[][] array = { 13 | { 1, 2, 3 }, 14 | { 4, 5, 6 }, 15 | { 7, 8, 9 } 16 | }; 17 | int[][] array2 = { 18 | { 7, 4, 1 }, 19 | { 8, 5, 2 }, 20 | { 9, 6, 3 } 21 | }; 22 | rotate(array); 23 | Assertions.assertArrayEquals(array2, array); 24 | } 25 | 26 | /** 27 | * @see 07. 旋转矩阵 28 | */ 29 | public static void rotate(int[][] matrix) { 30 | int row = matrix.length; 31 | int column = matrix[0].length; 32 | int[][] array = new int[row][column]; 33 | for (int i = 0; i < row; i++) { 34 | for (int j = 0; j < column; j++) { 35 | array[j][row - i - 1] = matrix[i][j]; 36 | } 37 | } 38 | for (int i = 0; i < row; i++) { 39 | for (int j = 0; j < column; j++) { 40 | matrix[i][j] = array[i][j]; 41 | } 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/最大连续1的个数.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | // 【最大连续1的个数】 4 | 5 | // 6 | // 给定一个二进制数组, 计算其中最大连续1的个数。 7 | // 8 | // 示例 1: 9 | // 10 | // 输入: [1,1,0,1,1,1] 11 | // 输出: 3 12 | // 解释: 开头的两位和最后的三位都是连续1,所以最大连续1的个数是 3. 13 | // 注意: 14 | // 15 | // 输入的数组只包含 0 和1。 16 | // 输入数组的长度是正整数,且不超过 10,000。 17 | 18 | import org.junit.jupiter.api.Assertions; 19 | 20 | /** 21 | * @author Zhang Peng 22 | * @since 2018-11-05 23 | */ 24 | public class 最大连续1的个数 { 25 | 26 | public static void main(String[] args) { 27 | Assertions.assertEquals(3, 最大连续1的个数.findMaxConsecutiveOnes(new int[] { 1, 1, 0, 1, 1, 1 })); 28 | } 29 | 30 | public static int findMaxConsecutiveOnes(int[] nums) { 31 | int max = 0; 32 | int count = 0; 33 | for (int i = 0; i < nums.length; i++) { 34 | if (nums[i] == 1) { 35 | count++; 36 | } else { 37 | if (count > max) { 38 | max = count; 39 | } 40 | count = 0; 41 | } 42 | } 43 | 44 | if (count > max) { 45 | max = count; 46 | } 47 | return max; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/有序矩阵中第K小的元素.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @date 2025-01-21 8 | */ 9 | public class 有序矩阵中第K小的元素 { 10 | 11 | public static void main(String[] args) { 12 | 13 | int[][] matrix = { { 1, 5, 9 }, { 10, 11, 13 }, { 12, 13, 15 } }; 14 | Assertions.assertEquals(13, kthSmallest(matrix, 8)); 15 | 16 | int[][] matrix2 = { { -5 } }; 17 | Assertions.assertEquals(-5, kthSmallest(matrix2, 1)); 18 | 19 | int[][] matrix3 = { { 1, 2 }, { 1, 3 } }; 20 | Assertions.assertEquals(1, kthSmallest(matrix3, 2)); 21 | 22 | int[][] matrix4 = { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } }; 23 | Assertions.assertEquals(3, kthSmallest(matrix4, 8)); 24 | } 25 | 26 | public static int kthSmallest(int[][] matrix, int n) { 27 | int row = matrix.length; 28 | if (row == 1) { 29 | return matrix[0][n - 1]; 30 | } 31 | int i = 1; 32 | int[] arr = matrix[0]; 33 | while (i < row) { 34 | arr = merge(matrix[i], arr); 35 | i++; 36 | } 37 | return arr[n - 1]; 38 | } 39 | 40 | public static int[] merge(int[] arr1, int[] arr2) { 41 | int i = 0, j = 0, k = 0; 42 | int[] merge = new int[arr1.length + arr2.length]; 43 | while (i < arr1.length && j < arr2.length) { 44 | if (arr1[i] <= arr2[j]) { 45 | merge[k++] = arr1[i++]; 46 | } else { 47 | merge[k++] = arr2[j++]; 48 | } 49 | } 50 | if (i < arr1.length) { 51 | while (i < arr1.length) { 52 | merge[k++] = arr1[i++]; 53 | } 54 | } 55 | if (j < arr2.length) { 56 | while (j < arr2.length) { 57 | merge[k++] = arr2[j++]; 58 | } 59 | } 60 | return merge; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/杨辉三角2.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import io.github.dunwu.algorithm.util.ArrayUtil; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | // 【杨辉三角 II】 10 | // 11 | // 给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。 12 | // 13 | // 在杨辉三角中,每个数是它左上方和右上方的数的和。 14 | // 15 | // 示例: 16 | // 17 | // 输入: 3 18 | // 输出: [1,3,3,1] 19 | // 进阶: 20 | // 21 | // 你可以优化你的算法到 O(k) 空间复杂度吗? 22 | 23 | /** 24 | * @author Zhang Peng 25 | * @since 2018-11-05 26 | */ 27 | public class 杨辉三角2 { 28 | 29 | public static void main(String[] args) { 30 | List list = 杨辉三角2.getRow(3); 31 | System.out.println(ArrayUtil.getArrayString(list.toArray(), 0, list.size() - 1)); 32 | } 33 | 34 | public static List getRow(int rowIndex) { 35 | List> result = new ArrayList<>(); 36 | 37 | int rows = rowIndex + 1; 38 | if (rows <= 0) { 39 | 40 | } else if (rows == 1) { 41 | result.add(Arrays.asList(1)); 42 | } else if (rows == 2) { 43 | result.add(Arrays.asList(1)); 44 | result.add(Arrays.asList(1, 1)); 45 | } else { 46 | result.add(Arrays.asList(1)); 47 | result.add(Arrays.asList(1, 1)); 48 | for (int i = 2; i < rows; i++) { 49 | List current = result.get(i - 1); 50 | List next = new ArrayList<>(); 51 | 52 | for (int j = 0; j <= i; j++) { 53 | if (j == 0 || j == i) { 54 | next.add(1); 55 | } else { 56 | int x = current.get(j - 1); 57 | int y = current.get(j); 58 | next.add(x + y); 59 | } 60 | } 61 | 62 | result.add(next); 63 | } 64 | } 65 | 66 | return result.get(rowIndex); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/查找总价格为目标值的两个商品.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * LCR 179. 查找总价格为目标值的两个商品 7 | * 8 | * @author Zhang Peng 9 | * @date 2025-01-13 10 | */ 11 | public class 查找总价格为目标值的两个商品 { 12 | 13 | public static void main(String[] args) { 14 | Assertions.assertArrayEquals(new int[] { 3, 15 }, twoSum(new int[] { 3, 9, 12, 15 }, 18)); 15 | Assertions.assertArrayEquals(new int[] { 27, 34 }, twoSum(new int[] { 8, 21, 27, 34, 52, 66 }, 61)); 16 | } 17 | 18 | /** 19 | * 时间复杂度:O(N) 20 | */ 21 | public static int[] twoSum(int[] price, int target) { 22 | int left = 0, right = price.length - 1; 23 | while (left < right) { 24 | int sum = price[left] + price[right]; 25 | if (sum == target) { 26 | return new int[] { price[left], price[right] }; 27 | } else if (sum < target) { 28 | left++; 29 | } else { 30 | right--; 31 | } 32 | } 33 | return new int[] { -1, -1 }; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/移除元素.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | // 【移除元素】 4 | 5 | // 6 | // 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。 7 | // 8 | // 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 9 | // 10 | // 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 11 | // 12 | // 示例 1: 13 | // 14 | // 给定 nums = [3,2,2,3], val = 3, 15 | // 16 | // 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 17 | // 18 | // 你不需要考虑数组中超出新长度后面的元素。 19 | // 示例 2: 20 | // 21 | // 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 22 | // 23 | // 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。 24 | // 25 | // 注意这五个元素可为任意顺序。 26 | // 27 | // 你不需要考虑数组中超出新长度后面的元素。 28 | // 说明: 29 | // 30 | // 为什么返回数值是整数,但输出的答案是数组呢? 31 | // 32 | // 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 33 | // 34 | // 你可以想象内部操作如下: 35 | // 36 | // // nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝 37 | // int len = removeElement(nums, val); 38 | // 39 | // // 在函数里修改输入数组对于调用者是可见的。 40 | // // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 41 | // for (int i = 0; i < len; i++) { 42 | // print(nums[i]); 43 | // } 44 | 45 | import org.junit.jupiter.api.Assertions; 46 | 47 | /** 48 | * @author Zhang Peng 49 | * @since 2018-11-05 50 | */ 51 | public class 移除元素 { 52 | 53 | public static void main(String[] args) { 54 | int[] nums1 = { 3, 2, 2, 3 }; 55 | Assertions.assertEquals(2, removeElement(nums1, 3)); 56 | 57 | int[] nums2 = { 0, 1, 2, 2, 3, 0, 4, 2 }; 58 | Assertions.assertEquals(5, removeElement(nums2, 2)); 59 | } 60 | 61 | public static int removeElement(int[] nums, int val) { 62 | if (nums.length == 0) { 63 | return 0; 64 | } 65 | int slow = 0, fast = 0; 66 | while (fast < nums.length) { 67 | if (nums[fast] != val) { 68 | nums[slow] = nums[fast]; 69 | slow++; 70 | } 71 | fast++; 72 | } 73 | return slow; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/至少是其他数字两倍的最大数.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | // 【至少是其他数字两倍的最大数】 6 | // 7 | // 在一个给定的数组nums中,总是存在一个最大元素 。 8 | // 9 | // 查找数组中的最大元素是否至少是数组中每个其他数字的两倍。 10 | // 11 | // 如果是,则返回最大元素的索引,否则返回-1。 12 | // 13 | // 示例 1: 14 | // 15 | // 输入: nums = [3, 6, 1, 0] 16 | // 输出: 1 17 | // 解释: 6是最大的整数, 对于数组中的其他整数, 18 | // 6大于数组中其他元素的两倍。6的索引是1, 所以我们返回1. 19 | // 20 | // 21 | // 示例 2: 22 | // 23 | // 输入: nums = [1, 2, 3, 4] 24 | // 输出: -1 25 | // 解释: 4没有超过3的两倍大, 所以我们返回 -1. 26 | // 27 | // 28 | // 提示: 29 | // 30 | // nums 的长度范围在[1, 50]. 31 | // 每个 nums[i] 的整数范围在 [0, 99]. 32 | 33 | /** 34 | * @author Zhang Peng 35 | * @since 2018-11-04 36 | */ 37 | public class 至少是其他数字两倍的最大数 { 38 | 39 | public static void main(String[] args) { 40 | int[] nums1 = { 3, 6, 1, 0 }; 41 | int[] nums2 = { 1, 2, 3, 4 }; 42 | 43 | Assertions.assertEquals(1, 至少是其他数字两倍的最大数.dominantIndex(nums1)); 44 | Assertions.assertEquals(-1, 至少是其他数字两倍的最大数.dominantIndex(nums2)); 45 | } 46 | 47 | public static int dominantIndex(int[] nums) { 48 | int index = 0; 49 | while (index < nums.length) { 50 | boolean isMatch = true; 51 | int max = nums[index]; 52 | for (int i = 0; i < nums.length; i++) { 53 | if (index != i && max < nums[i] * 2) { 54 | isMatch = false; 55 | break; 56 | } 57 | } 58 | if (isMatch) { 59 | return index; 60 | } else { 61 | index++; 62 | } 63 | } 64 | return -1; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/超级丑数.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * 313. 超级丑数 7 | * 8 | * @author Zhang Peng 9 | * @date 2025-01-24 10 | */ 11 | public class 超级丑数 { 12 | 13 | public static void main(String[] args) { 14 | Assertions.assertEquals(32, nthSuperUglyNumber(12, new int[] { 2, 7, 13, 19 })); 15 | Assertions.assertEquals(1, nthSuperUglyNumber(1, new int[] { 2, 3, 5 })); 16 | } 17 | 18 | public static int nthSuperUglyNumber(int n, int[] primes) { 19 | int len = primes.length; 20 | int[] offsets = new int[len]; 21 | long[] values = new long[len]; 22 | long[] ugly = new long[n + 1]; 23 | int u = 1; 24 | for (int i = 0; i < len; i++) { 25 | offsets[i] = 1; 26 | values[i] = 1; 27 | } 28 | while (u <= n) { 29 | long min = Integer.MAX_VALUE; 30 | for (int i = 0; i < len; i++) { 31 | min = Math.min(values[i], min); 32 | } 33 | ugly[u++] = min; 34 | 35 | for (int i = 0; i < len; i++) { 36 | if (values[i] == min) { 37 | values[i] = primes[i] * ugly[offsets[i]]; 38 | offsets[i] = offsets[i] + 1; 39 | } 40 | } 41 | } 42 | return (int) ugly[n]; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/长度最小的子数组.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.array; 2 | 3 | // 【长度最小的子数组】 4 | 5 | // 6 | // 给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。 7 | // 8 | // 示例: 9 | // 10 | // 输入: s = 7, nums = [2,3,1,2,4,3] 11 | // 输出: 2 12 | // 解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。 13 | // 进阶: 14 | // 15 | // 如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。 16 | 17 | /** 18 | * @author Zhang Peng 19 | * @since 2018-11-05 20 | */ 21 | public class 长度最小的子数组 { 22 | 23 | public static void main(String[] args) { 24 | 长度最小的子数组.minSubArrayLen(7, new int[] { 2, 3, 1, 2, 4, 3 }); 25 | 长度最小的子数组.minSubArrayLen(11, new int[] { 2, 3, 1, 2, 4, 3 }); 26 | } 27 | 28 | public static int minSubArrayLen(int s, int[] nums) { 29 | if (nums == null || nums.length == 0) { 30 | return 0; 31 | } 32 | 33 | int j = 0, i = 0, sum = 0, min = Integer.MAX_VALUE; 34 | 35 | while (i < nums.length) { 36 | sum += nums[i++]; 37 | 38 | while (sum >= s) { 39 | min = Math.min(min, i - j); 40 | sum -= nums[j++]; 41 | } 42 | } 43 | 44 | return min == Integer.MAX_VALUE ? 0 : min; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IList.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.common; 2 | 3 | /** 4 | * A list or sequence is an abstract data type that implements an ordered collection of values, where the same value may 5 | * occur more than once. 6 | *

7 | * 8 | * @author Justin Wetherell 9 | * @see List (Wikipedia)
10 | */ 11 | public interface IList { 12 | 13 | /** 14 | * Add value to list. 15 | * 16 | * @param value to add. 17 | * @return True if added. 18 | */ 19 | boolean add(T value); 20 | 21 | /** 22 | * Remove value from list. 23 | * 24 | * @param value to remove. 25 | * @return True if removed. 26 | */ 27 | boolean remove(T value); 28 | 29 | /** 30 | * Clear the entire list. 31 | */ 32 | void clear(); 33 | 34 | /** 35 | * Does the list contain value. 36 | * 37 | * @param value to search list for. 38 | * @return True if list contains value. 39 | */ 40 | boolean contains(T value); 41 | 42 | /** 43 | * Size of the list. 44 | * 45 | * @return size of the list. 46 | */ 47 | int size(); 48 | 49 | /** 50 | * Validate the list according to the invariants. 51 | * 52 | * @return True if the list is valid. 53 | */ 54 | boolean validate(); 55 | 56 | /** 57 | * Get this List as a Java compatible List 58 | * 59 | * @return Java compatible List 60 | */ 61 | java.util.List toList(); 62 | 63 | /** 64 | * Get this List as a Java compatible Collection 65 | * 66 | * @return Java compatible Collection 67 | */ 68 | java.util.Collection toCollection(); 69 | 70 | } 71 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IMap.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.common; 2 | 3 | /** 4 | * In computer science, an associative array, map, or dictionary is an abstract data type composed of a collection of 5 | * (key, value) pairs, such that each possible key appears at most once in the collection. 6 | *

7 | * 8 | * @author Justin Wetherell 9 | * @see Associative Array 10 | * (Wikipedia)
11 | */ 12 | public interface IMap { 13 | 14 | /** 15 | * Put key->value pair in the map. 16 | * 17 | * @param key to be inserted. 18 | * @param value to be inserted. 19 | * @return V previous value or null if none. 20 | */ 21 | V put(K key, V value); 22 | 23 | /** 24 | * Get value for key. 25 | * 26 | * @param key to get value for. 27 | * @return value mapped to key. 28 | */ 29 | V get(K key); 30 | 31 | /** 32 | * Remove key and value from map. 33 | * 34 | * @param key to remove from the map. 35 | * @return True if removed or False if not found. 36 | */ 37 | V remove(K key); 38 | 39 | /** 40 | * Clear the entire map. 41 | */ 42 | void clear(); 43 | 44 | /** 45 | * Does the map contain the key. 46 | * 47 | * @param key to locate in the map. 48 | * @return True if key is in the map. 49 | */ 50 | boolean contains(K key); 51 | 52 | /** 53 | * Number of key/value pairs in the hash map. 54 | * 55 | * @return number of key/value pairs. 56 | */ 57 | int size(); 58 | 59 | /** 60 | * Validate the map according to the invariants. 61 | * 62 | * @return True if the map is valid. 63 | */ 64 | boolean validate(); 65 | 66 | /** 67 | * Wraps this map in a Java compatible Map 68 | * 69 | * @return Java compatible Map 70 | */ 71 | java.util.Map toMap(); 72 | 73 | } 74 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/ISet.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.common; 2 | 3 | /** 4 | * In computer science, a set is an abstract data structure that can store certain values, without any particular order, 5 | * and no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most 6 | * other collection types, rather than retrieving a specific element from a set, one typically tests a value for 7 | * membership in a set. 8 | *

9 | * 10 | * @author Justin Wetherell 11 | * @see Set 12 | * (Wikipedia)
13 | */ 14 | public interface ISet { 15 | 16 | /** 17 | * Add value to set. 18 | * 19 | * @param value to add. 20 | * @return True if added. 21 | */ 22 | boolean add(T value); 23 | 24 | /** 25 | * Remove value from set. 26 | * 27 | * @param value to remove. 28 | * @return True if removed. 29 | */ 30 | boolean remove(T value); 31 | 32 | /** 33 | * Clear the entire set. 34 | */ 35 | void clear(); 36 | 37 | /** 38 | * Does the set contain value. 39 | * 40 | * @param value to search set for. 41 | * @return True if set contains value. 42 | */ 43 | boolean contains(T value); 44 | 45 | /** 46 | * Size of the set. 47 | * 48 | * @return size of the set. 49 | */ 50 | int size(); 51 | 52 | /** 53 | * Validate the set according to the invariants. 54 | * 55 | * @return True if the set is valid. 56 | */ 57 | boolean validate(); 58 | 59 | /** 60 | * Get this Set as a Java compatible Set 61 | * 62 | * @return Java compatible Set 63 | */ 64 | java.util.Set toSet(); 65 | 66 | /** 67 | * Get this Set as a Java compatible Collection 68 | * 69 | * @return Java compatible Collection 70 | */ 71 | java.util.Collection toCollection(); 72 | 73 | } 74 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/ISuffixTree.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.common; 2 | 3 | import java.util.Set; 4 | 5 | /** 6 | * In computer science, a suffix tree (also called PAT tree or, in an earlier form, position tree) is a compressed trie 7 | * containing all the suffixes of the given text as their keys and positions in the text as their values. Suffix trees 8 | * allow particularly fast implementations of many important string operations. 9 | *

10 | * 11 | * @author Justin Wetherell 12 | * @see Suffix Tree (Wikipedia) 13 | *
14 | */ 15 | public interface ISuffixTree { 16 | 17 | /** 18 | * Does the sub-sequence exist in the suffix tree. 19 | * 20 | * @param sub-sequence to locate in the tree. 21 | * @return True if the sub-sequence exist in the tree. 22 | */ 23 | boolean doesSubStringExist(C sub); 24 | 25 | /** 26 | * Get all the suffixes in the tree. 27 | * 28 | * @return set of suffixes in the tree. 29 | */ 30 | Set getSuffixes(); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/ITree.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.common; 2 | 3 | /** 4 | * A tree can be defined recursively (locally) as a collection of nodes (starting at a root node), where each node is a 5 | * data structure consisting of a value, together with a list of nodes (the "children"), with the constraints that no 6 | * node is duplicated. A tree can be defined abstractly as a whole (globally) as an ordered tree, with a value assigned 7 | * to each node. 8 | *

9 | * 10 | * @author Justin Wetherell 11 | * @see Tree (Wikipedia) 12 | *
13 | */ 14 | public interface ITree { 15 | 16 | /** 17 | * Add value to the tree. Tree can contain multiple equal values. 18 | * 19 | * @param value to add to the tree. 20 | * @return True if successfully added to tree. 21 | */ 22 | boolean add(T value); 23 | 24 | /** 25 | * Remove first occurrence of value in the tree. 26 | * 27 | * @param value to remove from the tree. 28 | * @return T value removed from tree. 29 | */ 30 | T remove(T value); 31 | 32 | /** 33 | * Clear the entire stack. 34 | */ 35 | void clear(); 36 | 37 | /** 38 | * Does the tree contain the value. 39 | * 40 | * @param value to locate in the tree. 41 | * @return True if tree contains value. 42 | */ 43 | boolean contains(T value); 44 | 45 | /** 46 | * Get number of nodes in the tree. 47 | * 48 | * @return Number of nodes in the tree. 49 | */ 50 | int size(); 51 | 52 | /** 53 | * Validate the tree according to the invariants. 54 | * 55 | * @return True if the tree is valid. 56 | */ 57 | boolean validate(); 58 | 59 | /** 60 | * Get Tree as a Java compatible Collection 61 | * 62 | * @return Java compatible Collection 63 | */ 64 | java.util.Collection toCollection(); 65 | 66 | } 67 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/divide/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 分治算法 3 | * 4 | * @author Zhang Peng 5 | * @since 2020-07-02 6 | */ 7 | package io.github.dunwu.algorithm.divide; 8 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/divide/多数元素.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.divide; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * 多数元素 9 | * 10 | * @author Zhang Peng 11 | * @see 多数元素 12 | * @since 2020-07-02 13 | */ 14 | public class 多数元素 { 15 | 16 | public static void main(String[] args) { 17 | Assertions.assertEquals(3, majorityElement(new int[] { 3, 2, 3 })); 18 | Assertions.assertEquals(2, majorityElement(new int[] { 2, 2, 1, 1, 1, 2, 2 })); 19 | Assertions.assertEquals(6, majorityElement(new int[] { 6, 6, 6, 7, 7 })); 20 | } 21 | 22 | // 暴力破解法 23 | // 时间复杂度:O(N) + O(log N) 24 | public static int majorityElement(int[] nums) { 25 | Arrays.sort(nums); 26 | int max = 1; 27 | int count = 0; 28 | int currElem = nums[0]; 29 | int maxElem = nums[0]; 30 | for (int i = 0; i < nums.length; i++) { 31 | if (nums[i] != currElem) { 32 | count = 1; 33 | currElem = nums[i]; 34 | } else { 35 | count++; 36 | if (maxElem == currElem) { 37 | max = count; 38 | } else { 39 | if (max < count) { 40 | maxElem = currElem; 41 | } 42 | } 43 | } 44 | } 45 | return maxElem; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/MaxSubArray.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.dynamic; 2 | 3 | import cn.hutool.core.util.ArrayUtil; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | /** 8 | * @author Zhang Peng 9 | * @since 2020-03-06 10 | */ 11 | public class MaxSubArray { 12 | 13 | private static final Logger log = LoggerFactory.getLogger(MaxSubArray.class); 14 | 15 | public static int maxSubArray(int[] nums) { 16 | int[] result = new int[nums.length]; 17 | result[0] = nums[0]; 18 | int max = nums[0]; 19 | for (int i = 1; i < nums.length; i++) { 20 | result[i] = Math.max(result[i - 1] + nums[i], nums[i]); 21 | if (max < result[i]) { 22 | max = result[i]; 23 | } 24 | 25 | if (log.isDebugEnabled()) { 26 | log.debug(ArrayUtil.toString(result)); 27 | } 28 | } 29 | return max; 30 | } 31 | 32 | public static void main(String[] args) { 33 | int[] array = new int[] { -2, 1, -3, 4, -1, 2, 1, -5, 4 }; 34 | int max = MaxSubArray.maxSubArray(array); 35 | System.out.println("max = " + max); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 动态规划算法 3 | * 4 | * @author Zhang Peng 5 | * @since 2020-03-06 6 | */ 7 | package io.github.dunwu.algorithm.dynamic; 8 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/乘积最大子数组.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.dynamic; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @since 2020-07-05 8 | */ 9 | public class 乘积最大子数组 { 10 | 11 | public static void main(String[] args) { 12 | int[] nums = { 2, 3, -2, 4 }; 13 | int[] nums2 = { -2, 0, -1 }; 14 | // Assertions.assertEquals(6, maxProduct(nums)); 15 | Assertions.assertEquals(6, maxProduct2(nums)); 16 | Assertions.assertEquals(0, maxProduct2(nums2)); 17 | } 18 | 19 | public static int maxProduct(int[] nums) { 20 | return backtrack(nums, 0, 0, 1, 0); 21 | } 22 | 23 | // 递归 + 回溯 暴力破解 24 | // 时间复杂度 O(2^N) 25 | public static int backtrack(int[] nums, int begin, int end, int res, int max) { 26 | if (end >= nums.length || begin > end) return max; 27 | res *= nums[end]; 28 | if (res > max) { 29 | return backtrack(nums, begin, end + 1, res, res); 30 | } else { 31 | return backtrack(nums, end + 1, end + 1, 1, max); 32 | } 33 | } 34 | 35 | public static int maxProduct2(int[] nums) { 36 | int min = nums[0]; 37 | int max = nums[0]; 38 | int res = nums[0]; 39 | for (int i = 1; i < nums.length; i++) { 40 | int currMax = Math.max(Math.max(nums[i] * max, nums[i] * min), nums[i]); 41 | int currMin = Math.min(Math.min(nums[i] * max, nums[i] * min), nums[i]); 42 | res = Math.max(currMax, res); 43 | max = currMax; 44 | min = currMin; 45 | } 46 | return res; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/买卖股票的最佳时机.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.dynamic; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @see 121. 买卖股票的最佳时机 8 | * @since 2020-07-05 9 | */ 10 | public class 买卖股票的最佳时机 { 11 | 12 | public static void main(String[] args) { 13 | int[] prices = { 7, 1, 5, 3, 6, 4 }; 14 | int[] prices2 = { 7, 6, 4, 3, 1 }; 15 | Assertions.assertEquals(5, maxProfit(prices)); 16 | Assertions.assertEquals(0, maxProfit(prices2)); 17 | } 18 | 19 | public static int maxProfit(int[] prices) { 20 | if (prices == null || prices.length == 0) return 0; 21 | int n = prices.length; 22 | int max = 0; 23 | 24 | // 定义二维数组 25 | // 一维表示第 i 天 26 | // 二维表示交易状态:0 表示没有买卖;1 表示买入;2 表示卖出 27 | int[][] mp = new int[n][3]; 28 | mp[0][0] = 0; // 无 29 | mp[0][1] = -prices[0]; // 买 30 | mp[0][2] = 0; // 当天买进卖出,净赚0 31 | for (int i = 1; i < n; i++) { 32 | mp[i][0] = mp[i - 1][0]; // 一直不买 33 | mp[i][1] = Math.max(mp[i - 1][1], mp[i - 1][0] - prices[i]); // 昨天买或今天买 34 | mp[i][2] = mp[i - 1][1] + prices[i]; // 昨天还有股,今天卖出 35 | for (int j = 0; j <= 2; j++) { 36 | if (max < mp[i][j]) { 37 | max = mp[i][j]; 38 | } 39 | } 40 | } 41 | return max; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/买卖股票的最佳时机II.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.dynamic; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @see 122. 买卖股票的最佳时机 II 8 | * @since 2020-07-05 9 | */ 10 | public class 买卖股票的最佳时机II { 11 | 12 | public static void main(String[] args) { 13 | int[] prices = { 7, 1, 5, 3, 6, 4 }; 14 | int[] prices2 = { 1, 2, 3, 4, 5 }; 15 | Assertions.assertEquals(7, maxProfit(prices)); 16 | Assertions.assertEquals(4, maxProfit(prices2)); 17 | } 18 | 19 | public static int maxProfit(int[] prices) { 20 | if (prices == null || prices.length == 0) return 0; 21 | 22 | int max = 0; 23 | final int days = prices.length; 24 | final int[][] dp = new int[days][2]; 25 | 26 | dp[0][0] = 0; 27 | dp[0][1] = -prices[0]; 28 | 29 | for (int i = 1; i < days; i++) { 30 | dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]); 31 | dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); 32 | max = Math.max(dp[i][0], dp[i][1]); 33 | } 34 | return max; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/买卖股票的最佳时机III.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.dynamic; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @see 123. 买卖股票的最佳时机 III 8 | * @since 2020-07-05 9 | */ 10 | public class 买卖股票的最佳时机III { 11 | 12 | public static void main(String[] args) { 13 | int[] prices = { 3, 3, 5, 0, 0, 3, 1, 4 }; 14 | int[] prices2 = { 1, 2, 3, 4, 5 }; 15 | Assertions.assertEquals(6, maxProfit(prices)); 16 | Assertions.assertEquals(4, maxProfit(prices2)); 17 | } 18 | 19 | public static int maxProfit(int[] prices) { 20 | if (prices == null || prices.length == 0) return 0; 21 | final int days = prices.length; 22 | final int deal = 2; // 交易笔数 23 | 24 | // 定义二维数组 25 | // 一维表示第 i 天 26 | // 二维表示交易笔数,最多 2 笔 27 | // 三维表示是否持有股票:0/1(持有) 28 | int[][][] dp = new int[days][deal + 1][2]; 29 | 30 | // 第一天数据初始化 31 | for (int k = 0; k <= deal; k++) { 32 | dp[0][k][0] = 0; 33 | dp[0][k][1] = -prices[0]; 34 | } 35 | 36 | for (int i = 1; i < days; i++) { // 扫描天数 37 | for (int k = deal; k >= 1; k--) { 38 | dp[i][k][0] = Math.max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i]); 39 | dp[i][k][1] = Math.max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i]); 40 | } 41 | } 42 | 43 | return dp[days - 1][deal][0]; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/买卖股票的最佳时机含手续费.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.dynamic; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @see 714. 8 | * 买卖股票的最佳时机含手续费 9 | * @since 2020-07-05 10 | */ 11 | public class 买卖股票的最佳时机含手续费 { 12 | 13 | public static void main(String[] args) { 14 | int[] prices = { 1, 3, 2, 8, 4, 9 }; 15 | Assertions.assertEquals(8, maxProfit(prices, 2)); 16 | } 17 | 18 | public static int maxProfit(int[] prices, int fee) { 19 | if (prices == null || prices.length == 0) return 0; 20 | 21 | int max = 0; 22 | final int days = prices.length; 23 | final int[][] dp = new int[days][2]; 24 | 25 | dp[0][0] = 0; 26 | dp[0][1] = -prices[0]; 27 | 28 | for (int i = 1; i < days; i++) { 29 | dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee); 30 | dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); 31 | max = Math.max(dp[i][0], dp[i][1]); 32 | } 33 | return max; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/判断子序列.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.dynamic; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @see 392. 判断子序列 8 | * @since 2020-07-06 9 | */ 10 | public class 判断子序列 { 11 | 12 | public static void main(String[] args) { 13 | Assertions.assertTrue(isSubsequence("abc", "ahbgdc")); 14 | Assertions.assertFalse(isSubsequence("axc", "ahbgdc")); 15 | Assertions.assertTrue(isSubsequence("", "ahbgdc")); 16 | Assertions.assertFalse(isSubsequence("aaaaaa", "bbaaaa")); 17 | } 18 | 19 | public static boolean isSubsequence(String s, String t) { 20 | if (s == null || s.length() == 0) return true; 21 | if (s.length() > t.length()) return false; 22 | char[] source = s.toCharArray(); 23 | char[] target = t.toCharArray(); 24 | int i = 0, j = 0; 25 | while (i < source.length && j < target.length) { 26 | if (target[j] != source[i]) { 27 | j++; 28 | } else { 29 | if (i == source.length - 1) { 30 | return true; 31 | } 32 | i++; 33 | j++; 34 | } 35 | } 36 | return false; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/最佳买卖股票时机含冷冻期.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.dynamic; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @see 309. 最佳买卖股票时机含冷冻期 8 | * @since 2020-07-05 9 | */ 10 | public class 最佳买卖股票时机含冷冻期 { 11 | 12 | public static void main(String[] args) { 13 | int[] prices = { 1, 2, 3, 0, 2 }; 14 | Assertions.assertEquals(3, maxProfit(prices)); 15 | } 16 | 17 | public static int maxProfit(int[] prices) { 18 | if (prices == null || prices.length == 0) return 0; 19 | 20 | int max = 0; 21 | final int days = prices.length; 22 | final int[][][] dp = new int[days][2][2]; 23 | 24 | dp[0][0][0] = 0; 25 | dp[0][0][1] = 0; 26 | dp[0][1][0] = -prices[0]; 27 | 28 | for (int i = 1; i < days; i++) { 29 | dp[i][0][0] = Math.max(dp[i - 1][0][0], dp[i - 1][0][1]); 30 | dp[i][0][1] = dp[i - 1][1][0] + prices[i]; 31 | dp[i][1][0] = Math.max(dp[i - 1][0][0] - prices[i], dp[i - 1][1][0]); 32 | 33 | int temp1 = Math.max(dp[i][0][0], dp[i][0][1]); 34 | int temp2 = Math.max(dp[i][1][0], temp1); 35 | max = Math.max(max, temp2); 36 | } 37 | return max; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/最大子序和.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.dynamic; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @see 53. 最大子序和 8 | * @since 2020-07-06 9 | */ 10 | public class 最大子序和 { 11 | 12 | public static void main(String[] args) { 13 | int[] nums = { -2, 1, -3, 4, -1, 2, 1, -5, 4 }; 14 | Assertions.assertEquals(6, maxSubArray(nums)); 15 | Assertions.assertEquals(-1, maxSubArray(new int[] { -1 })); 16 | } 17 | 18 | public static int maxSubArray(int[] nums) { 19 | if (nums == null || nums.length == 0) return 0; 20 | 21 | int[] dp = new int[nums.length + 1]; 22 | dp[0] = nums[0]; 23 | int max = dp[0]; 24 | for (int i = 1; i < nums.length; i++) { 25 | dp[i] = dp[i - 1] >= 0 ? dp[i - 1] + nums[i] : nums[i]; 26 | } 27 | 28 | for (int i = 0; i < nums.length; i++) { 29 | if (max < dp[i]) { 30 | max = dp[i]; 31 | } 32 | } 33 | return max; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/最长上升子序列.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.dynamic; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @see 300. 最长上升子序列 8 | * @since 2020-07-06 9 | */ 10 | public class 最长上升子序列 { 11 | 12 | public static void main(String[] args) { 13 | int[] nums = { 10, 9, 2, 5, 3, 7, 101, 18 }; 14 | Assertions.assertEquals(4, lengthOfLIS(nums)); 15 | Assertions.assertEquals(1, lengthOfLIS(new int[] { 0 })); 16 | } 17 | 18 | public static int lengthOfLIS(int[] nums) { 19 | if (nums == null || nums.length == 0) return 0; 20 | int max = 1; 21 | final int[] dp = new int[nums.length + 1]; 22 | for (int i = 0; i < nums.length; i++) dp[i] = 1; 23 | for (int i = 1; i < nums.length; i++) { 24 | for (int j = 0; j < i; j++) { 25 | if (nums[j] < nums[i]) { 26 | dp[i] = Math.max(dp[i], dp[j] + 1); 27 | } 28 | } 29 | max = Math.max(max, dp[i]); 30 | } 31 | return max; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/编辑距离.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.dynamic; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @see 72. 编辑距离 8 | * @since 2020-07-06 9 | */ 10 | public class 编辑距离 { 11 | 12 | public static void main(String[] args) { 13 | Assertions.assertEquals(3, minDistance("horse", "ros")); 14 | Assertions.assertEquals(5, minDistance("intention", "execution")); 15 | } 16 | 17 | public static int minDistance(String word1, String word2) { 18 | int m = word1.length(); 19 | int n = word2.length(); 20 | int[][] dp = new int[m + 1][n + 1]; 21 | for (int i = 0; i < m + 1; i++) dp[i][0] = i; 22 | for (int j = 0; j < n + 1; j++) dp[0][j] = j; 23 | 24 | for (int i = 1; i < m + 1; i++) { 25 | for (int j = 1; j < n + 1; j++) { 26 | if (word1.charAt(i - 1) == word2.charAt(j - 1)) { 27 | dp[i][j] = dp[i - 1][j - 1]; 28 | } else { 29 | int m1 = Math.min(dp[i - 1][j], dp[i][j - 1]); 30 | int m2 = Math.min(m1, dp[i - 1][j - 1]); 31 | dp[i][j] = 1 + m2; 32 | } 33 | } 34 | } 35 | return dp[m][n]; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/dynamic/零钱兑换.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.dynamic; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @see 322. 零钱兑换 8 | * @since 2020-07-06 9 | */ 10 | public class 零钱兑换 { 11 | 12 | public static void main(String[] args) { 13 | int[] nums = { 1, 2, 5 }; 14 | Assertions.assertEquals(3, coinChange(nums, 11)); 15 | Assertions.assertEquals(-1, coinChange(new int[] { 2 }, 3)); 16 | } 17 | 18 | 19 | public static int coinChange(int[] coins, int amount) { 20 | return coinChange(coins, amount, 0); 21 | } 22 | 23 | public static int coinChange(int[] coins, int amount, int idxCoin) { 24 | if (amount == 0) { return 0; } 25 | if (idxCoin < coins.length && amount > 0) { 26 | int maxVal = amount / coins[idxCoin]; 27 | int minCost = Integer.MAX_VALUE; 28 | for (int x = 0; x <= maxVal; x++) { 29 | if (amount >= x * coins[idxCoin]) { 30 | int res = coinChange(coins, amount - x * coins[idxCoin], idxCoin + 1); 31 | if (res != -1) { minCost = Math.min(minCost, res + x); } 32 | } 33 | } 34 | return (minCost == Integer.MAX_VALUE) ? -1 : minCost; 35 | } 36 | return -1; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/hashtable/JewelsAndStones.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.hashtable; 2 | 3 | import java.util.HashSet; 4 | 5 | /* 6 | https://leetcode.com/problems/jewels-and-stones/ 7 | 8 | You're given strings J representing the types of stones that are jewels, and S representing the stones you have. 9 | Each character in S is a type of stone you have. You want to know how many of the stones you have are also jewels. 10 | 11 | The letters in J are guaranteed distinct, and all characters in J and S are letters. 12 | Letters are case sensitive, so "a" is considered a different type of stone from "A". 13 | 14 | Example 1: 15 | 16 | Input: J = "aA", S = "aAAbbbb" 17 | Output: 3 18 | Example 2: 19 | 20 | Input: J = "z", S = "ZZ" 21 | Output: 0 22 | Note: 23 | 24 | S and J will consist of letters and have length at most 50. 25 | The characters in J are distinct. 26 | */ 27 | public class JewelsAndStones { 28 | 29 | public static void main(String[] args) { 30 | JewelsAndStones tmpl = new JewelsAndStones(); 31 | 32 | int result1 = tmpl.numJewelsInStones("aA", "aAAbbbb"); 33 | System.out.println("result1 = [" + result1 + "]"); 34 | 35 | int result2 = tmpl.numJewelsInStones("z", "ZZ"); 36 | System.out.println("result1 = [" + result2 + "]"); 37 | } 38 | 39 | public int numJewelsInStones(String J, String S) { 40 | HashSet set = new HashSet(); 41 | for (int i = 0; i < J.length(); i++) { 42 | set.add(J.charAt(i)); 43 | } 44 | 45 | int count = 0; 46 | for (int i = 0; i < S.length(); i++) { 47 | if (set.contains(S.charAt(i))) { 48 | count++; 49 | } 50 | } 51 | return count; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/hashtable/ToLowerCase.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.hashtable; 2 | 3 | /* 4 | https://leetcode.com/problems/to-lower-case/ 5 | 6 | Implement function ToLowerCase() that has a string parameter str, and returns the same string in lowercase. 7 | 8 | 9 | 10 | Example 1: 11 | 12 | Input: "Hello" 13 | Output: "hello" 14 | Example 2: 15 | 16 | Input: "here" 17 | Output: "here" 18 | Example 3: 19 | 20 | Input: "LOVELY" 21 | Output: "lovely" 22 | 23 | */ 24 | public class ToLowerCase { 25 | 26 | public static void main(String[] args) { 27 | ToLowerCase tmpl = new ToLowerCase(); 28 | String result = tmpl.toLowerCase("Hello"); 29 | System.out.println("result = [" + result + "]"); 30 | } 31 | 32 | public String toLowerCase(String str) { 33 | StringBuilder sb = new StringBuilder(); 34 | for (int i = 0; i < str.length(); i++) { 35 | if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') { 36 | sb.append((char) (str.charAt(i) + 32)); 37 | } else { 38 | sb.append(str.charAt(i)); 39 | } 40 | } 41 | return sb.toString(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/heap/KthLargest.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.heap; 2 | 3 | import java.util.PriorityQueue; 4 | 5 | // 703. 数据流中的第K大元素 6 | // 7 | // 设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。 8 | // 9 | // 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中的初始元素。每次调用 KthLargest.add,返回当前数据流中第K大的元素。 10 | // 11 | // 示例: 12 | // 13 | // int k = 3; 14 | // int[] arr = [4,5,8,2]; 15 | // KthLargest kthLargest = new KthLargest(3, arr); 16 | // kthLargest.add(3);   // returns 4 17 | // kthLargest.add(5);   // returns 5 18 | // kthLargest.add(10);  // returns 5 19 | // kthLargest.add(9);   // returns 8 20 | // kthLargest.add(4);   // returns 8 21 | // 说明: 22 | // 你可以假设 nums 的长度≥ k-1 且k ≥ 1。 23 | 24 | public class KthLargest> { 25 | 26 | private int size; 27 | 28 | private PriorityQueue queue; 29 | 30 | public KthLargest(int k, T[] nums) { 31 | size = k; 32 | queue = new PriorityQueue<>(k); 33 | for (T num : nums) { 34 | add(num); 35 | } 36 | } 37 | 38 | public T add(T val) { 39 | if (queue.size() < size) { 40 | queue.add(val); 41 | } else if (queue.peek().compareTo(val) < 0) { 42 | queue.poll(); 43 | queue.add(val); 44 | } 45 | return queue.peek(); 46 | } 47 | 48 | public static void main(String[] args) { 49 | Integer[] data = new Integer[] { 4, 5, 8, 2 }; 50 | KthLargest demo = new KthLargest<>(3, data); 51 | System.out.println("args = " + demo.add(3)); 52 | System.out.println("args = " + demo.add(5)); 53 | System.out.println("args = " + demo.add(10)); 54 | System.out.println("args = " + demo.add(9)); 55 | System.out.println("args = " + demo.add(4)); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/heap/KthLeast.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.heap; 2 | 3 | import java.util.PriorityQueue; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @since 2020-03-06 8 | */ 9 | public class KthLeast> { 10 | 11 | private int size; 12 | 13 | private PriorityQueue queue; 14 | 15 | public KthLeast(int k, T[] array) { 16 | this.size = k; 17 | queue = new PriorityQueue<>(k); 18 | for (T v : array) { 19 | add(v); 20 | } 21 | } 22 | 23 | public T add(T val) { 24 | if (queue.size() < size) { 25 | queue.add(val); 26 | } else if (queue.peek().compareTo(val) > 0) { 27 | queue.poll(); 28 | queue.add(val); 29 | } 30 | return queue.peek(); 31 | } 32 | 33 | public T pop() { 34 | return queue.poll(); 35 | } 36 | 37 | public static void main(String[] args) { 38 | Integer[] data = new Integer[] { 3, 2, 1 }; 39 | KthLeast demo = new KthLeast<>(2, data); 40 | System.out.println("args = " + demo.pop()); 41 | System.out.println("args = " + demo.pop()); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/heap/LeastKNum.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.heap; 2 | 3 | /** 4 | * 面试题40. 最小的k个数 5 | *

6 | * 输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。 7 | *

8 | *   9 | *

10 | * 示例 1: 11 | *

12 | * 输入:arr = [3,2,1], k = 2 输出:[1,2] 或者 [2,1] 示例 2: 13 | *

14 | * 输入:arr = [0,1,2,1], k = 1 输出:[0]   15 | *

16 | * 限制: 17 | *

18 | * 0 <= k <= arr.length <= 10000 0 <= arr[i] <= 10000 19 | * 20 | * @author Zhang Peng 21 | * @since 2020-03-06 22 | */ 23 | public class LeastKNum { 24 | 25 | // public int[] getLeastNumbers(int[] arr, int k) { 26 | // 27 | // } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListNode.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.list; 2 | 3 | import java.util.Objects; 4 | 5 | public final class ListNode { 6 | 7 | int val; 8 | ListNode next; 9 | 10 | ListNode(int val) { this.val = val; } 11 | 12 | @Override 13 | public boolean equals(Object o) { 14 | if (this == o) return true; 15 | if (!(o instanceof ListNode)) return false; 16 | ListNode listNode = (ListNode) o; 17 | return val == listNode.val && 18 | Objects.equals(next, listNode.next); 19 | } 20 | 21 | @Override 22 | public int hashCode() { 23 | return Objects.hash(val, next); 24 | } 25 | 26 | public static ListNode createLinkedList(int[] arr) { 27 | if (arr == null || arr.length == 0) { 28 | return null; 29 | } 30 | ListNode head = new ListNode(arr[0]); 31 | ListNode cur = head; 32 | for (int i = 1; i < arr.length; i++) { 33 | cur.next = new ListNode(arr[i]); 34 | cur = cur.next; 35 | } 36 | return head; 37 | } 38 | 39 | public static void addLast() { 40 | 41 | } 42 | 43 | public static void main(String[] args) { 44 | int[] arr = { 1, 2, 3, 4, 5 }; 45 | ListNode head = createLinkedList(arr); 46 | ListNode p = head; 47 | while (p.next != null) { 48 | p = p.next; 49 | } 50 | p.next = new ListNode(6); 51 | while (head != null) { 52 | System.out.println(head.val); 53 | head = head.next; 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/ListUtil.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.list; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @author Zhang Peng 8 | * @since 2020-06-09 9 | */ 10 | public class ListUtil { 11 | 12 | private ListUtil() { } 13 | 14 | public static ListNode buildList(int... list) { 15 | ListNode head = new ListNode(-1); 16 | ListNode node = head; 17 | for (int val : list) { 18 | node.next = new ListNode(val); 19 | node = node.next; 20 | } 21 | return head.next; 22 | } 23 | 24 | public static List toList(ListNode result) { 25 | List list = new ArrayList<>(); 26 | while (result != null) { 27 | list.add(result.val); 28 | result = result.next; 29 | } 30 | return list; 31 | } 32 | 33 | public static List getValues(ListNode listNode) { 34 | List list = new ArrayList<>(); 35 | ListNode item = listNode; 36 | while (item != null) { 37 | list.add(item.val); 38 | item = item.next; 39 | } 40 | return list; 41 | } 42 | 43 | public static ListNode buildCycleList(int pos, int[] list) { 44 | ListNode head = new ListNode(-1); 45 | ListNode node = head; 46 | ListNode cycleBeginNode = null; 47 | for (int val : list) { 48 | ListNode item = new ListNode(val); 49 | if (pos == 0 && cycleBeginNode == null) { 50 | cycleBeginNode = item; 51 | } else { 52 | pos--; 53 | } 54 | node.next = item; 55 | node = node.next; 56 | } 57 | if (cycleBeginNode != null) { 58 | node.next = cycleBeginNode; 59 | } 60 | return head.next; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/两数相加II.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.list; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * LCR 025. 两数相加II 9 | * 10 | * @author Zhang Peng 11 | * @date 2025-01-21 12 | */ 13 | public class 两数相加II { 14 | 15 | public static void main(String[] args) { 16 | ListNode result = addTwoNumbers(ListUtil.buildList(7, 2, 4, 3), ListUtil.buildList(5, 6, 4)); 17 | List list = ListUtil.toList(result); 18 | System.out.println(list); 19 | Assertions.assertArrayEquals(new Integer[] { 7, 8, 0, 7 }, list.toArray()); 20 | 21 | ListNode result2 = addTwoNumbers(ListUtil.buildList(2, 4, 3), ListUtil.buildList(5, 6, 4)); 22 | List list2 = ListUtil.toList(result2); 23 | System.out.println(list2); 24 | Assertions.assertArrayEquals(new Integer[] { 8, 0, 7 }, list2.toArray()); 25 | 26 | ListNode result3 = addTwoNumbers(ListUtil.buildList(0), ListUtil.buildList(0)); 27 | List list3 = ListUtil.toList(result3); 28 | System.out.println(list3); 29 | Assertions.assertArrayEquals(new Integer[] { 0 }, list3.toArray()); 30 | } 31 | 32 | public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { 33 | // 将两个链表倒置,方便先从低位到高位,逐次相加 34 | ListNode r1 = reverse(l1); 35 | ListNode r2 = reverse(l2); 36 | ListNode result = 两数相加.addTwoNumbers(r1, r2); 37 | return reverse(result); 38 | } 39 | 40 | public static ListNode reverse(ListNode head) { 41 | ListNode pre = null, cur = head; 42 | while (cur != null) { 43 | ListNode next = cur.next; 44 | cur.next = pre; 45 | pre = cur; 46 | cur = next; 47 | } 48 | return pre; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/分隔链表.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.list; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author Zhang Peng 9 | * @see 86. 分隔链表 10 | * @since 2020-07-06 11 | */ 12 | public class 分隔链表 { 13 | 14 | public static void main(String[] args) { 15 | ListNode head = ListUtil.buildList(1, 4, 3, 2, 5, 2); 16 | ListNode result = partition(head, 3); 17 | List list = ListUtil.toList(result); 18 | Assertions.assertArrayEquals(new Integer[] { 1, 2, 2, 4, 3, 5 }, list.toArray(new Integer[0])); 19 | 20 | ListNode head2 = ListUtil.buildList(2, 1); 21 | ListNode result2 = partition(head2, 2); 22 | List list2 = ListUtil.toList(result2); 23 | Assertions.assertArrayEquals(new Integer[] { 1, 2 }, list2.toArray(new Integer[0])); 24 | 25 | ListNode head3 = ListUtil.buildList(3, 1, 2); 26 | ListNode result3 = partition(head3, 3); 27 | List list3 = ListUtil.toList(result3); 28 | Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, list3.toArray(new Integer[0])); 29 | } 30 | 31 | public static ListNode partition(ListNode head, int x) { 32 | ListNode dummy1 = new ListNode(-1); 33 | ListNode dummy2 = new ListNode(-1); 34 | ListNode d1 = dummy1; 35 | ListNode d2 = dummy2; 36 | ListNode p = head; 37 | while (p != null) { 38 | if (p.val < x) { 39 | d1.next = p; 40 | d1 = d1.next; 41 | } else { 42 | d2.next = p; 43 | d2 = d2.next; 44 | } 45 | ListNode temp = p.next; 46 | p.next = null; 47 | p = temp; 48 | } 49 | d1.next = dummy2.next; 50 | d2.next = null; 51 | return dummy1.next; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/删除排序链表中的重复元素.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.list; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 83. 删除排序链表中的重复元素 9 | * 10 | * @author Zhang Peng 11 | * @since 2020-06-09 12 | */ 13 | public class 删除排序链表中的重复元素 { 14 | 15 | public static void main(String[] args) { 16 | ListNode head = ListUtil.buildList(1, 1, 2); 17 | System.out.println(ListUtil.toList(head)); 18 | ListNode result = deleteDuplicates(head); 19 | List list = ListUtil.toList(result); 20 | System.out.println(list); 21 | Assertions.assertArrayEquals(new Integer[] { 1, 2 }, list.toArray(new Integer[0])); 22 | 23 | ListNode head2 = ListUtil.buildList(1, 1, 2, 3, 3); 24 | System.out.println(ListUtil.toList(head2)); 25 | ListNode result2 = deleteDuplicates(head2); 26 | List list2 = ListUtil.toList(result2); 27 | System.out.println(list2); 28 | Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, list2.toArray(new Integer[0])); 29 | } 30 | 31 | public static ListNode deleteDuplicates(ListNode head) { 32 | if (head == null || head.next == null) { 33 | return head; 34 | } 35 | ListNode slow = head, fast = head.next; 36 | while (fast != null) { 37 | if (slow.val == fast.val) { 38 | slow.next = fast.next; 39 | } else { 40 | slow = slow.next; 41 | } 42 | fast = fast.next; 43 | } 44 | return head; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/删除链表的倒数第N个结点.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.list; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 19. 删除链表的倒数第 N 个结点 9 | * 10 | * @author Zhang Peng 11 | * @since 2020-06-09 12 | */ 13 | public class 删除链表的倒数第N个结点 { 14 | 15 | public static void main(String[] args) { 16 | ListNode head1 = ListUtil.buildList(1, 2, 3, 4, 5); 17 | ListNode result = removeNthFromEnd(head1, 2); 18 | List list = ListUtil.toList(result); 19 | System.out.println(list); 20 | Assertions.assertArrayEquals(new Integer[] { 1, 2, 3, 5 }, list.toArray(new Integer[0])); 21 | 22 | ListNode head2 = ListUtil.buildList(1); 23 | ListNode result2 = removeNthFromEnd(head2, 1); 24 | List list2 = ListUtil.toList(result2); 25 | System.out.println(list2); 26 | Assertions.assertArrayEquals(new Integer[] {}, list2.toArray(new Integer[0])); 27 | 28 | ListNode head3 = ListUtil.buildList(1, 2); 29 | ListNode result3 = removeNthFromEnd(head3, 1); 30 | List list3 = ListUtil.toList(result3); 31 | System.out.println(list3); 32 | Assertions.assertArrayEquals(new Integer[] { 1 }, list3.toArray(new Integer[0])); 33 | } 34 | 35 | public static ListNode removeNthFromEnd(ListNode head, int n) { 36 | ListNode dummy = new ListNode(-1); 37 | dummy.next = head; 38 | 39 | ListNode fast = dummy; 40 | for (int i = 0; i < n + 1; i++) { 41 | fast = fast.next; 42 | } 43 | 44 | ListNode slow = dummy; 45 | while (fast != null) { 46 | fast = fast.next; 47 | slow = slow.next; 48 | } 49 | 50 | slow.next = slow.next.next; 51 | return dummy.next; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/反转链表II.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.list; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 92. 反转链表 II 9 | * 10 | * @author Zhang Peng 11 | * @date 2025-01-20 12 | */ 13 | public class 反转链表II { 14 | 15 | public static void main(String[] args) { 16 | ListNode head = ListUtil.buildList(1, 2, 3, 4, 5); 17 | System.out.println(ListUtil.toList(head)); 18 | ListNode result = reverseList(head, 2, 4); 19 | List list = ListUtil.toList(result); 20 | System.out.println(list); 21 | Assertions.assertArrayEquals(new Integer[] { 1, 4, 3, 2, 5 }, list.toArray(new Integer[0])); 22 | } 23 | 24 | /** 25 | * 借助栈来实现,时间复杂度:O(2N) 26 | */ 27 | public static ListNode reverseList(ListNode head, int m, int n) { 28 | if (m == 1) { 29 | return reverseN(head, n); 30 | } 31 | ListNode cur = head; 32 | for (int i = 1; i < m - 1; i++) { 33 | cur = cur.next; 34 | } 35 | cur.next = reverseN(cur.next, n - m + 1); 36 | return head; 37 | } 38 | 39 | public static ListNode reverseN(ListNode head, int n) { 40 | if (head == null || head.next == null) { 41 | return head; 42 | } 43 | ListNode pre = null, cur = head; 44 | while (cur != null && n > 0) { 45 | ListNode next = cur.next; 46 | cur.next = pre; 47 | pre = cur; 48 | cur = next; 49 | n--; 50 | } 51 | if (head != null) { 52 | head.next = cur; 53 | } 54 | return pre; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/合并两个有序链表.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.list; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author Zhang Peng 9 | * @see 合并两个有序链表 10 | * @since 2020-06-09 11 | */ 12 | public class 合并两个有序链表 { 13 | 14 | public static void main(String[] args) { 15 | ListNode head1 = ListUtil.buildList(1, 2, 4); 16 | ListNode head2 = ListUtil.buildList(1, 3, 4); 17 | ListNode result = mergeTwoLists(head1, head2); 18 | List list = ListUtil.toList(result); 19 | System.out.println(list); 20 | Assertions.assertArrayEquals(new Integer[] { 1, 1, 2, 3, 4, 4 }, list.toArray(new Integer[0])); 21 | } 22 | 23 | public static ListNode mergeTwoLists(ListNode l1, ListNode l2) { 24 | ListNode dummy = new ListNode(-1); 25 | ListNode n = dummy; 26 | while (l1 != null && l2 != null) { 27 | if (l1.val <= l2.val) { 28 | n.next = l1; 29 | l1 = l1.next; 30 | } else { 31 | n.next = l2; 32 | l2 = l2.next; 33 | } 34 | n = n.next; 35 | } 36 | 37 | n.next = (l1 != null) ? l1 : l2; 38 | return dummy.next; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/奇偶链表.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.list; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | /** 7 | * @author Zhang Peng 8 | * @since 2020-07-08 9 | */ 10 | public class 奇偶链表 { 11 | 12 | public static void main(String[] args) { 13 | ListNode head = ListUtil.buildList(1, 2, 3, 4, 5); 14 | List list = ListUtil.toList(oddEvenList(head)); 15 | System.out.println(list); 16 | // Assertions.assertFalse(); 17 | } 18 | 19 | public static ListNode oddEvenList(ListNode head) { 20 | if (head == null || head.next == null) return head; 21 | 22 | ListNode odd = head, even = head.next, evenHead = even; 23 | 24 | while (even != null && even.next != null) { 25 | odd.next = even.next; 26 | odd = odd.next; 27 | even.next = odd.next; 28 | even = even.next; 29 | } 30 | odd.next = evenHead; 31 | return head; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/环形链表.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.list; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * 141. 环形链表 7 | * 8 | * @author Zhang Peng 9 | * @since 2020-06-09 10 | */ 11 | public class 环形链表 { 12 | 13 | public static void main(String[] args) { 14 | ListNode head = ListUtil.buildList(3, 2, 0, -4); 15 | Assertions.assertFalse(hasCycle(head)); 16 | 17 | ListNode head2 = ListUtil.buildCycleList(1, new int[] { 3, 2, 0, -4 }); 18 | Assertions.assertTrue(hasCycle(head2)); 19 | 20 | ListNode head3 = ListUtil.buildCycleList(0, new int[] { 1, 2 }); 21 | Assertions.assertTrue(hasCycle(head3)); 22 | 23 | ListNode head4 = ListUtil.buildCycleList(1, new int[] { 1 }); 24 | Assertions.assertFalse(hasCycle(head4)); 25 | } 26 | 27 | public static boolean hasCycle(ListNode head) { 28 | if (head == null || head.next == null) return false; 29 | ListNode slow = head, fast = head.next; 30 | while (fast != null && fast.next != null) { 31 | if (slow == fast) { 32 | return true; 33 | } 34 | slow = slow.next; 35 | fast = fast.next.next; 36 | } 37 | return false; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/相交链表.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.list; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * 相交链表 7 | * 8 | * @author Zhang Peng 9 | * @since 2020-06-09 10 | */ 11 | public class 相交链表 { 12 | 13 | public static void main(String[] args) { 14 | ListNode listA = ListUtil.buildList(4, 1, 8, 4, 5); 15 | ListNode listB = ListUtil.buildList(5, 6, 1, 8, 4, 5); 16 | buildMetPot(listA, listB, 2, 3); 17 | ListNode result = getIntersectionNode(listA, listB); 18 | Assertions.assertEquals(8, result.val); 19 | 20 | ListNode listA2 = ListUtil.buildList(1, 9, 1, 2, 4); 21 | ListNode listB2 = ListUtil.buildList(3, 2, 4); 22 | buildMetPot(listA2, listB2, 3, 1); 23 | ListNode result2 = getIntersectionNode(listA2, listB2); 24 | Assertions.assertEquals(2, result2.val); 25 | } 26 | 27 | public static void buildMetPot(ListNode listA, ListNode listB, int skipA, int skipB) { 28 | ListNode pA = listA; 29 | for (int i = 0; i < skipA; i++) { 30 | pA = pA.next; 31 | } 32 | ListNode pB = listB; 33 | for (int i = 0; i < skipB - 1; i++) { 34 | pB = pB.next; 35 | } 36 | pB.next = pA; 37 | } 38 | 39 | public static ListNode getIntersectionNode(ListNode headA, ListNode headB) { 40 | if (headA == null || headB == null) return null; 41 | ListNode pA = headA, pB = headB; 42 | while (pA != pB) { 43 | pA = pA == null ? headB : pA.next; 44 | pB = pB == null ? headA : pB.next; 45 | } 46 | return pA; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/移除重复节点.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.list; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author Zhang Peng 9 | * @since 2020-06-09 10 | */ 11 | public class 移除重复节点 { 12 | 13 | public static void main(String[] args) { 14 | ListNode head = ListUtil.buildList(1, 2, 3, 3, 2, 1); 15 | ListNode listNode = removeDuplicateNodes(head); 16 | List result = ListUtil.getValues(listNode); 17 | System.out.println(result); 18 | Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, result.toArray()); 19 | } 20 | 21 | /** 22 | * @see 面试题 02.01. 移除重复节点 23 | */ 24 | public static ListNode removeDuplicateNodes(ListNode head) { 25 | if (head == null) { 26 | return null; 27 | } 28 | 29 | ListNode list = new ListNode(-1); 30 | list.next = null; 31 | 32 | ListNode node = head; 33 | while (node != null) { 34 | if (!exists(list, node.val)) { 35 | addToTail(list, node.val); 36 | } 37 | node = node.next; 38 | } 39 | return list.next; 40 | } 41 | 42 | private static boolean exists(ListNode head, int val) { 43 | ListNode node = head; 44 | while (node != null) { 45 | if (node.val == val) { return true; } 46 | node = node.next; 47 | } 48 | return false; 49 | } 50 | 51 | private static void addToTail(ListNode head, int val) { 52 | if (head == null) { 53 | return; 54 | } 55 | ListNode node = head; 56 | while (node.next != null) { 57 | node = node.next; 58 | } 59 | ListNode newNode = new ListNode(val); 60 | node.next = newNode; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/返回倒数第k个节点.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.list; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * 面试题 02. 返回倒数第 k 个节点 7 | * LCR 140. 训练计划 II 8 | * 9 | * @author Zhang Peng 10 | * @since 2020-06-09 11 | */ 12 | public class 返回倒数第k个节点 { 13 | 14 | public static void main(String[] args) { 15 | ListNode head = ListUtil.buildList(1, 2, 3, 4, 5); 16 | int val = kthToLast(head, 2); 17 | Assertions.assertEquals(4, val); 18 | 19 | ListNode head2 = ListUtil.buildList(1); 20 | int val2 = kthToLast(head2, 1); 21 | Assertions.assertEquals(1, val2); 22 | } 23 | 24 | public static int kthToLast(ListNode head, int k) { 25 | ListNode fast = head; 26 | // fast 指针先走 k 步 27 | for (int i = 0; i < k; i++) { 28 | fast = fast.next; 29 | } 30 | // fast、slow 同时走,直到结束 31 | ListNode slow = head; 32 | while (fast != null) { 33 | fast = fast.next; 34 | slow = slow.next; 35 | } 36 | // slow 现在指向第 n - k + 1 个节点,即倒数第 k 个节点 37 | return slow.val; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/链表的中间结点.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.list; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 876. 链表的中间结点 9 | * 10 | * @author Zhang Peng 11 | * @since 2020-06-09 12 | */ 13 | public class 链表的中间结点 { 14 | 15 | public static void main(String[] args) { 16 | ListNode head = ListUtil.buildList(1, 2, 3, 4, 5); 17 | System.out.println(ListUtil.toList(head)); 18 | ListNode result = middleNode(head); 19 | List list = ListUtil.toList(result); 20 | System.out.println(list); 21 | Assertions.assertArrayEquals(new Integer[] { 3, 4, 5 }, list.toArray(new Integer[0])); 22 | 23 | ListNode head2 = ListUtil.buildList(1, 2, 3, 4, 5, 6); 24 | System.out.println(ListUtil.toList(head2)); 25 | ListNode result2 = middleNode(head2); 26 | List list2 = ListUtil.toList(result2); 27 | System.out.println(list2); 28 | Assertions.assertArrayEquals(new Integer[] { 4, 5, 6 }, list2.toArray(new Integer[0])); 29 | } 30 | 31 | public static ListNode middleNode(ListNode head) { 32 | // 利用快慢指针,慢指针每次偏移一个节点,快指针每次偏移两个节点 33 | ListNode slow = head, fast = head; 34 | while (fast != null && fast.next != null) { 35 | slow = slow.next; 36 | fast = fast.next.next; 37 | } 38 | return slow; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/map/LRUCache.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.map; 2 | 3 | import java.util.Iterator; 4 | import java.util.LinkedHashMap; 5 | import java.util.Map; 6 | 7 | /** 8 | * @author Zhang Peng 9 | * @since 2020-01-18 10 | */ 11 | class LRUCache { 12 | 13 | private int capacity; 14 | 15 | // 保持插入顺序 16 | private Map map; 17 | 18 | public LRUCache(int capacity) { 19 | this.capacity = capacity; 20 | map = new LinkedHashMap<>(capacity); 21 | } 22 | 23 | public int get(int key) { 24 | if (map.containsKey(key)) { 25 | int value = map.get(key); 26 | map.remove(key); 27 | // 保证每次查询后,都在末尾 28 | map.put(key, value); 29 | return value; 30 | } 31 | return -1; 32 | } 33 | 34 | public void put(int key, int value) { 35 | if (map.containsKey(key)) { 36 | map.remove(key); 37 | } else if (map.size() == capacity) { 38 | Iterator> iterator = map.entrySet().iterator(); 39 | iterator.next(); 40 | iterator.remove(); 41 | } 42 | map.put(key, value); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/GenericQueue.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.queue; 2 | 3 | /** 4 | * @author Zhang Peng 5 | * @since 2020-06-10 6 | */ 7 | public class GenericQueue { 8 | 9 | // 队列的队首和队尾 10 | private Node head = null; 11 | private Node tail = null; 12 | 13 | // 入队 14 | public void enqueue(T value) { 15 | if (head == null) { 16 | tail = new Node(value, null); 17 | head = tail; 18 | } else { 19 | tail.next = new Node(value, null); 20 | tail = tail.next; 21 | } 22 | } 23 | 24 | // 出队 25 | public T dequeue() { 26 | if (head == null) { 27 | return null; 28 | } 29 | 30 | T val = head.data; 31 | head = head.next; 32 | if (head == null) { 33 | tail = null; 34 | } 35 | return val; 36 | } 37 | 38 | public void printAll() { 39 | Node p = head; 40 | while (p != null) { 41 | System.out.print(p.data + " "); 42 | p = p.next; 43 | } 44 | System.out.println(); 45 | } 46 | 47 | private static class Node { 48 | 49 | private T data; 50 | private Node next; 51 | 52 | public Node(T data, Node next) { 53 | this.data = data; 54 | this.next = next; 55 | } 56 | 57 | public T getData() { 58 | return data; 59 | } 60 | 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/动态扩容数组实现的队列.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.queue; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by wangzheng on 2018/10/9. 7 | */ 8 | public class 动态扩容数组实现的队列 { 9 | 10 | public static void main(String[] args) { 11 | 动态扩容数组实现的队列 queue = new 动态扩容数组实现的队列(3); 12 | queue.enqueue("1"); 13 | queue.enqueue("2"); 14 | queue.enqueue("3"); 15 | queue.enqueue("4"); 16 | queue.printAll(); 17 | System.out.println("dequeue " + queue.dequeue()); 18 | queue.printAll(); 19 | System.out.println("dequeue " + queue.dequeue()); 20 | queue.printAll(); 21 | } 22 | 23 | // 数组:items,数组大小:n 24 | private String[] items; 25 | private int n = 0; 26 | // head表示队头下标,tail表示队尾下标 27 | private int head = 0; 28 | private int tail = 0; 29 | 30 | // 申请一个大小为capacity的数组 31 | public 动态扩容数组实现的队列(int capacity) { 32 | items = new String[capacity]; 33 | n = capacity; 34 | } 35 | 36 | // 入队操作,将item放入队尾 37 | public boolean enqueue(String item) { 38 | // 队列已满,扩容 39 | if (tail == n) { 40 | n = n * 2; 41 | items = Arrays.copyOf(items, n); 42 | } 43 | 44 | items[tail] = item; 45 | tail++; 46 | return true; 47 | } 48 | 49 | // 出队 50 | public String dequeue() { 51 | // 如果head == tail 表示队列为空 52 | if (head == tail) return null; 53 | String val = items[head]; 54 | items = Arrays.copyOfRange(items, 1, tail); 55 | tail--; 56 | return val; 57 | } 58 | 59 | public void printAll() { 60 | for (int i = head; i < tail; ++i) { 61 | System.out.print(items[i] + " "); 62 | } 63 | System.out.println(); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/数组实现的队列.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.queue; 2 | 3 | /** 4 | * 用数组实现的队列 5 | * Created by wangzheng on 2018/10/9. 6 | */ 7 | public class 数组实现的队列 { 8 | 9 | public static void main(String[] args) { 10 | 数组实现的队列 queue = new 数组实现的队列(3); 11 | queue.enqueue("1"); 12 | queue.enqueue("2"); 13 | queue.enqueue("3"); 14 | queue.enqueue("4"); 15 | queue.printAll(); 16 | System.out.println("dequeue " + queue.dequeue()); 17 | queue.printAll(); 18 | System.out.println("dequeue " + queue.dequeue()); 19 | queue.printAll(); 20 | } 21 | 22 | // 数组:items,数组大小:n 23 | private String[] items; 24 | private int n = 0; 25 | // head表示队头下标,tail表示队尾下标 26 | private int head = 0; 27 | private int tail = 0; 28 | 29 | // 申请一个大小为capacity的数组 30 | public 数组实现的队列(int capacity) { 31 | items = new String[capacity]; 32 | n = capacity; 33 | } 34 | 35 | // 入队 36 | public boolean enqueue(String item) { 37 | // 如果tail == n 表示队列已经满了 38 | if (tail == n) return false; 39 | items[tail] = item; 40 | ++tail; 41 | return true; 42 | } 43 | 44 | // 出队 45 | public String dequeue() { 46 | // 如果head == tail 表示队列为空 47 | if (head == tail) return null; 48 | // 为了让其他语言的同学看的更加明确,把--操作放到单独一行来写了 49 | String ret = items[head]; 50 | ++head; 51 | return ret; 52 | } 53 | 54 | public void printAll() { 55 | for (int i = head; i < tail; ++i) { 56 | System.out.print(items[i] + " "); 57 | } 58 | System.out.println(); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/最近的请求次数.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.queue; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | /** 7 | * @author Zhang Peng 8 | * @see 933. 最近的请求次数 9 | * @since 2020-06-10 10 | */ 11 | public class 最近的请求次数 { 12 | 13 | Queue queue; 14 | 15 | public 最近的请求次数() { 16 | queue = new LinkedList<>(); 17 | } 18 | 19 | public int ping(int t) { 20 | queue.add(t); 21 | while (queue.peek() < t - 3000) { queue.poll(); } 22 | return queue.size(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/链表实现的队列.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.queue; 2 | 3 | /** 4 | * 基于链表实现的队列 5 | *

6 | * Author: Zheng 7 | */ 8 | public class 链表实现的队列 { 9 | 10 | public static void main(String[] args) { 11 | 链表实现的队列 queue = new 链表实现的队列(); 12 | queue.enqueue("1"); 13 | queue.enqueue("2"); 14 | queue.enqueue("3"); 15 | queue.enqueue("4"); 16 | queue.printAll(); 17 | System.out.println("dequeue " + queue.dequeue()); 18 | queue.printAll(); 19 | System.out.println("dequeue " + queue.dequeue()); 20 | queue.printAll(); 21 | } 22 | 23 | // 队列的队首和队尾 24 | private Node head = null; 25 | private Node tail = null; 26 | 27 | // 入队 28 | public void enqueue(String value) { 29 | if (head == null) { 30 | tail = new Node(value, null); 31 | head = tail; 32 | } else { 33 | tail.next = new Node(value, null); 34 | tail = tail.next; 35 | } 36 | } 37 | 38 | // 出队 39 | public String dequeue() { 40 | if (head == null) { 41 | return null; 42 | } 43 | 44 | String val = head.data; 45 | head = head.next; 46 | if (head == null) { 47 | tail = null; 48 | } 49 | return val; 50 | } 51 | 52 | public void printAll() { 53 | Node p = head; 54 | while (p != null) { 55 | System.out.print(p.data + " "); 56 | p = p.next; 57 | } 58 | System.out.println(); 59 | } 60 | 61 | private static class Node { 62 | 63 | private String data; 64 | private Node next; 65 | 66 | public Node(String data, Node next) { 67 | this.data = data; 68 | this.next = next; 69 | } 70 | 71 | public String getData() { 72 | return data; 73 | } 74 | 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/recursive/反转字符串.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.recursive; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * https://leetcode-cn.com/problems/reverse-string/ 7 | * 8 | * @author Zhang Peng 9 | * @since 2020-07-08 10 | */ 11 | public class 反转字符串 { 12 | 13 | public static void main(String[] args) { 14 | char[] str = { 'h', 'e', 'l', 'l', 'o' }; 15 | reverseString(str); 16 | Assertions.assertArrayEquals(new char[] { 'o', 'l', 'l', 'e', 'h' }, str); 17 | 18 | char[] str2 = { 'H', 'a', 'n', 'n', 'a', 'h' }; 19 | reverseString(str2); 20 | Assertions.assertArrayEquals(new char[] { 'h', 'a', 'n', 'n', 'a', 'H' }, str2); 21 | } 22 | 23 | public static void reverseString(char[] s) { 24 | if (s == null || s.length == 0) return; 25 | int l = 0, r = s.length - 1; 26 | recursive(s, l, r); 27 | } 28 | 29 | private static void recursive(char[] s, int l, int r) { 30 | if (l >= r) return; 31 | char temp = s[l]; 32 | s[l] = s[r]; 33 | s[r] = temp; 34 | recursive(s, l + 1, r - 1); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/Search.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.search; 2 | 3 | /** 4 | * @author Zhang Peng 5 | */ 6 | public interface Search { 7 | 8 | /** 9 | * @param array 要查找的数组 10 | * @param key 要查找的 key 11 | * @return 返回第一个匹配 key 值的数组元素所在位置 12 | */ 13 | > int find(T[] array, T key); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/SearchStrategy.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.search; 2 | 3 | import cn.hutool.core.util.ArrayUtil; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | /** 8 | * 使用策略模式,对算法进行包装 9 | * 10 | * @author Zhang Peng 11 | */ 12 | public class SearchStrategy { 13 | 14 | private static final Logger logger = LoggerFactory.getLogger(SearchStrategy.class); 15 | 16 | private Search search; 17 | 18 | public SearchStrategy(Search search) { 19 | search = search; 20 | } 21 | 22 | public int find(Integer[] list, int key) { 23 | logger.info(search.getClass().getSimpleName() + " 查找开始:"); 24 | logger.info("要查找的线性表:{}", ArrayUtil.toString(list)); 25 | logger.info("要查找的 key:{}", key); 26 | 27 | int index = search.find(list, key); 28 | logger.info("{} 的位置是:{}", key, index); 29 | return index; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/strategy/BinarySearch.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.search.strategy; 2 | 3 | import io.github.dunwu.algorithm.search.Search; 4 | 5 | /** 6 | * 二分查找又称折半查找,它是一种效率较高的查找方法。 二分查找需要两个前提:(1) 必须是顺序存储结构。(2) 必须是有序的表。 算法: 从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功; 7 | * 若扫描结束仍没有找到等于关键字的结点,表示查找失败。 算法分析: 最坏情况 O(log n) 最好情况 O(1) 平均情况 O(log n) 最坏情况下的空间复杂性 O(1) 8 | * 9 | * @author Zhang Peng 10 | */ 11 | public class BinarySearch implements Search { 12 | 13 | /** 14 | * 查找方法 15 | * 16 | * @param array 被查找的线性表 17 | * @param key 被查找的 key 18 | * @return 成功返回 key 的位置;失败返回 -1 19 | */ 20 | @Override 21 | public > int find(T[] array, T key) { 22 | return search(array, key, 0, array.length); 23 | } 24 | 25 | private > int search(T[] array, T key, int left, int right) { 26 | // this means that the key not found 27 | if (right < left) { 28 | return -1; 29 | } 30 | 31 | int mid = (left + right) >>> 1; 32 | int comp = key.compareTo(array[mid]); 33 | 34 | if (comp < 0) { 35 | return search(array, key, left, mid - 1); 36 | } 37 | 38 | if (comp > 0) { 39 | return search(array, key, mid + 1, right); 40 | } 41 | 42 | return mid; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/strategy/OrderSearch.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.search.strategy; 2 | 3 | import io.github.dunwu.algorithm.search.Search; 4 | 5 | /** 6 | * 顺序查找是一种最简单的查找算法。它的查找效率不高。 算法: 从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功; 若扫描结束仍没有找到关键字等于k的结点,表示查找失败。 算法分析: 7 | * 最坏情况 O(n) 最好情况 O(1) 平均情况 O(n) 最坏情况下的空间复杂性 8 | * 9 | * @author Zhang Peng 10 | */ 11 | public class OrderSearch implements Search { 12 | 13 | /** 14 | * 查找方法 15 | * 16 | * @param array 被查找的线性表 17 | * @param key 被查找的 key 18 | * @return 成功返回 key 的位置;失败返回 -1 19 | */ 20 | @Override 21 | public > int find(T[] array, T key) { 22 | for (int i = 0; i < array.length; i++) { 23 | if (array[i].compareTo(key) == 0) { 24 | return i; 25 | } 26 | } 27 | return -1; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/x的平方根.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.search; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | import java.math.BigDecimal; 6 | 7 | /** 8 | * @author Zhang Peng 9 | * @since 2020-07-04 10 | */ 11 | public class x的平方根 { 12 | 13 | public static void main(String[] args) { 14 | Assertions.assertEquals(2, mySqrt(4)); 15 | Assertions.assertEquals(3, mySqrt(9)); 16 | Assertions.assertEquals(2, mySqrt(8)); // 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。 17 | Assertions.assertEquals(2.8285f, mySqrt2(8, 4)); // 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。 18 | } 19 | 20 | // 利用二分法实现求平发根 21 | public static int mySqrt(int x) { 22 | if (x == 0 || x == 1) return x; 23 | int l = 1, r = x, res = x; 24 | while (l <= r) { 25 | int m = (l + r) / 2; 26 | if (m == x / m) { 27 | return m; 28 | } else if (m > x / m) { 29 | r = m - 1; 30 | } else { 31 | l = m + 1; 32 | res = m; 33 | } 34 | } 35 | return res; 36 | } 37 | 38 | // 利用二分法实现求浮点数平发根,支持指定精度 e (小数点位数) 39 | public static float mySqrt2(float x, int e) { 40 | if (x == 0 || Float.compare(x, 1f) == 0) return x; 41 | float l = 1f, r = x, res = x; 42 | while (l <= r) { 43 | float m = (l + r) / 2; 44 | if (m == x / m) { 45 | BigDecimal decimal = new BigDecimal(m).setScale(e, BigDecimal.ROUND_UP); 46 | return decimal.floatValue(); 47 | } else if (m > x / m) { 48 | r = m; 49 | } else { 50 | l = m; 51 | res = m; 52 | } 53 | } 54 | BigDecimal decimal = new BigDecimal(res).setScale(e, BigDecimal.ROUND_UP); 55 | return decimal.floatValue(); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/搜索二维矩阵.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.search; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * https://leetcode-cn.com/problems/search-insert-position/ 7 | * 8 | * @author Zhang Peng 9 | * @since 2020-07-13 10 | */ 11 | public class 搜索二维矩阵 { 12 | 13 | public static void main(String[] args) { 14 | int[][] metrix = { 15 | { 1, 3, 5, 7 }, 16 | { 10, 11, 16, 20 }, 17 | { 23, 30, 34, 50 } 18 | }; 19 | Assertions.assertTrue(searchMatrix(metrix, 3)); 20 | Assertions.assertFalse(searchMatrix(metrix, 13)); 21 | // Assertions.assertEquals(1, searchMatrix(metrix, 2)); 22 | // Assertions.assertEquals(4, searchMatrix(metrix, 7)); 23 | } 24 | 25 | public static boolean searchMatrix(int[][] matrix, int target) { 26 | int rowLen = matrix.length; 27 | int columnLen = matrix[0].length; 28 | 29 | // 剪枝 30 | if (matrix[rowLen - 1][columnLen - 1] < target) { 31 | return false; 32 | } 33 | 34 | int rbegin = 0, rend = rowLen - 1; 35 | while (rbegin < rend) { 36 | int rmid = rbegin + (rend - rbegin) / 2; 37 | if (matrix[rmid][columnLen - 1] == target) { 38 | return true; 39 | } else if (matrix[rmid][columnLen - 1] < target) { 40 | rbegin = rmid + 1; 41 | } else { 42 | rend = rmid; 43 | } 44 | } 45 | 46 | int cbegin = 0, cend = columnLen - 1; 47 | while (cbegin < cend) { 48 | int cmid = cbegin + (cend - cbegin) / 2; 49 | if (matrix[rbegin][cmid] == target) { 50 | return true; 51 | } else if (matrix[rbegin][cmid] < target) { 52 | cbegin = cmid + 1; 53 | } else { 54 | cend = cmid; 55 | } 56 | } 57 | 58 | return false; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/搜索插入位置.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.search; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * https://leetcode-cn.com/problems/search-insert-position/ 7 | * 8 | * @author Zhang Peng 9 | * @since 2020-07-13 10 | */ 11 | public class 搜索插入位置 { 12 | 13 | public static void main(String[] args) { 14 | int[] nums = { 1, 3, 5, 6 }; 15 | Assertions.assertEquals(2, searchInsert2(nums, 5)); 16 | Assertions.assertEquals(1, searchInsert2(nums, 2)); 17 | Assertions.assertEquals(4, searchInsert2(nums, 7)); 18 | } 19 | 20 | public static int searchInsert(int[] nums, int target) { 21 | 22 | int len = nums.length; 23 | int left = 0; 24 | int right = len - 1; 25 | if (nums[len - 1] < target) { 26 | return len; 27 | } 28 | while (left < right) { 29 | int mid = left + (right - left) / 2; 30 | if (nums[mid] < target) { 31 | left = mid + 1; 32 | } else { 33 | right = mid; 34 | } 35 | } 36 | return left; 37 | } 38 | 39 | public static int searchInsert2(int[] nums, int target) { 40 | int N = nums.length; 41 | if (target < nums[0]) return 0; 42 | if (target > nums[N - 1]) return N; 43 | int left = 0, right = N - 1; 44 | 45 | while (left < right) { 46 | int mid = left + (right - left) / 2; 47 | if (nums[mid] < target) { 48 | left = mid + 1; 49 | } else { 50 | right = mid; 51 | } 52 | } 53 | return left; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/第一个错误的版本.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.search; 2 | 3 | /** 4 | * @author Zhang Peng 5 | * @since 2020-07-13 6 | */ 7 | public class 第一个错误的版本 { 8 | 9 | public static void main(String[] args) { 10 | 11 | } 12 | 13 | public static int firstBadVersion(int n) { 14 | int begin = 1, end = n; 15 | while (begin < end) { 16 | int mid = begin + (end - begin) / 2; 17 | if (isBadVersion(mid)) { 18 | end = mid; 19 | } else { 20 | begin = mid; 21 | } 22 | } 23 | return begin; 24 | } 25 | 26 | public static boolean isBadVersion(int n) { 27 | return true; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/Sort.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.sort; 2 | 3 | /** 4 | * @author Zhang Peng 5 | */ 6 | public interface Sort { 7 | 8 | /** 9 | * 排序接口 10 | * 11 | * @param list 要排序的数组 12 | */ 13 | > void sort(T[] list); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/SortStrategy.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.sort; 2 | 3 | import io.github.dunwu.algorithm.util.ArrayUtil; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | /** 8 | * 使用策略模式,对算法进行包装 9 | * 10 | * @author Zhang Peng 11 | */ 12 | public class SortStrategy { 13 | 14 | private static final Logger logger = LoggerFactory.getLogger(SortStrategy.class); 15 | 16 | private Sort sort; 17 | 18 | public SortStrategy(Sort sort) { 19 | this.sort = sort; 20 | } 21 | 22 | public void sort(Integer[] list) { 23 | logger.info(this.sort.getClass().getSimpleName() + " 排序开始:"); 24 | logger.info("排序前: {}", ArrayUtil.getArrayString(list, 0, list.length - 1)); 25 | this.sort.sort(list); 26 | logger.info("排序后: {}", ArrayUtil.getArrayString(list, 0, list.length - 1)); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.sort.strategy; 2 | 3 | import io.github.dunwu.algorithm.sort.Sort; 4 | import io.github.dunwu.algorithm.util.ArrayUtil; 5 | 6 | /** 7 | * 冒泡排序算法 8 | * 9 | * @author Zhang Peng 10 | */ 11 | public class BubbleSort implements Sort { 12 | 13 | @Override 14 | public > void sort(T[] list) { 15 | // 要遍历的次数 16 | for (int i = 0; i < list.length - 1; i++) { 17 | // 从后向前依次的比较相邻两个数的大小,遍历一次后,把数组中第i小的数放在第i个位置上 18 | for (int j = list.length - 1; j > i; j--) { 19 | // 比较相邻的元素,如果前面的数大于后面的数,则交换 20 | if (list[j - 1].compareTo(list[j]) > 0) { 21 | T temp = list[j - 1]; 22 | list[j - 1] = list[j]; 23 | list[j] = temp; 24 | } 25 | } 26 | 27 | ArrayUtil.debugLogArray(list, 0, list.length - 1, String.format("第 %d 趟:", i + 1)); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort2.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.sort.strategy; 2 | 3 | import io.github.dunwu.algorithm.sort.Sort; 4 | import io.github.dunwu.algorithm.util.ArrayUtil; 5 | 6 | /** 7 | * 冒泡排序的优化算法 8 | * 9 | * @author Zhang Peng 10 | */ 11 | public class BubbleSort2 implements Sort { 12 | 13 | @Override 14 | public > void sort(T[] list) { 15 | // 交换标志 16 | boolean bChange = false; 17 | 18 | // 要遍历的次数 19 | for (int i = 0; i < list.length - 1; i++) { 20 | bChange = false; 21 | // 从后向前依次的比较相邻两个数的大小,遍历一次后,把数组中第i小的数放在第i个位置上 22 | for (int j = list.length - 1; j > i; j--) { 23 | // 比较相邻的元素,如果前面的数大于后面的数,则交换 24 | if (list[j - 1].compareTo(list[j]) > 0) { 25 | T temp = list[j - 1]; 26 | list[j - 1] = list[j]; 27 | list[j] = temp; 28 | bChange = true; 29 | } 30 | } 31 | 32 | // 如果标志为false,说明本轮遍历没有交换,已经是有序数列,可以结束排序 33 | if (false == bChange) { 34 | break; 35 | } 36 | 37 | ArrayUtil.debugLogArray(list, 0, list.length - 1, String.format("第 %d 趟:", i + 1)); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/HeapSort.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.sort.strategy; 2 | 3 | import io.github.dunwu.algorithm.sort.Sort; 4 | import io.github.dunwu.algorithm.util.ArrayUtil; 5 | 6 | /** 7 | * 堆排序算法 8 | * 9 | * @author Zhang Peng 10 | */ 11 | public class HeapSort implements Sort { 12 | 13 | @Override 14 | public > void sort(T[] list) { 15 | // 循环建立初始堆 16 | for (int i = list.length / 2; i >= 0; i--) { 17 | adjustHeat(list, i, list.length); 18 | } 19 | 20 | // 进行n-1次循环,完成排序 21 | for (int i = list.length - 1; i > 0; i--) { 22 | // 最后一个元素和第一元素进行交换 23 | T temp = list[i]; 24 | list[i] = list[0]; 25 | list[0] = temp; 26 | 27 | // 筛选 R[0] 结点,得到i-1个结点的堆 28 | adjustHeat(list, 0, i); 29 | 30 | ArrayUtil.debugLogArray(list, 0, list.length - 1, String.format("第 %d 趟:", list.length - i)); 31 | } 32 | } 33 | 34 | private static > void adjustHeat(T[] array, int parent, int length) { 35 | // temp保存当前父节点 36 | T temp = array[parent]; 37 | // 先获得左孩子 38 | int child = 2 * parent + 1; 39 | 40 | while (child < length) { 41 | // 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点 42 | if (child + 1 < length && array[child].compareTo(array[child + 1]) < 0) { 43 | child++; 44 | } 45 | 46 | // 如果父结点的值已经大于孩子结点的值,则直接结束 47 | if (temp.compareTo(array[child]) >= 0) { 48 | break; 49 | } 50 | 51 | // 把孩子结点的值赋给父结点 52 | array[parent] = array[child]; 53 | 54 | // 选取孩子结点的左孩子结点,继续向下筛选 55 | parent = child; 56 | child = 2 * child + 1; 57 | } 58 | 59 | array[parent] = temp; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/InsertSort.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.sort.strategy; 2 | 3 | import io.github.dunwu.algorithm.sort.Sort; 4 | import io.github.dunwu.algorithm.util.ArrayUtil; 5 | 6 | /** 7 | * 插入排序算法 8 | * 9 | * @author Zhang Peng 10 | */ 11 | public class InsertSort implements Sort { 12 | 13 | @Override 14 | public > void sort(T[] list) { 15 | // 打印第一个元素 16 | ArrayUtil.debugLogArray(list, 0, 0, String.format("i = %d:\t", 0)); 17 | 18 | // 第1个数肯定是有序的,从第2个数开始遍历,依次插入有序序列 19 | for (int i = 1; i < list.length; i++) { 20 | int j = 0; 21 | // 取出第i个数,和前i-1个数比较后,插入合适位置 22 | T temp = list[i]; 23 | 24 | // 因为前i-1个数都是从小到大的有序序列,所以只要当前比较的数(list[j])比temp大,就把这个数后移一位 25 | for (j = i - 1; j >= 0 && temp.compareTo(list[j]) < 0; j--) { 26 | list[j + 1] = list[j]; 27 | } 28 | list[j + 1] = temp; 29 | 30 | ArrayUtil.debugLogArray(list, 0, list.length - 1, String.format("i = %d:\t", i)); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/QuickSort.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.sort.strategy; 2 | 3 | import io.github.dunwu.algorithm.sort.Sort; 4 | import io.github.dunwu.algorithm.util.ArrayUtil; 5 | 6 | /** 7 | * 快速排序算法 8 | * 9 | * @author Zhang Peng 10 | */ 11 | public class QuickSort implements Sort { 12 | 13 | private > int division(T[] list, int left, int right) { 14 | // 以最左边的数(left)为基准 15 | T base = list[left]; 16 | while (left < right) { 17 | // 从序列右端开始,向左遍历,直到找到小于base的数 18 | while (left < right && list[right].compareTo(base) >= 0) { 19 | right--; 20 | } 21 | // 找到了比base小的元素,将这个元素放到最左边的位置 22 | list[left] = list[right]; 23 | 24 | // 从序列左端开始,向右遍历,直到找到大于base的数 25 | while (left < right && list[left].compareTo(base) <= 0) { 26 | left++; 27 | } 28 | // 找到了比base大的元素,将这个元素放到最右边的位置 29 | list[right] = list[left]; 30 | } 31 | 32 | // 最后将base放到left位置。此时,left位置的左侧数值应该都比left小; 33 | // 而left位置的右侧数值应该都比left大。 34 | list[left] = base; 35 | return left; 36 | } 37 | 38 | private > void quickSort(T[] list, int left, int right) { 39 | 40 | // 左下标一定小于右下标,否则就越界了 41 | if (left < right) { 42 | // 对数组进行分割,取出下次分割的基准标号 43 | int base = division(list, left, right); 44 | 45 | ArrayUtil.debugLogArray(list, left, right, String.format("base = %d: ", list[base])); 46 | 47 | // 对“基准标号“左侧的一组数值进行递归的切割,以至于将这些数值完整的排序 48 | quickSort(list, left, base - 1); 49 | 50 | // 对“基准标号“右侧的一组数值进行递归的切割,以至于将这些数值完整的排序 51 | quickSort(list, base + 1, right); 52 | } 53 | } 54 | 55 | @Override 56 | public > void sort(T[] list) { 57 | quickSort(list, 0, list.length - 1); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/SelectionSort.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.sort.strategy; 2 | 3 | import io.github.dunwu.algorithm.sort.Sort; 4 | import io.github.dunwu.algorithm.util.ArrayUtil; 5 | 6 | /** 7 | * 选择排序算法 8 | * 9 | * @author Zhang Peng 10 | */ 11 | public class SelectionSort implements Sort { 12 | 13 | @Override 14 | public > void sort(T[] list) { 15 | // 需要遍历获得最小值的次数 16 | // 要注意一点,当要排序 N 个数,已经经过 N-1 次遍历后,已经是有序数列 17 | for (int i = 0; i < list.length - 1; i++) { 18 | // 用来保存最小值得索引 19 | int index = i; 20 | 21 | // 寻找第i个小的数值 22 | for (int j = i + 1; j < list.length; j++) { 23 | if (list[index].compareTo(list[j]) > 0) { 24 | index = j; 25 | } 26 | } 27 | 28 | // 将找到的第i个小的数值放在第i个位置上 29 | T temp = list[index]; 30 | list[index] = list[i]; 31 | list[i] = temp; 32 | 33 | ArrayUtil.debugLogArray(list, 0, list.length - 1, String.format("第 %d 趟:", i + 1)); 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/ShellSort.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.sort.strategy; 2 | 3 | import io.github.dunwu.algorithm.sort.Sort; 4 | import io.github.dunwu.algorithm.util.ArrayUtil; 5 | 6 | /** 7 | * 希尔排序算法 8 | * 9 | * @author Zhang Peng 10 | */ 11 | public class ShellSort implements Sort { 12 | 13 | @Override 14 | public > void sort(T[] list) { 15 | int gap = list.length / 2; 16 | 17 | while (1 <= gap) { 18 | // 把距离为 gap 的元素编为一个组,扫描所有组 19 | for (int i = gap; i < list.length; i++) { 20 | int j = 0; 21 | T temp = list[i]; 22 | 23 | // 对距离为 gap 的元素组进行排序 24 | for (j = i - gap; j >= 0 && temp.compareTo(list[j]) < 0; j = j - gap) { 25 | list[j + gap] = list[j]; 26 | } 27 | list[j + gap] = temp; 28 | } 29 | 30 | ArrayUtil.debugLogArray(list, 0, list.length - 1, String.format("gap = %d:", gap)); 31 | // 减小增量 32 | gap = gap / 2; 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/GenericStack.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.stack; 2 | 3 | /** 4 | * 简化版泛型栈 5 | * 6 | * @author Zhang Peng 7 | * @since 2020-06-09 8 | */ 9 | public class GenericStack { 10 | 11 | private int size = 0; 12 | private Node top = null; 13 | 14 | public void push(T value) { 15 | Node node = new Node<>(value, null); 16 | if (top == null) { 17 | top = node; 18 | } else { 19 | node.next = top; 20 | top = node; 21 | } 22 | size++; 23 | } 24 | 25 | public T pop() { 26 | if (top == null) { 27 | return null; 28 | } 29 | T val = top.data; 30 | top = top.next; 31 | size--; 32 | return val; 33 | } 34 | 35 | public T peek() { 36 | if (top == null) { 37 | return null; 38 | } 39 | return top.data; 40 | } 41 | 42 | public int getSize() { 43 | return size; 44 | } 45 | 46 | public boolean isEmpty() { 47 | return size == 0; 48 | } 49 | 50 | public void printAll() { 51 | Node p = top; 52 | while (p != null) { 53 | System.out.print(p.data + " "); 54 | p = p.next; 55 | } 56 | System.out.println(); 57 | } 58 | 59 | private static class Node { 60 | 61 | private T data; 62 | private Node next; 63 | 64 | public Node(T data, Node next) { 65 | this.data = data; 66 | this.next = next; 67 | } 68 | 69 | public T getData() { 70 | return data; 71 | } 72 | 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/StackBasedOnLinkedList.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.stack; 2 | 3 | /** 4 | * 基于链表实现的栈。 5 | *

6 | * Author: Zheng 7 | */ 8 | public class StackBasedOnLinkedList { 9 | 10 | public static void main(String[] args) { 11 | StackBasedOnLinkedList stack = new StackBasedOnLinkedList(); 12 | stack.push(1); 13 | stack.push(2); 14 | stack.push(3); 15 | stack.printAll(); 16 | System.out.println("pop " + stack.pop()); 17 | System.out.println("pop " + stack.pop()); 18 | System.out.println("pop " + stack.pop()); 19 | } 20 | 21 | private Node top = null; 22 | 23 | public void push(int value) { 24 | Node node = new Node(value, null); 25 | if (top == null) { 26 | top = node; 27 | } else { 28 | node.next = top; 29 | top = node; 30 | } 31 | } 32 | 33 | /** 34 | * 我用-1表示栈中没有数据。 35 | */ 36 | public int pop() { 37 | if (top == null) return -1; 38 | int val = top.data; 39 | top = top.next; 40 | return val; 41 | } 42 | 43 | public void printAll() { 44 | Node p = top; 45 | while (p != null) { 46 | System.out.print(p.data + " "); 47 | p = p.next; 48 | } 49 | System.out.println(); 50 | } 51 | 52 | private static class Node { 53 | 54 | private int data; 55 | private Node next; 56 | 57 | public Node(int data, Node next) { 58 | this.data = data; 59 | this.next = next; 60 | } 61 | 62 | public int getData() { 63 | return data; 64 | } 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/三合一.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.stack; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | 7 | /** 8 | * @author Zhang Peng 9 | * @since 2020-06-09 10 | */ 11 | public class 三合一 { 12 | 13 | int stackSize; 14 | List> stacks; 15 | 16 | public 三合一(int stackSize) { 17 | this.stackSize = stackSize; 18 | this.stacks = new ArrayList<>(); 19 | for (int i = 0; i < 3; i++) { 20 | LinkedList list = new LinkedList<>(); 21 | this.stacks.add(list); 22 | } 23 | } 24 | 25 | public void push(int stackNum, int value) { 26 | LinkedList list = stacks.get(stackNum); 27 | if (list.size() < stackSize) { 28 | list.addLast(value); 29 | } 30 | } 31 | 32 | public int pop(int stackNum) { 33 | LinkedList list = stacks.get(stackNum); 34 | int value = -1; 35 | if (list.size() > 0) { 36 | value = list.getLast(); 37 | list.removeLast(); 38 | } 39 | return value; 40 | } 41 | 42 | public int peek(int stackNum) { 43 | LinkedList list = stacks.get(stackNum); 44 | int value = -1; 45 | if (list.size() > 0) { 46 | value = list.getLast(); 47 | } 48 | return value; 49 | } 50 | 51 | public boolean isEmpty(int stackNum) { 52 | LinkedList list = stacks.get(stackNum); 53 | return list.size() <= 0; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/最小栈.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.stack; 2 | 3 | import java.util.LinkedList; 4 | 5 | /** 6 | * @see 面试题 03.02. 栈的最小值 7 | */ 8 | public class 最小栈 { 9 | 10 | public static void main(String[] args) { 11 | 最小栈 stack = new 最小栈(); 12 | stack.push(9); 13 | stack.push(2); 14 | stack.push(5); 15 | stack.push(6); 16 | stack.push(3); 17 | stack.push(1); 18 | System.out.println("min = " + stack.getMin()); 19 | System.out.println("pop " + stack.pop()); 20 | System.out.println("pop " + stack.pop()); 21 | System.out.println("pop " + stack.pop()); 22 | } 23 | 24 | private final LinkedList stack; 25 | private final LinkedList minStack; 26 | 27 | public 最小栈() { 28 | stack = new LinkedList<>(); 29 | minStack = new LinkedList<>(); 30 | } 31 | 32 | public void push(int x) { 33 | if (!minStack.isEmpty()) { 34 | Integer first = minStack.getFirst(); 35 | if (x < first) { 36 | minStack.push(x); 37 | } 38 | stack.push(x); 39 | } 40 | } 41 | 42 | public int pop() { 43 | int top = stack.pop(); 44 | int val = minStack.peek() ; 45 | if (val == val) { 46 | minStack.pop(); 47 | } 48 | return val; 49 | } 50 | 51 | public int top() { 52 | return stack.getFirst(); 53 | } 54 | 55 | public int getMin() { 56 | if (minStack.isEmpty()) { 57 | return -1; 58 | } else { 59 | return minStack.getFirst(); 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/最小栈2.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.stack; 2 | 3 | import java.util.LinkedList; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @since 2020-01-18 8 | */ 9 | public class 最小栈2 { 10 | 11 | // 数据栈 12 | private LinkedList data; 13 | 14 | // 辅助栈 15 | private LinkedList helper; 16 | 17 | /** 18 | * initialize your data structure here. 19 | */ 20 | public 最小栈2() { 21 | data = new LinkedList<>(); 22 | helper = new LinkedList<>(); 23 | } 24 | 25 | // 思路 1:数据栈和辅助栈在任何时候都同步 26 | public void push(int x) { 27 | // 数据栈和辅助栈一定会增加元素 28 | data.push(x); 29 | if (helper.isEmpty() || helper.peek() >= x) { 30 | helper.push(x); 31 | } else { 32 | helper.push(helper.peek()); 33 | } 34 | } 35 | 36 | public void pop() { 37 | // 两个栈都得 pop 38 | if (!data.isEmpty()) { 39 | helper.pop(); 40 | data.pop(); 41 | } 42 | } 43 | 44 | public int top() { 45 | if (!data.isEmpty()) { 46 | return data.peek(); 47 | } 48 | throw new RuntimeException("栈中元素为空,此操作非法"); 49 | } 50 | 51 | public int getMin() { 52 | if (!helper.isEmpty()) { 53 | return helper.peek(); 54 | } 55 | throw new RuntimeException("栈中元素为空,此操作非法"); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/有效的括号.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.stack; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @see 20. 有效的括号 7 | * @author Zhang Peng 8 | * @since 2020-06-09 9 | */ 10 | public class 有效的括号 { 11 | 12 | public static void main(String[] args) { 13 | Assertions.assertTrue(isValid("()")); 14 | Assertions.assertTrue(isValid("{[]}")); 15 | Assertions.assertFalse(isValid("([)]")); 16 | Assertions.assertFalse(isValid("([)")); 17 | } 18 | 19 | public static boolean isValid(String s) { 20 | if (s == null) { 21 | return true; 22 | } 23 | 24 | int length = s.length(); 25 | if (length == 0) return true; 26 | if (length % 2 != 0) return false; 27 | 28 | GenericStack stack = new GenericStack<>(); 29 | for (char c : s.toCharArray()) { 30 | Character top = stack.peek(); 31 | if (top == null) { 32 | stack.push(c); 33 | continue; 34 | } 35 | 36 | if (top == '(' && c == ')') { 37 | stack.pop(); 38 | } else if (top == '[' && c == ']') { 39 | stack.pop(); 40 | } else if (top == '{' && c == '}') { 41 | stack.pop(); 42 | } else { 43 | stack.push(c); 44 | } 45 | } 46 | 47 | if (stack.getSize() == 0) { 48 | return true; 49 | } 50 | return false; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/栈排序.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.stack; 2 | 3 | import java.util.LinkedList; 4 | 5 | /** 6 | * @see 面试题 03.05. 栈排序 7 | */ 8 | public class 栈排序 { 9 | 10 | public static void main(String[] args) { 11 | 栈排序 demo = new 栈排序(); 12 | demo.push(1); 13 | System.out.println(demo.stack1); 14 | demo.push(2); 15 | System.out.println(demo.stack1); 16 | } 17 | 18 | public LinkedList stack1; 19 | public LinkedList stack2; 20 | 21 | public 栈排序() { 22 | stack1 = new LinkedList<>(); 23 | stack2 = new LinkedList<>(); 24 | } 25 | 26 | public void push(int val) { 27 | if (isEmpty()) { 28 | stack1.push(val); 29 | return; 30 | } 31 | 32 | if (!stack1.isEmpty()) { 33 | move(val); 34 | } 35 | 36 | stack1.push(val); 37 | while (!stack2.isEmpty()) { 38 | Integer top = stack2.pop(); 39 | stack1.push(top); 40 | } 41 | } 42 | 43 | private void move(int val) { 44 | if (stack1.isEmpty()) { 45 | return; 46 | } 47 | 48 | int top = peek(); 49 | if (top < val) { 50 | stack2.push(stack1.pop()); 51 | move(val); 52 | } 53 | } 54 | 55 | public int pop() { 56 | if (stack1.isEmpty()) { 57 | return -1; 58 | } 59 | return stack1.pop(); 60 | } 61 | 62 | public int peek() { 63 | if (stack1.isEmpty()) { 64 | return -1; 65 | } 66 | return stack1.peek(); 67 | } 68 | 69 | public boolean isEmpty() { 70 | return stack1.isEmpty() && stack2.isEmpty(); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/棒球比赛.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.stack; 2 | 3 | /** 4 | * @author Zhang Peng 5 | * @see 682. 棒球比赛 6 | * @since 2020-06-09 7 | */ 8 | public class 棒球比赛 { 9 | 10 | public static void main(String[] args) { 11 | System.out.println(calPoints("5", "2", "C", "D", "+")); 12 | System.out.println(calPoints("5", "-2", "4", "C", "D", "9", "+", "+")); 13 | } 14 | 15 | public static int calPoints(String... ops) { 16 | int total = 0; 17 | GenericStack stack = new GenericStack<>(); 18 | for (String s : ops) { 19 | if (s.equals("+")) { 20 | int num1 = stack.pop(); 21 | int num2 = stack.pop(); 22 | int num = num1 + num2; 23 | stack.push(num2); 24 | stack.push(num1); 25 | stack.push(num); 26 | } else if (s.equals("D")) { 27 | stack.push(stack.peek() * 2); 28 | } else if (s.equals("C")) { 29 | stack.pop(); 30 | } else { 31 | stack.push(Integer.valueOf(s)); 32 | } 33 | } 34 | 35 | while (stack.getSize() != 0) { 36 | total += stack.pop(); 37 | } 38 | 39 | return total; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/比较含退格的字符串.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.stack; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @see 844. 比较含退格的字符串 8 | * @since 2020-06-09 9 | */ 10 | public class 比较含退格的字符串 { 11 | 12 | public static void main(String[] args) { 13 | Assertions.assertTrue(backspaceCompare("ab#c", "ad#c")); 14 | Assertions.assertTrue(backspaceCompare("ab##", "c#d#")); 15 | Assertions.assertTrue(backspaceCompare("a##c", "#a#c")); 16 | Assertions.assertFalse(backspaceCompare("a#c", "b")); 17 | } 18 | 19 | public static boolean backspaceCompare(String S, String T) { 20 | return getFinalStr(S).equals(getFinalStr(T)); 21 | } 22 | 23 | public static String getFinalStr(String S) { 24 | GenericStack stack = new GenericStack<>(); 25 | for (char c : S.toCharArray()) { 26 | if (c == '#') { 27 | stack.pop(); 28 | } else { 29 | stack.push(c); 30 | } 31 | } 32 | 33 | StringBuilder sb = new StringBuilder(); 34 | while (stack.getSize() > 0) { 35 | sb.append(stack.pop()); 36 | } 37 | 38 | return sb.reverse().toString(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/用栈实现队列.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.stack; 2 | 3 | import java.util.LinkedList; 4 | 5 | /** 6 | * @see 232. 用栈实现队列 7 | */ 8 | public class 用栈实现队列 { 9 | 10 | public static void main(String[] args) { 11 | 用栈实现队列 queue = new 用栈实现队列(); 12 | queue.push(1); 13 | queue.push(2); 14 | System.out.println(queue.peek()); // 返回 1 15 | System.out.println(queue.pop()); // 返回 1 16 | System.out.println(queue.empty()); // 返回 false 17 | } 18 | 19 | private LinkedList stack1; 20 | private LinkedList stack2; 21 | 22 | /** Initialize your data structure here. */ 23 | public 用栈实现队列() { 24 | stack1 = new LinkedList<>(); 25 | stack2 = new LinkedList<>(); 26 | } 27 | 28 | /** Push element x to the back of queue. */ 29 | public void push(int x) { 30 | stack1.push(x); 31 | } 32 | 33 | /** Removes the element from in front of queue and returns that element. */ 34 | public int pop() { 35 | peek(); 36 | return stack2.pop(); 37 | } 38 | 39 | /** Get the front element. */ 40 | public int peek() { 41 | if (stack2.size() > 0) { 42 | return stack2.peek(); 43 | } 44 | while (!stack1.isEmpty()) { 45 | stack2.push(stack1.pop()); 46 | } 47 | return stack2.peek(); 48 | } 49 | 50 | /** Returns whether the queue is empty. */ 51 | public boolean empty() { 52 | return stack1.isEmpty() && stack2.isEmpty(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/用队列实现栈.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.stack; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | /** 7 | * 基于队列实现的栈 8 | * 9 | * @author Zhang Peng 10 | * @see 225. 用队列实现栈 11 | * @since 2020-01-18 12 | */ 13 | public class 用队列实现栈 { 14 | 15 | public static void main(String[] args) { 16 | 用队列实现栈 stack = new 用队列实现栈<>(); 17 | stack.push(1); 18 | stack.push(2); 19 | System.out.println(stack.pop()); 20 | System.out.println(stack.pop()); 21 | } 22 | 23 | private Queue q1 = new LinkedList<>(); 24 | 25 | /** 26 | * Initialize your data structure here. 27 | */ 28 | public 用队列实现栈() { } 29 | 30 | /** 31 | * Push element x onto stack. 32 | */ 33 | public void push(T x) { 34 | q1.add(x); 35 | int sz = q1.size(); 36 | while (sz > 1) { 37 | q1.add(q1.remove()); 38 | sz--; 39 | } 40 | } 41 | 42 | /** 43 | * Removes the element on top of the stack and returns that element. 44 | */ 45 | public T pop() { 46 | return q1.poll(); 47 | } 48 | 49 | /** 50 | * Get the top element. 51 | */ 52 | public T top() { 53 | return q1.peek(); 54 | } 55 | 56 | /** 57 | * Returns whether the stack is empty. 58 | */ 59 | public boolean empty() { 60 | return q1.isEmpty(); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/AddBinary.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.str; 2 | 3 | // 【二进制求和】 4 | 5 | // 6 | // 给定两个二进制字符串,返回他们的和(用二进制表示)。 7 | // 8 | // 输入为非空字符串且只包含数字 1 和 0。 9 | // 10 | // 示例 1: 11 | // 12 | // 输入: a = "11", b = "1" 13 | // 输出: "100" 14 | // 示例 2: 15 | // 16 | // 输入: a = "1010", b = "1011" 17 | // 输出: "10101" 18 | 19 | /** 20 | * @author Zhang Peng 21 | * @since 2018-11-04 22 | */ 23 | public class AddBinary { 24 | 25 | public static String addBinary(String a, String b) { 26 | StringBuilder sb = new StringBuilder(); 27 | int i = a.length() - 1, j = b.length() - 1, carry = 0; 28 | while (i >= 0 || j >= 0) { 29 | int sum = carry; 30 | if (j >= 0) { 31 | sum += b.charAt(j--) - '0'; 32 | } 33 | if (i >= 0) { 34 | sum += a.charAt(i--) - '0'; 35 | } 36 | sb.append(sum % 2); 37 | carry = sum / 2; 38 | } 39 | if (carry != 0) { 40 | sb.append(carry); 41 | } 42 | return sb.reverse().toString(); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ImplementStrstr.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.str; 2 | 3 | // 【实现 strStr() 函数】 4 | // 5 | // 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。 6 | // 7 | // 示例 1: 8 | // 9 | // 输入: haystack = "hello", needle = "ll" 10 | // 输出: 2 11 | // 示例 2: 12 | // 13 | // 输入: haystack = "aaaaa", needle = "bba" 14 | // 输出: -1 15 | // 说明: 16 | // 17 | // 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 18 | // 19 | // 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。 20 | 21 | /** 22 | * @author Zhang Peng 23 | * @since 2018-11-05 24 | */ 25 | public class ImplementStrstr { 26 | 27 | public static int strStr(String haystack, String needle) { 28 | if (haystack.equals(needle)) { 29 | return 0; 30 | } 31 | 32 | if (haystack == null || haystack.length() == 0) { 33 | return -1; 34 | } 35 | 36 | if (needle == null || needle.length() == 0) { 37 | return 0; 38 | } 39 | 40 | if (haystack.length() < needle.length()) { 41 | return -1; 42 | } 43 | 44 | int begin = 0; 45 | int i = 0; 46 | int j = 0; 47 | while (i < haystack.length() && begin < haystack.length()) { 48 | if (j == needle.length()) { 49 | return begin; 50 | } else if (haystack.charAt(i) == needle.charAt(j)) { 51 | i++; 52 | j++; 53 | } else { 54 | j = 0; 55 | begin++; 56 | i = begin; 57 | } 58 | } 59 | 60 | if (i == haystack.length() && j == needle.length()) { 61 | return begin; 62 | } 63 | return -1; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/LongestCommonPrefix.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.str; 2 | 3 | // 【最长公共前缀】 4 | 5 | // 6 | // 编写一个函数来查找字符串数组中的最长公共前缀。 7 | // 8 | // 如果不存在公共前缀,返回空字符串 ""。 9 | // 10 | // 示例 1: 11 | // 12 | // 输入: ["flower","flow","flight"] 13 | // 输出: "fl" 14 | // 示例 2: 15 | // 16 | // 输入: ["dog","racecar","car"] 17 | // 输出: "" 18 | // 解释: 输入不存在公共前缀。 19 | // 说明: 20 | // 21 | // 所有输入只包含小写字母 a-z 。 22 | 23 | /** 24 | * @author Zhang Peng 25 | * @since 2018-11-05 26 | */ 27 | public class LongestCommonPrefix { 28 | 29 | public static String longestCommonPrefix(String[] strs) { 30 | if (strs == null || strs.length == 0) { 31 | return ""; 32 | } 33 | 34 | int index = 0; 35 | StringBuilder sb = new StringBuilder(); 36 | 37 | while (index < strs[0].length()) { 38 | char c = strs[0].charAt(index); 39 | boolean flag = true; 40 | for (String str : strs) { 41 | if (index >= str.length()) { 42 | flag = false; 43 | break; 44 | } 45 | if (str.charAt(index) != c) { 46 | flag = false; 47 | break; 48 | } 49 | } 50 | 51 | if (flag) { 52 | sb.append(c); 53 | index++; 54 | } else { 55 | break; 56 | } 57 | } 58 | return sb.toString(); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ReverseString.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.str; 2 | 3 | // 【反转字符串】 4 | 5 | // 6 | // 编写一个函数,其作用是将输入的字符串反转过来。 7 | // 8 | // 示例 1: 9 | // 10 | // 输入: "hello" 11 | // 输出: "olleh" 12 | // 示例 2: 13 | // 14 | // 输入: "A man, a plan, a canal: Panama" 15 | // 输出: "amanaP :lanac a ,nalp a ,nam A" 16 | 17 | /** 18 | * @author Zhang Peng 19 | * @since 2018-11-05 20 | */ 21 | public class ReverseString { 22 | 23 | public static String reverseString(String s) { 24 | StringBuilder sb = new StringBuilder(); 25 | 26 | for (int i = s.length() - 1; i >= 0; i--) { 27 | sb.append(s.charAt(i)); 28 | } 29 | 30 | return sb.toString(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ReverseWordsInAString3.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.str; 2 | 3 | // 【反转字符串中的单词 III】 4 | 5 | // 6 | // 给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。 7 | // 8 | // 示例 1: 9 | // 10 | // 输入: "Let's take LeetCode contest" 11 | // 输出: "s'teL ekat edoCteeL tsetnoc" 12 | // 注意:在字符串中,每个单词由单个空格分隔,并且字符串中不会有任何额外的空格。 13 | 14 | /** 15 | * @author Zhang Peng 16 | * @since 2018-11-05 17 | */ 18 | public class ReverseWordsInAString3 { 19 | 20 | public static String reverseWords(String s) { 21 | StringBuilder sb = new StringBuilder(); 22 | String[] strs = s.split(" "); 23 | for (int index = 0; index < strs.length; index++) { 24 | int i = 0; 25 | int j = strs[index].length() - 1; 26 | 27 | char[] a = strs[index].toCharArray(); 28 | while (i < j) { 29 | char t = a[i]; 30 | a[i++] = a[j]; 31 | a[j--] = t; 32 | } 33 | 34 | sb.append(a); 35 | if (index != strs.length - 1) { 36 | sb.append(" "); 37 | } 38 | } 39 | 40 | return sb.toString(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/string/最长回文子串.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.string; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @date 2025-01-10 8 | */ 9 | public class 最长回文子串 { 10 | 11 | public static void main(String[] args) { 12 | Assertions.assertEquals("bab", longestPalindrome("babad")); 13 | Assertions.assertEquals("bb", longestPalindrome("cbbd")); 14 | Assertions.assertEquals("aca", longestPalindrome("aacabdkacaa")); 15 | } 16 | 17 | public static String longestPalindrome(String s) { 18 | char[] chars = s.toCharArray(); 19 | String max = s.substring(0, 1); 20 | for (int i = 0; i < chars.length; i++) { 21 | for (int j = chars.length - 1; j > i; j--) { 22 | if (check(chars, i, j)) { 23 | String temp = s.substring(i, j + 1); 24 | if (temp.length() > max.length()) { 25 | max = temp; 26 | } 27 | } 28 | } 29 | } 30 | return max; 31 | } 32 | 33 | public static boolean check(char[] chars, int begin, int end) { 34 | int left = begin, right = end; 35 | while (left < right) { 36 | if (chars[left] != chars[right]) { 37 | return false; 38 | } 39 | left++; 40 | right--; 41 | } 42 | return true; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/N叉树的最大深度.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree; 2 | 3 | import java.util.List; 4 | 5 | // 559. N叉树的最大深度 6 | // 7 | // https://leetcode-cn.com/problems/maximum-depth-of-n-ary-tree/ 8 | // 9 | // 给定一个 N 叉树,找到其最大深度。 10 | // 11 | // 最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。 12 | // 13 | // 例如,给定一个 3叉树 : 14 | // 15 | // 我们应返回其最大深度,3。 16 | // 17 | // 说明: 18 | // 19 | // 树的深度不会超过 1000。 20 | // 树的节点总不会超过 5000。 21 | public class N叉树的最大深度 { 22 | 23 | public static int maxDepth(Node root) { 24 | if (root == null) return 0; 25 | if (root.children == null || root.children.size() == 0) return 1; 26 | int max = 0; 27 | for (Node node : root.children) { 28 | int temp = maxDepth(node); 29 | if (temp > max) { 30 | max = temp; 31 | } 32 | } 33 | return max + 1; 34 | } 35 | 36 | static class Node { 37 | 38 | public int val; 39 | 40 | public List children; 41 | 42 | public Node() {} 43 | 44 | public Node(int val) { 45 | this.val = val; 46 | } 47 | 48 | public Node(int val, List children) { 49 | this.val = val; 50 | this.children = children; 51 | } 52 | 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeNode.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @since 2020-01-28 8 | */ 9 | public class TreeNode { 10 | 11 | public int val; 12 | 13 | public TreeNode left; 14 | 15 | public TreeNode right; 16 | 17 | public TreeNode(int val) { this.val = val; } 18 | 19 | public TreeNode(int val, TreeNode left, TreeNode right) { 20 | this.val = val; 21 | this.left = left; 22 | this.right = right; 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | return String.valueOf(val); 28 | } 29 | 30 | @Override 31 | public boolean equals(Object o) { 32 | if (this == o) return true; 33 | if (!(o instanceof TreeNode)) return false; 34 | TreeNode treeNode = (TreeNode) o; 35 | return val == treeNode.val && 36 | Objects.equals(left, treeNode.left) && 37 | Objects.equals(right, treeNode.right); 38 | } 39 | 40 | @Override 41 | public int hashCode() { 42 | return Objects.hash(val, left, right); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 二叉搜索树算法 3 | * 4 | * @author Zhang Peng 5 | * @since 2020-07-07 6 | */ 7 | package io.github.dunwu.algorithm.tree.bstree; 8 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/二叉搜索树中的插入操作.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.bstree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | import io.github.dunwu.algorithm.tree.TreeUtils; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author Zhang Peng 10 | * @see 701. 二叉搜索树中的插入操作 11 | * @since 2020-07-06 12 | */ 13 | public class 二叉搜索树中的插入操作 { 14 | 15 | public static void main(String[] args) { 16 | TreeNode tree = TreeUtils.asTree(4, 2, 7, 1, 3); 17 | insertIntoBST(tree, 5); 18 | List treeNodes = TreeUtils.toBfsList(tree); 19 | System.out.println(treeNodes); 20 | } 21 | 22 | public static TreeNode insertIntoBST(TreeNode root, int val) { 23 | if (root == null) return new TreeNode(val); 24 | 25 | TreeNode node = root; 26 | if (val > node.val) { 27 | if (node.right == null) { 28 | node.right = new TreeNode(val); 29 | } else { insertIntoBST(node.right, val); } 30 | } else { 31 | if (node.left == null) { 32 | node.left = new TreeNode(val); 33 | } else { insertIntoBST(node.left, val); } 34 | } 35 | return root; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/将有序数组转换为二叉搜索树.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.bstree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @since 2020-07-07 8 | */ 9 | public class 将有序数组转换为二叉搜索树 { 10 | 11 | public static void main(String[] args) { 12 | System.out.println("result = " + sortedArrayToBST(new int[] { -10, -3, 0, 5, 9 })); 13 | } 14 | 15 | public static TreeNode sortedArrayToBST(int[] nums) { 16 | if (nums == null || nums.length == 0) return null; 17 | return backtrack(nums, 0, nums.length - 1); 18 | } 19 | 20 | public static TreeNode backtrack(int[] nums, int left, int right) { 21 | if (left > right) return null; 22 | // always choose left middle node as a root 23 | int p = (left + right) / 2; 24 | 25 | // inorder traversal: left -> node -> right 26 | TreeNode root = new TreeNode(nums[p]); 27 | root.left = backtrack(nums, left, p - 1); 28 | root.right = backtrack(nums, p + 1, right); 29 | return root; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 二叉树算法 3 | * 4 | * @author Zhang Peng 5 | * @since 2020-06-18 6 | */ 7 | package io.github.dunwu.algorithm.tree.btree; 8 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树中的最大路径和.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | import io.github.dunwu.algorithm.tree.TreeUtils; 5 | import org.junit.jupiter.api.Assertions; 6 | 7 | /** 8 | * @author Zhang Peng 9 | * @see 124. 二叉树中的最大路径和 10 | * @since 2020-07-06 11 | */ 12 | public class 二叉树中的最大路径和 { 13 | 14 | public static void main(String[] args) { 15 | 二叉树中的最大路径和 demo = new 二叉树中的最大路径和(); 16 | TreeNode tree = TreeUtils.asTree(1, 2, 3); 17 | Assertions.assertEquals(6, demo.maxPathSum(tree)); 18 | TreeNode tree2 = TreeUtils.asTree(-10, 9, 20, null, null, 15, 7); 19 | Assertions.assertEquals(42, demo.maxPathSum(tree2)); 20 | TreeNode tree3 = TreeUtils.asTree(2, -1); 21 | Assertions.assertEquals(2, demo.maxPathSum(tree3)); 22 | TreeNode tree4 = TreeUtils.asTree(-2, -1); 23 | Assertions.assertEquals(-1, demo.maxPathSum(tree4)); 24 | } 25 | 26 | int maxSum; 27 | 28 | public int maxPathSum(TreeNode root) { 29 | maxSum = Integer.MIN_VALUE; 30 | maxGain(root); 31 | return maxSum; 32 | } 33 | 34 | public int maxGain(TreeNode node) { 35 | if (node == null) { 36 | return 0; 37 | } 38 | 39 | // 递归计算左右子节点的最大贡献值 40 | // 只有在最大贡献值大于 0 时,才会选取对应子节点 41 | int left = Math.max(maxGain(node.left), 0); 42 | int right = Math.max(maxGain(node.right), 0); 43 | 44 | // 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值 45 | int current = node.val + left + right; 46 | 47 | // 更新答案 48 | maxSum = Math.max(maxSum, current); 49 | 50 | // 返回节点的最大贡献值 51 | return node.val + Math.max(left, right); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的中序遍历.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @author Zhang Peng 10 | * @since 2020-07-06 11 | */ 12 | public class 二叉树的中序遍历 { 13 | 14 | public static List inorderTraversal(TreeNode root) { 15 | List list = new ArrayList<>(); 16 | if (root == null) return list; 17 | backtrack(root, list); 18 | return list; 19 | } 20 | 21 | public static void backtrack(TreeNode root, List list) { 22 | if (root == null) return; 23 | if (root.left != null) backtrack(root.left, list); 24 | list.add(root.val); 25 | if (root.right != null) backtrack(root.right, list); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的前序遍历.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | import io.github.dunwu.algorithm.tree.TreeUtils; 5 | import org.junit.jupiter.api.Assertions; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * @author Zhang Peng 12 | * @since 2020-07-06 13 | */ 14 | public class 二叉树的前序遍历 { 15 | 16 | public static void main(String[] args) { 17 | TreeNode tree = TreeUtils.buildTree(new Integer[] { 1, null, 2, 3 }); 18 | List list = preorderTraversal(tree); 19 | Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, list.toArray(new Integer[0])); 20 | } 21 | 22 | public static List preorderTraversal(TreeNode root) { 23 | List list = new ArrayList<>(); 24 | if (root == null) return list; 25 | backtrack(root, list); 26 | return list; 27 | } 28 | 29 | public static void backtrack(TreeNode root, List list) { 30 | if (root == null) return; 31 | list.add(root.val); 32 | if (root.left != null) backtrack(root.left, list); 33 | if (root.right != null) backtrack(root.right, list); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的后序遍历.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @author Zhang Peng 10 | * @since 2020-07-06 11 | */ 12 | public class 二叉树的后序遍历 { 13 | 14 | public List postorderTraversal(TreeNode root) { 15 | List list = new ArrayList<>(); 16 | if (root == null) return list; 17 | backtrack(root, list); 18 | return list; 19 | } 20 | 21 | public static void backtrack(TreeNode root, List list) { 22 | if (root == null) return; 23 | if (root.left != null) backtrack(root.left, list); 24 | if (root.right != null) backtrack(root.right, list); 25 | list.add(root.val); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的层次遍历.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | import io.github.dunwu.algorithm.tree.TreeUtils; 5 | import org.junit.jupiter.api.Assertions; 6 | 7 | import java.util.*; 8 | 9 | /** 10 | * @author Zhang Peng 11 | * @see 二叉树的层次遍历 12 | * @since 2020-06-18 13 | */ 14 | public class 二叉树的层次遍历 { 15 | 16 | public static void main(String[] args) { 17 | TreeNode tree = TreeUtils.asTree(3, 9, 20, null, null, 15, 7); 18 | List> resultList = levelOrder(tree); 19 | List> expectList = new LinkedList<>(); 20 | expectList.add(Arrays.asList(3)); 21 | expectList.add(Arrays.asList(9, 20)); 22 | expectList.add(Arrays.asList(15, 7)); 23 | Assertions.assertArrayEquals(expectList.toArray(), resultList.toArray()); 24 | } 25 | 26 | /** 27 | * 基于 BFS 实现二叉树层次遍历。关键在于使用一个队列存储 28 | */ 29 | public static List> levelOrder(TreeNode root) { 30 | List> result = new ArrayList<>(); 31 | if (root == null) return result; 32 | 33 | Queue queue = new LinkedList<>(); 34 | queue.offer(root); 35 | while (!queue.isEmpty()) { 36 | int size = queue.size(); 37 | List list = new ArrayList<>(); 38 | for (int i = 0; i < size; i++) { 39 | TreeNode node = queue.poll(); 40 | if (node.left != null) queue.offer(node.left); 41 | if (node.right != null) queue.offer(node.right); 42 | list.add(node.val); 43 | } 44 | result.add(list); 45 | } 46 | 47 | return result; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的所有路径.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | import io.github.dunwu.algorithm.tree.TreeUtils; 5 | import org.junit.jupiter.api.Assertions; 6 | 7 | import java.util.Arrays; 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | 11 | /** 12 | * 二叉树的所有路径 算法实现 13 | * 14 | *

15 |  * 给定一个二叉树,返回所有从根节点到叶子节点的路径。
16 |  *
17 |  * 说明: 叶子节点是指没有子节点的节点。
18 |  *
19 |  * 示例:
20 |  *
21 |  * 输入:
22 |  *
23 |  *    1
24 |  *  /   \
25 |  * 2     3
26 |  *  \
27 |  *   5
28 |  *
29 |  * 输出: ["1->2->5", "1->3"]
30 |  *
31 |  * 解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3
32 |  * 
33 | * 34 | * @see 二叉树的所有路径 35 | */ 36 | public class 二叉树的所有路径 { 37 | 38 | public static void main(String[] args) { 39 | TreeNode tree = TreeUtils.asTree(1, 2, 3, 5); 40 | System.out.println("result = " + binaryTreePaths(tree)); 41 | Assertions.assertArrayEquals(Arrays.asList("1->2->5", "1->3").toArray(), 42 | binaryTreePaths(tree).toArray(new String[0])); 43 | } 44 | 45 | public static List binaryTreePaths(TreeNode root) { 46 | List paths = new LinkedList<>(); 47 | recordPath(root, "", paths); 48 | return paths; 49 | } 50 | 51 | private static void recordPath(TreeNode node, String path, List paths) { 52 | if (node == null) return; 53 | path += node.val; 54 | if (node.left == null && node.right == null) { 55 | paths.add(path); 56 | } else { 57 | path += "->"; 58 | recordPath(node.left, path, paths); 59 | recordPath(node.right, path, paths); 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的最大深度.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | import io.github.dunwu.algorithm.tree.TreeUtils; 5 | import org.junit.jupiter.api.Assertions; 6 | 7 | import java.util.LinkedList; 8 | import java.util.Queue; 9 | 10 | /** 11 | * 104. 二叉树的最大深度 算法实现 12 | * 13 | * @see 104. 二叉树的最大深度 14 | */ 15 | public class 二叉树的最大深度 { 16 | 17 | public static void main(String[] args) { 18 | TreeNode tree = TreeUtils.deserialize("[3,9,20,null,null,15,7]"); 19 | System.out.println("result = " + maxDepthInDFS(tree)); 20 | Assertions.assertEquals(3, maxDepthInDFS(tree)); 21 | Assertions.assertEquals(3, maxDepthInBFS(tree)); 22 | } 23 | 24 | // 基于 DFS 实现 25 | // 时间复杂度 O(N) 26 | public static int maxDepthInDFS(TreeNode root) { 27 | if (root == null) return 0; 28 | return 1 + Math.max(maxDepthInDFS(root.left), maxDepthInDFS(root.right)); 29 | } 30 | 31 | // 基于 BFS 实现 32 | // 逐层扫描,只要每层有节点,层级数+1 33 | // 时间复杂度 O(N) 34 | public static int maxDepthInBFS(TreeNode root) { 35 | 36 | if (root == null) return 0; 37 | 38 | int level = 0; 39 | Queue queue = new LinkedList<>(); 40 | queue.offer(root); 41 | while (!queue.isEmpty()) { 42 | level++; 43 | int size = queue.size(); 44 | for (int i = 0; i < size; i++) { 45 | TreeNode node = queue.poll(); 46 | if (node == null) continue; 47 | if (node.left != null) queue.add(node.left); 48 | if (node.right != null) queue.add(node.right); 49 | } 50 | } 51 | 52 | return level; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/叶子相似的树.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | import io.github.dunwu.algorithm.tree.TreeUtils; 5 | import org.junit.jupiter.api.Assertions; 6 | 7 | import java.util.Arrays; 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | 11 | /** 12 | * 叶子相似的树 算法实现 13 | * 14 | *
15 |  * 请考虑一颗二叉树上所有的叶子,这些叶子的值按从左到右的顺序排列形成一个 叶值序列 。
16 |  *
17 |  *
18 |  *
19 |  * 举个例子,如上图所示,给定一颗叶值序列为 (6, 7, 4, 9, 8) 的树。
20 |  *
21 |  * 如果有两颗二叉树的叶值序列是相同,那么我们就认为它们是 叶相似 的。
22 |  *
23 |  * 如果给定的两个头结点分别为 root1 和 root2 的树是叶相似的,则返回 true;否则返回 false 。
24 |  *
25 |  * 提示:
26 |  *
27 |  * 给定的两颗树可能会有 1 到 100 个结点。
28 |  * 
29 | * 30 | * @see 叶子相似的树 31 | */ 32 | public class 叶子相似的树 { 33 | 34 | public static void main(String[] args) { 35 | TreeNode tree1 = TreeUtils.asTree(3, 5, 1, 6, 2, 9, 8, null, null, 7, 4); 36 | TreeNode tree2 = TreeUtils.asTree(3, 5, 1, 6, 7, 4, 2, null, null, null, null, null, null, 9, 8); 37 | Assertions.assertTrue(leafSimilar(tree1, tree2)); 38 | } 39 | 40 | public static boolean leafSimilar(TreeNode root1, TreeNode root2) { 41 | List leafs1 = new LinkedList<>(); 42 | List leafs2 = new LinkedList<>(); 43 | leafNodes(root1, leafs1); 44 | leafNodes(root2, leafs2); 45 | return Arrays.equals(leafs1.toArray(), leafs2.toArray()); 46 | } 47 | 48 | public static void leafNodes(TreeNode root, List leafs) { 49 | if (root == null) { return; } 50 | if (root.left == null && root.right == null) { leafs.add(root.val); } 51 | leafNodes(root.left, leafs); 52 | leafNodes(root.right, leafs); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/填充每个节点的下一个右侧节点指针.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import java.util.LinkedList; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @since 2020-07-06 8 | */ 9 | public class 填充每个节点的下一个右侧节点指针 { 10 | 11 | public Node connect(Node root) { 12 | if (root == null) return null; 13 | bfs(root); 14 | return root; 15 | } 16 | 17 | /** 18 | * 基于 BFS 实现二叉树层次遍历。关键在于使用一个队列存储 19 | */ 20 | public void bfs(Node root) { 21 | LinkedList queue = new LinkedList<>(); 22 | queue.offer(root); 23 | while (!queue.isEmpty()) { 24 | int size = queue.size(); 25 | for (int i = 1; i < size; i++) { 26 | queue.get(i - 1).next = queue.get(i); 27 | } 28 | 29 | for (int i = 0; i < size; i++) { 30 | Node node = queue.poll(); 31 | if (node.left != null) queue.offer(node.left); 32 | if (node.right != null) queue.offer(node.right); 33 | } 34 | } 35 | } 36 | 37 | private static class Node { 38 | 39 | public int val; 40 | public Node left; 41 | public Node right; 42 | public Node next; 43 | 44 | public Node(int val) { this.val = val; } 45 | 46 | public Node(int val, Node left, Node right) { 47 | this.val = val; 48 | this.left = left; 49 | this.right = right; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "Node{" + 55 | "val=" + val + 56 | '}'; 57 | } 58 | 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/填充每个节点的下一个右侧节点指针II.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import java.util.LinkedList; 4 | 5 | /** 6 | * @author Zhang Peng 7 | * @since 2020-07-06 8 | */ 9 | public class 填充每个节点的下一个右侧节点指针II { 10 | 11 | public Node connect(Node root) { 12 | if (root == null) return null; 13 | bfs(root); 14 | return root; 15 | } 16 | 17 | /** 18 | * 基于 BFS 实现二叉树层次遍历。关键在于使用一个队列存储 19 | */ 20 | public void bfs(Node root) { 21 | LinkedList queue = new LinkedList<>(); 22 | queue.offer(root); 23 | while (!queue.isEmpty()) { 24 | int size = queue.size(); 25 | for (int i = 1; i < size; i++) { 26 | queue.get(i - 1).next = queue.get(i); 27 | } 28 | 29 | for (int i = 0; i < size; i++) { 30 | Node node = queue.poll(); 31 | if (node.left != null) queue.offer(node.left); 32 | if (node.right != null) queue.offer(node.right); 33 | } 34 | } 35 | } 36 | 37 | private static class Node { 38 | 39 | public int val; 40 | public Node left; 41 | public Node right; 42 | public Node next; 43 | 44 | public Node(int val) { this.val = val; } 45 | 46 | public Node(int val, Node left, Node right) { 47 | this.val = val; 48 | this.left = left; 49 | this.right = right; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "Node{" + 55 | "val=" + val + 56 | '}'; 57 | } 58 | 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/对称二叉树.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | import io.github.dunwu.algorithm.tree.TreeUtils; 5 | 6 | /** 7 | * 101. 对称二叉树 算法实现 8 | *

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

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

13 |  *     1
14 |  *    / \
15 |  *   2   2
16 |  *  / \ / \
17 |  * 3  4 4  3
18 |  * 
19 | * 但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的: 20 | *
21 |  *     1
22 |  *    / \
23 |  *   2   2
24 |  *    \   \
25 |  *    3    3
26 |  * 
27 | * 说明:如果你可以运用递归和迭代两种方法解决这个问题,会很加分。 28 | * 29 | * @see 101. 对称二叉树 30 | */ 31 | public class 对称二叉树 { 32 | 33 | public static void main(String[] args) { 34 | TreeNode tree = TreeUtils.asTree(1, 2, 2, 3, 4, 4, 3); 35 | System.out.println("result = " + isSymmetric(tree)); 36 | 37 | tree = TreeUtils.asTree(1, 2, 2, null, 3, null, 3); 38 | System.out.println("result = " + isSymmetric(tree)); 39 | } 40 | 41 | public static boolean isSymmetric(TreeNode root) { 42 | return isMirror(root, root); 43 | } 44 | 45 | private static boolean isMirror(TreeNode tree1, TreeNode tree2) { 46 | if (tree1 == null && tree2 == null) return true; 47 | if (tree1 == null || tree2 == null) return false; 48 | if (tree1.val != tree2.val) return false; 49 | return isMirror(tree1.left, tree2.right) && isMirror(tree1.right, tree2.left); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/平衡二叉树.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | import io.github.dunwu.algorithm.tree.TreeUtils; 5 | import org.junit.jupiter.api.Assertions; 6 | 7 | /** 8 | * @author Zhang Peng 9 | * @since 2020-07-06 10 | */ 11 | public class 平衡二叉树 { 12 | 13 | public static void main(String[] args) { 14 | TreeNode tree = TreeUtils.asTree(3, 9, 20, null, null, 15, 7); 15 | TreeNode tree2 = TreeUtils.asTree(1, 2, 2, 3, 3, null, null, 4, 4); 16 | TreeNode tree3 = TreeUtils.asTree(null); 17 | 平衡二叉树 demo = new 平衡二叉树(); 18 | Assertions.assertTrue(demo.isBalanced(tree)); 19 | Assertions.assertFalse(demo.isBalanced(tree2)); 20 | Assertions.assertTrue(demo.isBalanced(tree3)); 21 | } 22 | 23 | private boolean flag = true; 24 | 25 | public boolean isBalanced(TreeNode root) { 26 | if (root == null) return true; 27 | backtrack(root); 28 | return flag; 29 | } 30 | 31 | public int backtrack(TreeNode root) { 32 | if (root == null) return 0; 33 | if (root.left == null && root.right == null) return 1; 34 | int left = backtrack(root.left); 35 | int right = backtrack(root.right); 36 | int temp = left - right; 37 | if (temp > 1 || temp < -1) { 38 | flag = false; 39 | } 40 | return Math.max(left, right) + 1; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/相同的树.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | import io.github.dunwu.algorithm.tree.TreeUtils; 5 | 6 | /** 7 | * 100. 相同的树 算法实现 8 | *

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

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

13 | * 示例 1: 14 | *

15 |  * 输入:       1         1
16 |  *           / \       / \
17 |  *          2   3     2   3
18 |  *
19 |  *         [1,2,3],   [1,2,3]
20 |  *
21 |  * 输出: true
22 |  * 
23 | * 示例 2: 24 | *
25 |  * 输入:      1          1
26 |  *           /           \
27 |  *          2             2
28 |  *
29 |  *         [1,2],     [1,null,2]
30 |  *
31 |  * 输出: false
32 |  * 
33 | * 示例 3: 34 | *
35 |  * 输入:       1         1
36 |  *           / \       / \
37 |  *          2   1     1   2
38 |  *
39 |  *         [1,2,1],   [1,1,2]
40 |  *
41 |  * 输出: false
42 |  * 
43 | * 44 | * @see 100. 相同的树 45 | */ 46 | public class 相同的树 { 47 | 48 | public static void main(String[] args) { 49 | TreeNode tree1 = TreeUtils.asTree(1, 2, 3); 50 | TreeNode tree2 = TreeUtils.asTree(1, 2, 3); 51 | System.out.println("result = " + isSameTree(tree1, tree2)); 52 | 53 | tree1 = TreeUtils.asTree(1, 2); 54 | tree2 = TreeUtils.asTree(1, 2, 3); 55 | System.out.println("result = " + isSameTree(tree1, tree2)); 56 | 57 | tree1 = TreeUtils.asTree(1, 2, 1); 58 | tree2 = TreeUtils.asTree(1, 1, 2); 59 | System.out.println("result = " + isSameTree(tree1, tree2)); 60 | } 61 | 62 | public static boolean isSameTree(TreeNode p, TreeNode q) { 63 | if (p == null && q == null) return true; 64 | 65 | if (p == null || q == null) return false; 66 | 67 | if (p.val != q.val) return false; 68 | 69 | return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/翻转二叉树.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | import io.github.dunwu.algorithm.tree.TreeUtils; 5 | 6 | /** 7 | * 翻转二叉树 算法实现 8 | * 9 | *
10 |  * 翻转一棵二叉树。
11 |  *
12 |  * 示例:
13 |  *
14 |  * 输入:
15 |  *
16 |  *      4
17 |  *    /   \
18 |  *   2     7
19 |  *  / \   / \
20 |  * 1   3 6   9
21 |  * 输出:
22 |  *
23 |  *      4
24 |  *    /   \
25 |  *   7     2
26 |  *  / \   / \
27 |  * 9   6 3   1
28 |  * 备注:
29 |  * 这个问题是受到 Max Howell 的 原问题 启发的 :
30 |  * 
31 | * 32 | * @see 翻转二叉树 33 | */ 34 | public class 翻转二叉树 { 35 | 36 | public static void main(String[] args) { 37 | TreeNode tree = TreeUtils.asTree(4, 2, 7, 1, 3, 6, 9); 38 | System.out.println("result = " + invertTree(tree)); 39 | } 40 | 41 | public static TreeNode invertTree(TreeNode root) { 42 | if (root == null) { return null; } 43 | 44 | TreeNode right = invertTree(root.right); 45 | TreeNode left = invertTree(root.left); 46 | 47 | root.left = right; 48 | root.right = left; 49 | return root; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/路径总和.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree.btree; 2 | 3 | import io.github.dunwu.algorithm.tree.TreeNode; 4 | import io.github.dunwu.algorithm.tree.TreeUtils; 5 | import org.junit.jupiter.api.Assertions; 6 | 7 | /** 8 | * 路径总和 算法实现 9 | * 10 | *
11 |  * 给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
12 |  *
13 |  * 说明: 叶子节点是指没有子节点的节点。
14 |  *
15 |  * 示例: 
16 |  * 给定如下二叉树,以及目标和 sum = 22,
17 |  *
18 |  *               5
19 |  *              / \
20 |  *             4   8
21 |  *            /   / \
22 |  *           11  13  4
23 |  *          /  \      \
24 |  *         7    2      1
25 |  * 返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
26 |  * 
27 | * 28 | * @see 112. 路径总和 29 | */ 30 | public class 路径总和 { 31 | 32 | public static void main(String[] args) { 33 | TreeNode 34 | tree = TreeUtils.asTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, null, null, 1); 35 | Assertions.assertTrue(hasPathSum(tree, 22)); 36 | TreeNode tree2 = TreeUtils.asTree(1, 2); 37 | Assertions.assertFalse(hasPathSum(tree2, 1)); 38 | } 39 | 40 | public static boolean hasPathSum(TreeNode root, int sum) { 41 | if (root == null) { return false; } 42 | sum -= root.val; 43 | if (root.left == null && root.right == null) { return sum == 0; } 44 | return hasPathSum(root.left, sum) || hasPathSum(root.right, sum); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/最长公共前缀.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.trie; 2 | 3 | /** 4 | * @author Zhang Peng 5 | * @since 2020-06-15 6 | */ 7 | public class 最长公共前缀 { 8 | 9 | public static void main(String[] args) { 10 | longestCommonPrefix("flower", "flow", "flight"); 11 | } 12 | 13 | public static String longestCommonPrefix(String... strs) { 14 | Trie trie = new Trie(); 15 | for (String s : strs) { 16 | trie.insert(s.toCharArray()); 17 | } 18 | return trie.longest(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/java/io/github/dunwu/algorithm/括号生成.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.List; 8 | 9 | /** 10 | * @author Zhang Peng 11 | * @since 2020-07-03 12 | */ 13 | public class 括号生成 { 14 | 15 | public static void main(String[] args) { 16 | List list1 = Collections.singletonList("()"); 17 | List list2 = new ArrayList<>(); 18 | list2.add("(())"); 19 | list2.add("()()"); 20 | Assertions.assertArrayEquals(list1.toArray(), generateParenthesis(1).toArray()); 21 | Assertions.assertArrayEquals(list2.toArray(), generateParenthesis(2).toArray()); 22 | } 23 | 24 | public static List generateParenthesis(int n) { 25 | List list = new ArrayList<>(); 26 | generateOneByOne(list, 0, 0, n, ""); 27 | return list; 28 | } 29 | 30 | private static void generateOneByOne(List list, int left, int right, int n, String str) { 31 | // 因为括号必然成对出现,所以左括号数和右括号都等于 N,即符合条件 32 | if (left == n && right == n) { 33 | list.add(str); 34 | return; 35 | } 36 | // 左括号数小于 N,就累加,将其 ( 加入字符串 37 | if (left < n) generateOneByOne(list, left + 1, right, n, str + "("); 38 | // 右括号数小于 N 并且小于左括号数(右括号数多于左括号数,则语义不合法),就累加,将其 ) 加入字符串 39 | if (right < n && right < left) generateOneByOne(list, left, right + 1, n, str + ")"); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /codes/algorithm/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | %d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n 12 | 13 | 14 | 15 | 16 | 17 | ${user.dir}/logs/${DIR_NAME}/all.%d{yyyy-MM-dd}.log 18 | 30 19 | 20 | 21 | 22 | 23 | 30MB 24 | 25 | 26 | 27 | %d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/IteratorTest.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.common; 2 | 3 | import java.util.Iterator; 4 | 5 | public class IteratorTest { 6 | 7 | public static > boolean testIterator(Iterator iter) { 8 | while (iter.hasNext()) { 9 | T item = iter.next(); 10 | if (item == null) { 11 | System.err.println("Iterator failure."); 12 | return false; 13 | } 14 | } 15 | return true; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/SuffixTreeTest.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.common; 2 | 3 | public class SuffixTreeTest { 4 | 5 | /** 6 | * In computer science, a suffix tree (also called PAT tree or, in an earlier form, position tree) is a compressed 7 | * trie containing all the suffixes of the given text as their keys and positions in the text as their values. 8 | * Suffix trees allow particularly fast implementations of many important string operations. 9 | * 10 | * @param tree Suffix tree to test. 11 | * @param test String to use in testing the suffix tree. 12 | * @return True if the suffix tree passes it's invariants tests. 13 | */ 14 | public static boolean suffixTreeTest(ISuffixTree tree, String test) { 15 | boolean exists = tree.doesSubStringExist(test); 16 | if (!exists) { 17 | System.err.println("YIKES!! " + test + " doesn't exists."); 18 | Utils.handleError(test, tree); 19 | return false; 20 | } 21 | 22 | String failed = test + "Z"; 23 | exists = tree.doesSubStringExist(failed); 24 | if (exists) { 25 | System.err.println("YIKES!! " + failed + " exists."); 26 | Utils.handleError(failed, tree); 27 | return false; 28 | } 29 | 30 | String pass = test.substring(0, 6); 31 | exists = tree.doesSubStringExist(pass); 32 | if (!exists) { 33 | System.err.println("YIKES!! " + pass + " doesn't exists."); 34 | Utils.handleError(pass, tree); 35 | return false; 36 | } 37 | 38 | return true; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /codes/algorithm/src/test/java/io/github/dunwu/algorithm/map/LRUCacheTest.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.map; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | /** 7 | * @author Zhang Peng 8 | * @since 2020-01-18 9 | */ 10 | public class LRUCacheTest { 11 | 12 | @Test 13 | public void test() { 14 | LRUCache cache = new LRUCache(3); 15 | Assertions.assertEquals(-1, cache.get(2)); 16 | cache.put(2, 6); 17 | Assertions.assertEquals(-1, cache.get(1)); 18 | cache.put(1, 5); 19 | cache.put(1, 2); 20 | Assertions.assertEquals(2, cache.get(1)); 21 | Assertions.assertEquals(6, cache.get(2)); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/AddBinaryTest.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.str; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | /** 7 | * @author Zhang Peng 8 | * @since 2018-11-05 9 | */ 10 | public class AddBinaryTest { 11 | 12 | @Test 13 | public void test() { 14 | Assertions.assertEquals("100", AddBinary.addBinary("11", "1")); 15 | Assertions.assertEquals("10101", AddBinary.addBinary("1010", "1011")); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ImplementStrstrTest.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.str; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | /** 7 | * @author Zhang Peng 8 | * @since 2018-11-05 9 | */ 10 | public class ImplementStrstrTest { 11 | 12 | @Test 13 | public void test() { 14 | Assertions.assertEquals(0, ImplementStrstr.strStr("", "")); 15 | Assertions.assertEquals(-1, ImplementStrstr.strStr("aaa", "aaaa")); 16 | Assertions.assertEquals(0, ImplementStrstr.strStr("aaa", "")); 17 | Assertions.assertEquals(2, ImplementStrstr.strStr("hello", "ll")); 18 | Assertions.assertEquals(-1, ImplementStrstr.strStr("aaaaa", "bba")); 19 | Assertions.assertEquals(1, ImplementStrstr.strStr("mississippi", "issi")); 20 | Assertions.assertEquals(9, ImplementStrstr.strStr("mississippi", "pi")); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/LongestCommonPrefixTest.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.str; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | /** 7 | * @author Zhang Peng 8 | * @since 2018-11-05 9 | */ 10 | public class LongestCommonPrefixTest { 11 | 12 | @Test 13 | public void test() { 14 | String[] strs1 = { "flower", "flow", "flight" }; 15 | String[] strs2 = { "dog", "racecar", "car" }; 16 | 17 | Assertions.assertEquals("fl", LongestCommonPrefix.longestCommonPrefix(strs1)); 18 | Assertions.assertEquals("", LongestCommonPrefix.longestCommonPrefix(strs2)); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ReverseStringTest.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.str; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | /** 7 | * @author Zhang Peng 8 | * @since 2018-11-05 9 | */ 10 | public class ReverseStringTest { 11 | 12 | @Test 13 | public void test() { 14 | Assertions.assertEquals("olleh", ReverseString.reverseString("hello")); 15 | Assertions.assertEquals("amanaP :lanac a ,nalp a ,nam A", 16 | ReverseString.reverseString("A man, a plan, a canal: Panama")); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ReverseWordsInAString3Test.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.str; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | /** 7 | * @author Zhang Peng 8 | * @since 2018-11-05 9 | */ 10 | public class ReverseWordsInAString3Test { 11 | 12 | @Test 13 | public void test() { 14 | Assertions.assertEquals("s'teL ekat edoCteeL tsetnoc", 15 | ReverseWordsInAString3.reverseWords("Let's take LeetCode contest")); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ReverseWordsInAStringTest.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.str; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | /** 7 | * @author Zhang Peng 8 | * @since 2018-11-05 9 | */ 10 | public class ReverseWordsInAStringTest { 11 | 12 | @Test 13 | public void test() { 14 | Assertions.assertEquals("blue is sky the", ReverseWordsInAString.reverseWords("the sky is blue")); 15 | Assertions.assertEquals(" ", ReverseWordsInAString.reverseWords(" ")); 16 | Assertions.assertEquals("1", ReverseWordsInAString.reverseWords("1 ")); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BinaryTreeTests.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.algorithm.tree; 2 | 3 | import io.github.dunwu.algorithm.common.JavaCollectionTest; 4 | import io.github.dunwu.algorithm.common.TreeTest; 5 | import io.github.dunwu.algorithm.common.Utils; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.util.Collection; 9 | 10 | import static org.junit.jupiter.api.Assertions.assertTrue; 11 | 12 | public class BinaryTreeTests { 13 | 14 | @Test 15 | public void testBTree() { 16 | Utils.TestData data = Utils.generateTestData(1000); 17 | 18 | String bstName = "B-Tree"; 19 | BinaryTree bst = new BinaryTree(2); 20 | Collection bstCollection = bst.toCollection(); 21 | 22 | assertTrue(TreeTest.testTree(bst, Integer.class, bstName, data.unsorted, data.invalid)); 23 | assertTrue(JavaCollectionTest.testCollection(bstCollection, Integer.class, bstName, data.unsorted, data.sorted, 24 | data.invalid)); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /docs/.vuepress/config/baiduCode.js: -------------------------------------------------------------------------------- 1 | module.exports = ''; 2 | -------------------------------------------------------------------------------- /docs/.vuepress/plugins/love-me/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const LoveMyPlugin = (options = {}) => ({ 3 | define() { 4 | const COLOR = 5 | options.color || 6 | 'rgb(' + ~~(255 * Math.random()) + ',' + ~~(255 * Math.random()) + ',' + ~~(255 * Math.random()) + ')' 7 | const EXCLUDECLASS = options.excludeClassName || '' 8 | return { COLOR, EXCLUDECLASS } 9 | }, 10 | enhanceAppFiles: [path.resolve(__dirname, 'love-me.js')], 11 | }) 12 | module.exports = LoveMyPlugin 13 | -------------------------------------------------------------------------------- /docs/.vuepress/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/algorithm-tutorial/54042d4a8f0c00a814107142a81ca7c9d8e2c213/docs/.vuepress/public/favicon.ico -------------------------------------------------------------------------------- /docs/.vuepress/public/img/bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/algorithm-tutorial/54042d4a8f0c00a814107142a81ca7c9d8e2c213/docs/.vuepress/public/img/bg.gif -------------------------------------------------------------------------------- /docs/.vuepress/public/img/bg.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/algorithm-tutorial/54042d4a8f0c00a814107142a81ca7c9d8e2c213/docs/.vuepress/public/img/bg.jpeg -------------------------------------------------------------------------------- /docs/.vuepress/public/img/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/algorithm-tutorial/54042d4a8f0c00a814107142a81ca7c9d8e2c213/docs/.vuepress/public/img/bg.jpg -------------------------------------------------------------------------------- /docs/.vuepress/public/img/dunwu-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/algorithm-tutorial/54042d4a8f0c00a814107142a81ca7c9d8e2c213/docs/.vuepress/public/img/dunwu-logo.png -------------------------------------------------------------------------------- /docs/.vuepress/public/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/algorithm-tutorial/54042d4a8f0c00a814107142a81ca7c9d8e2c213/docs/.vuepress/public/img/favicon.ico -------------------------------------------------------------------------------- /docs/.vuepress/public/img/git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/algorithm-tutorial/54042d4a8f0c00a814107142a81ca7c9d8e2c213/docs/.vuepress/public/img/git.png -------------------------------------------------------------------------------- /docs/.vuepress/public/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/algorithm-tutorial/54042d4a8f0c00a814107142a81ca7c9d8e2c213/docs/.vuepress/public/img/logo.png -------------------------------------------------------------------------------- /docs/.vuepress/public/img/more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/algorithm-tutorial/54042d4a8f0c00a814107142a81ca7c9d8e2c213/docs/.vuepress/public/img/more.png -------------------------------------------------------------------------------- /docs/.vuepress/public/img/other.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/algorithm-tutorial/54042d4a8f0c00a814107142a81ca7c9d8e2c213/docs/.vuepress/public/img/other.png -------------------------------------------------------------------------------- /docs/.vuepress/public/img/panda-waving.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/algorithm-tutorial/54042d4a8f0c00a814107142a81ca7c9d8e2c213/docs/.vuepress/public/img/panda-waving.png -------------------------------------------------------------------------------- /docs/.vuepress/public/img/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/algorithm-tutorial/54042d4a8f0c00a814107142a81ca7c9d8e2c213/docs/.vuepress/public/img/python.png -------------------------------------------------------------------------------- /docs/.vuepress/public/img/ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/algorithm-tutorial/54042d4a8f0c00a814107142a81ca7c9d8e2c213/docs/.vuepress/public/img/ui.png -------------------------------------------------------------------------------- /docs/.vuepress/public/img/web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/algorithm-tutorial/54042d4a8f0c00a814107142a81ca7c9d8e2c213/docs/.vuepress/public/img/web.png -------------------------------------------------------------------------------- /docs/.vuepress/styles/palette.styl: -------------------------------------------------------------------------------- 1 | 2 | // 原主题变量已弃用,以下是vdoing使用的变量,你可以在这个文件内修改它们。 3 | 4 | //***vdoing主题-变量***// 5 | 6 | // // 颜色 7 | 8 | // $bannerTextColor = #fff // 首页banner区(博客标题)文本颜色 9 | // $accentColor = #11A8CD 10 | // $arrowBgColor = #ccc 11 | // $badgeTipColor = #42b983 12 | // $badgeWarningColor = darken(#ffe564, 35%) 13 | // $badgeErrorColor = #DA5961 14 | 15 | // // 布局 16 | // $navbarHeight = 3.6rem 17 | // $sidebarWidth = 18rem 18 | // $contentWidth = 860px 19 | // $homePageWidth = 1100px 20 | // $rightMenuWidth = 230px // 右侧菜单 21 | 22 | // // 代码块 23 | // $lineNumbersWrapperWidth = 2.5rem 24 | 25 | // 浅色模式 26 | .theme-mode-light 27 | --bodyBg: rgba(255,255,255,1) 28 | --mainBg: rgba(255,255,255,1) 29 | --sidebarBg: rgba(255,255,255,.8) 30 | --blurBg: rgba(255,255,255,.9) 31 | --textColor: #004050 32 | --textLightenColor: #0085AD 33 | --borderColor: rgba(0,0,0,.15) 34 | --codeBg: #f6f6f6 35 | --codeColor: #525252 36 | codeThemeLight() 37 | 38 | // 深色模式 39 | .theme-mode-dark 40 | --bodyBg: rgba(30,30,34,1) 41 | --mainBg: rgba(30,30,34,1) 42 | --sidebarBg: rgba(30,30,34,.8) 43 | --blurBg: rgba(30,30,34,.8) 44 | --textColor: rgb(140,140,150) 45 | --textLightenColor: #0085AD 46 | --borderColor: #2C2C3A 47 | --codeBg: #252526 48 | --codeColor: #fff 49 | codeThemeDark() 50 | 51 | // 阅读模式 52 | .theme-mode-read 53 | --bodyBg: rgba(245,245,213,1) 54 | --mainBg: rgba(245,245,213,1) 55 | --sidebarBg: rgba(245,245,213,.8) 56 | --blurBg: rgba(245,245,213,.9) 57 | --textColor: #004050 58 | --textLightenColor: #0085AD 59 | --borderColor: rgba(0,0,0,.15) 60 | --codeBg: #282c34 61 | --codeColor: #fff 62 | codeThemeDark() 63 | -------------------------------------------------------------------------------- /docs/01.数据结构和算法/00.综合/01.数据结构和算法指南.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 数据结构和算法指南 3 | categories: 4 | - 数据结构和算法 5 | - 综合 6 | tags: 7 | - 数据结构 8 | - 算法 9 | abbrlink: e74901af 10 | date: 2015-03-10 18:29:37 11 | permalink: /pages/8b1bd0/ 12 | --- 13 | # 数据结构和算法指南 14 | 15 | ## 1. 为什么学习数据结构和算法 16 | 17 | - **为了找到一份好工作**:大厂面试喜欢考算法 18 | - **更深入了解流行技术的设计思想**:数据结构和算法是计算机基础学科,很多框架、中间、底层系统设的设计,都借鉴了其思想。因此,掌握数据结构和算法,有利于更深入了解这些技术的设计思想。 19 | - 提升个人的编程水平 20 | - 不满足于做业务狗,拓展性能思考的视角 21 | 22 | ## 2. 如何学习数据结构和算法 23 | 24 | 数据结构就是指一组数据的存储结构。算法就是操作数据的一组方法。 25 | 26 | 数据结构和算法是相辅相成的。**数据结构是为算法服务的,算法要作用在特定的数据结构之上。** 27 | 28 | 先要学会复杂度分析,才能识别数据结构和算法的利弊。 29 | 30 | - 循序渐进 31 | - 边学边练,适度刷题 32 | - 学习并思考:学而不思则罔,思而不学则殆 33 | - 知识需要沉淀,不要想试图一下子掌握所有 34 | -------------------------------------------------------------------------------- /docs/01.数据结构和算法/02.树/02.堆.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 堆 3 | categories: 4 | - 数据结构和算法 5 | - 树 6 | tags: 7 | - 数据结构 8 | - 树 9 | - 二叉树 10 | - 堆 11 | abbrlink: fab451a5 12 | date: 2015-03-09 16:01:27 13 | permalink: /pages/ce297c/ 14 | --- 15 | 16 | # 堆 17 | 18 | ## 什么是堆? 19 | 20 | 堆(Heap)是一个可以被看成近似完全二叉树的数组。 21 | 22 | - **堆是一个完全二叉树**。完全二叉树要求,除了最后一层,其他层的节点个数都是满的,最后一层的节点都靠左排列。 23 | - **堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值**。 24 | 25 | 堆可以分为大顶堆和小顶堆。 26 | 27 | - 对于每个节点的值都大于等于子树中每个节点值的堆,叫作“**大顶堆**”。 28 | 29 | - 对于每个节点的值都小于等于子树中每个节点值的堆,叫作“**小顶堆**”。 30 | 31 | ## 如何实现堆 32 | 33 | 完全二叉树比较适合用数组来存储。用数组来存储完全二叉树是非常节省存储空间的。因为我们不需要存储左右子节点的指针,单纯地通过数组的下标,就可以找到一个节点的左右子节点和父节点。 34 | 35 | ![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220311112542.jpg) 36 | 37 | 堆常见的操作: 38 | 39 | - HEAPIFY 建堆:把一个乱序的数组变成堆结构的数组,时间复杂度为 $$O(n)$$。 40 | - HEAPPUSH:把一个数值放进已经是堆结构的数组中,并保持堆结构,时间复杂度为 $$O(log N)$$ 41 | - HEAPPOP:从最大堆中取出最大值或从最小堆中取出最小值,并将剩余的数组保持堆结构,时间复杂度为 $$O(log N)$$。 42 | - HEAPSORT:借由 HEAPFY 建堆和 HEAPPOP 堆数组进行排序,时间复杂度为$$ O(N log N)$$,空间复杂度为 $$O(1)$$。 43 | 44 | ## 堆的应用场景 45 | 46 | ### 求 TOP N 47 | 48 | 堆结构的一个常见应用是建立优先队列(Priority Queue)。 49 | 50 | 求 Top K 的问题抽象成两类。一类是针对静态数据集合;另一类是针对动态数据集合 51 | 52 | ### 优先级队列 53 | 54 | 在优先级队列中,数据的出队顺序不是先进先出,而是按照优先级来,优先级最高的,最先出队。 55 | 56 | 堆和优先级队列非常相似:往优先级队列中插入一个元素,就相当于往堆中插入一个元素;从优先级队列中取出优先级最高的元素,就相当于取出堆顶元素。 57 | 58 | > 参考:Java 的 `PriorityQueue` 类 59 | 60 | ### 求中位数 61 | -------------------------------------------------------------------------------- /docs/@pages/archivesPage.md: -------------------------------------------------------------------------------- 1 | --- 2 | archivesPage: true 3 | title: 归档 4 | permalink: /archives/ 5 | article: false 6 | --- 7 | -------------------------------------------------------------------------------- /docs/@pages/categoriesPage.md: -------------------------------------------------------------------------------- 1 | --- 2 | categoriesPage: true 3 | title: 分类 4 | permalink: /categories/ 5 | article: false 6 | --- 7 | -------------------------------------------------------------------------------- /docs/@pages/tagsPage.md: -------------------------------------------------------------------------------- 1 | --- 2 | tagsPage: true 3 | title: 标签 4 | permalink: /tags/ 5 | article: false 6 | --- 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "algorithm-tutorial", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "clean": "rimraf docs/.temp", 7 | "start": "vuepress dev docs", 8 | "build": "vuepress build docs", 9 | "deploy": "bash scripts/deploy.sh", 10 | "editFm": "node utils/editFrontmatter.js", 11 | "baiduPush": "node utils/baiduPush.js https://xugaoyi.com && bash baiduPush.sh", 12 | "publish": "cd ./vdoing && npm publish && cd .. && yarn updateTheme", 13 | "updateTheme": "yarn remove vuepress-theme-vdoing && rm -rf node_modules && yarn && yarn add vuepress-theme-vdoing -D", 14 | "lint": "markdownlint -r markdownlint-rule-emphasis-style -c docs/.markdownlint.json **/*.md -i node_modules", 15 | "lint:fix": "markdownlint -f -r markdownlint-rule-emphasis-style -c docs/.markdownlint.json **/*.md -i node_modules", 16 | "show-help": "vuepress --help", 17 | "view-info": "vuepress view-info ./ --temp docs/.temp" 18 | }, 19 | "devDependencies": { 20 | "dayjs": "^1.9.7", 21 | "inquirer": "^7.1.0", 22 | "json2yaml": "^1.1.0", 23 | "vuepress": "1.9.5", 24 | "vuepress-plugin-baidu-autopush": "^1.0.1", 25 | "vuepress-plugin-baidu-tongji": "^1.0.1", 26 | "vuepress-plugin-comment": "^0.7.3", 27 | "vuepress-plugin-demo-block": "^0.7.2", 28 | "vuepress-plugin-fulltext-search": "^2.2.1", 29 | "vuepress-plugin-one-click-copy": "^1.0.2", 30 | "vuepress-plugin-thirdparty-search": "^1.0.2", 31 | "vuepress-plugin-zooming": "^1.1.7", 32 | "vuepress-theme-vdoing": "^1.11.2", 33 | "yamljs": "^0.3.0", 34 | "markdownlint-cli": "^0.25.0", 35 | "markdownlint-rule-emphasis-style": "^1.0.1", 36 | "rimraf": "^3.0.1", 37 | "vue-toasted": "^1.1.25" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | io.github.dunwu 8 | algorithm-tutorial 9 | 1.0.0 10 | pom 11 | ALGORITHM-TUTORIAL 12 | algorithm-tutorial 示例源码 13 | 14 | 15 | codes/algorithm 16 | 17 | 18 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @see https://prettier.io/docs/en/options.html 3 | * @see https://prettier.io/docs/en/configuration.html 4 | */ 5 | module.exports = { 6 | tabWidth: 2, semi: false, singleQuote: true 7 | } 8 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # ------------------------------------------------------------------------------ 4 | # gh-pages 部署脚本 5 | # @author Zhang Peng 6 | # @since 2020/2/10 7 | # ------------------------------------------------------------------------------ 8 | 9 | # 装载其它库 10 | ROOT_DIR=$( 11 | cd $(dirname $0)/.. 12 | pwd 13 | ) 14 | 15 | # 确保脚本抛出遇到的错误 16 | set -e 17 | 18 | # 生成静态文件 19 | npm run build 20 | 21 | # 进入生成的文件夹 22 | cd ${ROOT_DIR}/docs/.temp 23 | 24 | # 如果是发布到自定义域名 25 | # echo 'www.example.com' > CNAME 26 | 27 | if [[ ${GITHUB_TOKEN} && ${GITEE_TOKEN} ]]; then 28 | msg='自动部署' 29 | GITHUB_URL=https://dunwu:${GITHUB_TOKEN}@github.com/dunwu/algorithm-tutorial.git 30 | GITEE_URL=https://turnon:${GITEE_TOKEN}@gitee.com/turnon/algorithm-tutorial.git 31 | git config --global user.name "dunwu" 32 | git config --global user.email "forbreak@163.com" 33 | else 34 | msg='手动部署' 35 | GITHUB_URL=git@github.com:dunwu/algorithm-tutorial.git 36 | GITEE_URL=git@gitee.com:turnon/algorithm-tutorial.git 37 | fi 38 | git init 39 | git add -A 40 | git commit -m "${msg}" 41 | # 推送到github gh-pages分支 42 | git push -f "${GITHUB_URL}" master:gh-pages 43 | git push -f "${GITEE_URL}" master:gh-pages 44 | 45 | cd - 46 | rm -rf ${ROOT_DIR}/docs/.temp 47 | -------------------------------------------------------------------------------- /utils/config.yml: -------------------------------------------------------------------------------- 1 | #批量添加和修改、删除front matter配置文件 2 | 3 | # 需要批量处理的路径,docs文件夹内的文件夹 (数组。映射路径:docs/arr[0]/arr[1] ... ) 4 | path: 5 | - docs # 第一个成员必须是docs 6 | 7 | # 要删除的字段 (数组) 8 | delete: 9 | # - test 10 | # - tags 11 | 12 | # 要添加、修改front matter的数据 (front matter中没有的数据则添加,已有的数据则覆盖) 13 | data: 14 | article: false -------------------------------------------------------------------------------- /utils/modules/fn.js: -------------------------------------------------------------------------------- 1 | // 类型判断 2 | exports.type = function (o){ 3 | var s = Object.prototype.toString.call(o) 4 | return s.match(/\[object (.*?)\]/)[1].toLowerCase() 5 | } 6 | 7 | // 修复date时区格式的问题 8 | exports.repairDate = function (date) { 9 | date = new Date(date); 10 | return `${date.getUTCFullYear()}-${zero(date.getUTCMonth()+1)}-${zero(date.getUTCDate())} ${zero(date.getUTCHours())}:${zero(date.getUTCMinutes())}:${zero(date.getUTCSeconds())}`; 11 | } 12 | 13 | // 日期的格式 14 | exports.dateFormat = function (date) { 15 | return `${date.getFullYear()}-${zero(date.getMonth()+1)}-${zero(date.getDate())} ${zero(date.getHours())}:${zero(date.getMinutes())}:${zero(date.getSeconds())}` 16 | } 17 | 18 | // 小于10补0 19 | function zero(d){ 20 | return d.toString().padStart(2,'0') 21 | } -------------------------------------------------------------------------------- /utils/modules/readFileList.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 读取所有md文件数据 3 | */ 4 | const fs = require('fs'); // 文件模块 5 | const path = require('path'); // 路径模块 6 | const docsRoot = path.join(__dirname, '..', '..', 'docs'); // docs文件路径 7 | 8 | function readFileList(dir = docsRoot, filesList = []) { 9 | const files = fs.readdirSync(dir); 10 | files.forEach( (item, index) => { 11 | let filePath = path.join(dir, item); 12 | const stat = fs.statSync(filePath); 13 | if (stat.isDirectory() && item !== '.vuepress') { 14 | readFileList(path.join(dir, item), filesList); //递归读取文件 15 | } else { 16 | if(path.basename(dir) !== 'docs'){ // 过滤docs目录级下的文件 17 | 18 | const fileNameArr = path.basename(filePath).split('.') 19 | let name = null, type = null; 20 | if (fileNameArr.length === 2) { // 没有序号的文件 21 | name = fileNameArr[0] 22 | type = fileNameArr[1] 23 | } else if (fileNameArr.length === 3) { // 有序号的文件 24 | name = fileNameArr[1] 25 | type = fileNameArr[2] 26 | } else { // 超过两个‘.’的 27 | log(chalk.yellow(`warning: 该文件 "${filePath}" 没有按照约定命名,将忽略生成相应数据。`)) 28 | return 29 | } 30 | if(type === 'md'){ // 过滤非md文件 31 | filesList.push({ 32 | name, 33 | filePath 34 | }); 35 | } 36 | 37 | } 38 | } 39 | }); 40 | return filesList; 41 | } 42 | 43 | module.exports = readFileList; --------------------------------------------------------------------------------