From 585a2321f303519dd65957704a4c03294fc97b80 Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Wed, 10 Sep 2025 20:57:03 +0800 Subject: [PATCH] =?UTF-8?q?9.10=20=E5=A4=8D=E4=B9=A0+=E4=B8=80=E4=BA=9Bjuc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- .../dynamic_programming/FindLengthOfLCIS.java | 4 +- .../MinFallingPathSum.java | 45 ++++++ src/main/java/graph/CanFinish.java | 6 +- .../java/graph/LongestIncreasingPath.java | 76 ++++++++++ src/main/java/juc/BlockingqueueTest.java | 38 +++++ src/main/java/juc/Countdownlatch.java | 18 +++ src/main/java/juc/SemaphoreTest.java | 24 ++++ src/main/java/juc/test.java | 42 ++++++ src/main/java/linkedlist/IsPalindrome.java | 1 - src/main/java/linkedlist/MergeKLists.java | 51 +++---- src/main/java/linkedlist/ReorderList.java | 50 +++++++ src/main/java/linkedlist/ReverseKGroup.java | 14 +- src/main/java/sort/ListNode.java | 11 ++ src/main/java/sort/Test.java | 133 ++++++++++++++++++ src/main/java/substring/MaxSlidingWindow.java | 36 ++++- src/main/java/tree/Flatten.java | 2 +- src/main/java/tree/PathSum.java | 2 +- src/main/java/实现类功能/LRUCache.java | 3 +- src/main/java/实现类功能/MyHashMap.java | 55 ++++++++ 20 files changed, 559 insertions(+), 55 deletions(-) create mode 100644 src/main/java/dynamic_programming/MinFallingPathSum.java create mode 100644 src/main/java/graph/LongestIncreasingPath.java create mode 100644 src/main/java/juc/BlockingqueueTest.java create mode 100644 src/main/java/juc/Countdownlatch.java create mode 100644 src/main/java/juc/SemaphoreTest.java create mode 100644 src/main/java/juc/test.java create mode 100644 src/main/java/linkedlist/ReorderList.java create mode 100644 src/main/java/sort/ListNode.java create mode 100644 src/main/java/sort/Test.java create mode 100644 src/main/java/实现类功能/MyHashMap.java diff --git a/.gitignore b/.gitignore index d0385bf..8966385 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,5 @@ Thumbs.db # 忽略其他临时文件 *.tmp *.bak -*.swp \ No newline at end of file +*.swp +/src/main/java/大厂真题/ diff --git a/src/main/java/dynamic_programming/FindLengthOfLCIS.java b/src/main/java/dynamic_programming/FindLengthOfLCIS.java index d7660bd..f1355fd 100644 --- a/src/main/java/dynamic_programming/FindLengthOfLCIS.java +++ b/src/main/java/dynamic_programming/FindLengthOfLCIS.java @@ -6,14 +6,12 @@ import java.util.Arrays; * 题目: 674. 最长连续递增序列 (MaxProduct) * 描述:给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。 * 连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。 - * 示例 1: 输入:nums = [1,3,5,4,7] 输出:3 解释:最长连续递增序列是 [1,3,5], 长度为3。 尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。 - - * 链接:https://leetcode.cn/problems/longest-continuous-increasing-subsequence/ + * 链接:... */ //二刷会做 public class FindLengthOfLCIS { diff --git a/src/main/java/dynamic_programming/MinFallingPathSum.java b/src/main/java/dynamic_programming/MinFallingPathSum.java new file mode 100644 index 0000000..76114fd --- /dev/null +++ b/src/main/java/dynamic_programming/MinFallingPathSum.java @@ -0,0 +1,45 @@ +package dynamic_programming; +/** + * 题目:931. 下降路径最小和 (minFallingPathSum) + * 描述:给你一个 n x n 的 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径 的 最小和 。 + * + * 下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。 + * 具体来说,位置 (row, col) 的下一个元素应当是 (row + 1, col - 1)、(row + 1, col) 或者 (row + 1, col + 1) 。 + * + * 链接:https://leetcode.cn/problems/minimum-falling-path-sum/ + * + 输入:matrix = [[2,1,3],[6,5,4],[7,8,9]] + 输出:13 + 解释:如图所示,为和最小的两条下降路径 + + */ +public class MinFallingPathSum { + + public int minFallingPathSum(int[][] matrix) { + int minPath=Integer.MAX_VALUE; + int row=matrix.length,col=matrix[0].length; + int[][]dp=new int[row][col]; + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + dp[i][j]=Integer.MAX_VALUE; + } + } + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + if(i==0) { + dp[0][j] = matrix[0][j]; + }else { + if(j-1>=0) + dp[i][j]=Math.min(dp[i][j],dp[i-1][j-1]); + if(j+1> graph = new ArrayList<>(); // 记录每个课程的入度(即需要先修课程的数量) int[] indegree = new int[numCourses]; - // 初始化图 for (int i = 0; i < numCourses; i++) { graph.add(new ArrayList<>()); diff --git a/src/main/java/graph/LongestIncreasingPath.java b/src/main/java/graph/LongestIncreasingPath.java new file mode 100644 index 0000000..0b580fb --- /dev/null +++ b/src/main/java/graph/LongestIncreasingPath.java @@ -0,0 +1,76 @@ +package graph; +/** + * 题目:329. 矩阵中的最长递增路径 (longestIncreasingPath) + * 描述:给定一个 m x n 整数矩阵 matrix ,找出其中 最长递增路径 的长度。 + * 对于每个单元格,你可以往上,下,左,右四个方向移动。 你 不能 在 对角线 方向上移动或移动到 边界外(即不允许环绕)。 + * + * 链接:https://leetcode.cn/problems/longest-increasing-path-in-a-matrix/ + * + 输入:matrix = [[9,9,4],[6,6,8],[2,1,1]] + 输出:4 + 解释:最长递增路径为 [1, 2, 6, 9]。 + + */ +public class LongestIncreasingPath { + // 上、下、左、右四个方向 + public int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; + public int rows, columns; + + /** + * 主函数:计算矩阵中的最长递增路径 + */ + public int longestIncreasingPath(int[][] matrix) { + // 边界条件:空矩阵直接返回 0 + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { + return 0; + } + + rows = matrix.length; + columns = matrix[0].length; + + // 记忆化数组:memo[i][j] 表示从 (i,j) ‘出发’的最长递增路径长度 + int[][] memo = new int[rows][columns]; + + int ans = 0; + // 遍历所有格子,分别作为起点,取最大值 + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < columns; ++j) { + ans = Math.max(ans, dfs(matrix, i, j, memo)); + } + } + return ans; + } + + /** + * 深度优先搜索 + 记忆化 + * @param row 当前行 + * @param column 当前列 + * @return 从 (row, column) 出发的最长递增路径长度 + */ + public int dfs(int[][] matrix, int row, int column, int[][] memo) { + // 如果已经计算过,直接返回 + if (memo[row][column] != 0) { + return memo[row][column]; + } + + // 默认长度至少为 1(当前格子本身) + memo[row][column] = 1; + + // 向四个方向探索 + for (int[] dir : dirs) { + int newRow = row + dir[0], newColumn = column + dir[1]; + // 检查边界,且必须是严格递增 + if (newRow >= 0 && newRow < rows && + newColumn >= 0 && newColumn < columns && + matrix[newRow][newColumn] > matrix[row][column]) { + + // 更新最大路径长度 + memo[row][column] = Math.max( + memo[row][column], + dfs(matrix, newRow, newColumn, memo) + 1 + ); + } + } + return memo[row][column]; + } +} \ No newline at end of file diff --git a/src/main/java/juc/BlockingqueueTest.java b/src/main/java/juc/BlockingqueueTest.java new file mode 100644 index 0000000..e36850b --- /dev/null +++ b/src/main/java/juc/BlockingqueueTest.java @@ -0,0 +1,38 @@ +package juc; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +public class BlockingqueueTest { + private static final BlockingQueue queue = new LinkedBlockingQueue<>(); + + public static void main(String[] args) { + // 生产者线程 + Thread producer = new Thread(() -> { + try { + for (int i = 1; i <= 5; i++) { + String msg = "Message-" + i; + queue.put(msg); // 放入队列 + System.out.println("Produced: " + msg); + Thread.sleep(300); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }); + + // 消费者线程 + Thread consumer = new Thread(() -> { + try { + while (true) { + String msg = queue.take(); // 从队列取出 + System.out.println("Consumed: " + msg); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }); + + producer.start(); + consumer.start(); + } +} diff --git a/src/main/java/juc/Countdownlatch.java b/src/main/java/juc/Countdownlatch.java new file mode 100644 index 0000000..94c0bc3 --- /dev/null +++ b/src/main/java/juc/Countdownlatch.java @@ -0,0 +1,18 @@ +package juc; + +import java.util.concurrent.CountDownLatch; + +public class Countdownlatch { + public static void main(String[] args) throws InterruptedException { + CountDownLatch latch=new CountDownLatch(3); + Runnable runnable=()->{ + System.out.println("hello"); + latch.countDown(); + }; + for (int i = 0; i < 3; i++) { + new Thread(runnable,"thread"+i+":").start(); + } + latch.await(); + System.out.println("main"); + } +} diff --git a/src/main/java/juc/SemaphoreTest.java b/src/main/java/juc/SemaphoreTest.java new file mode 100644 index 0000000..9e89e81 --- /dev/null +++ b/src/main/java/juc/SemaphoreTest.java @@ -0,0 +1,24 @@ +package juc; + +import java.util.concurrent.Semaphore; + +public class SemaphoreTest { + static Semaphore semaphore=new Semaphore(3); + + public static void main(String[] args) { + Runnable task1=()->{ + try { + semaphore.acquire(); + System.out.println("get"); + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + semaphore.release(); + } + }; + for (int i = 0; i < 5; i++) { + new Thread(task1).start(); + } + } +} diff --git a/src/main/java/juc/test.java b/src/main/java/juc/test.java new file mode 100644 index 0000000..2e913d6 --- /dev/null +++ b/src/main/java/juc/test.java @@ -0,0 +1,42 @@ +package juc; + +public class test { + public static final Object lock=new Object(); + public static int target=100; + private static int count = 1; + + public static void main(String[] args) { + new Thread(()->{ + while (count{ + while (countlist=new ArrayList<>(); while (head!=null){ list.add(head.val); diff --git a/src/main/java/linkedlist/MergeKLists.java b/src/main/java/linkedlist/MergeKLists.java index fc49f18..f91ae9b 100644 --- a/src/main/java/linkedlist/MergeKLists.java +++ b/src/main/java/linkedlist/MergeKLists.java @@ -19,49 +19,32 @@ package linkedlist; */ //二刷不会 public class MergeKLists { - //两两合并 - public ListNode mergeKLists2(ListNode[] lists) { - ListNode ans = null; - for (int i = 0; i < lists.length; ++i) { - ans = mergeTwoLists(ans, lists[i]); - } - return ans; - } public ListNode mergeTwoLists(ListNode a, ListNode b) { - if (a == null || b == null) { - return a != null ? a : b; + ListNode dummy = new ListNode(-1), p = dummy; + while (a != null && b != null) { + if (a.val <= b.val) { p.next = a; a = a.next; } + else { p.next = b; b = b.next; } + p = p.next; } - ListNode head = new ListNode(0); - ListNode tail = head, aPtr = a, bPtr = b; - while (aPtr != null && bPtr != null) { - if (aPtr.val < bPtr.val) { - tail.next = aPtr; - aPtr = aPtr.next; - } else { - tail.next = bPtr; - bPtr = bPtr.next; - } - tail = tail.next; - } - tail.next = (aPtr != null ? aPtr : bPtr); - return head.next; + p.next = (a != null ? a : b); + return dummy.next; } - //分治合并 + // 分治合并入口 public ListNode mergeKLists(ListNode[] lists) { - return merge(lists, 0, lists.length - 1); + return mergeRange(lists, 0, lists.length - 1); } - public ListNode merge(ListNode[] lists, int l, int r) { - if (l == r) { - return lists[l]; - } - if (l > r) { - return null; - } + // 分治合并区间 [l, r] + private ListNode mergeRange(ListNode[] lists, int l, int r) { + if (l == r) return lists[l]; + if (l > r) return null; int mid = (l + r) >> 1; - return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r)); + return mergeTwoLists( + mergeRange(lists, l, mid), + mergeRange(lists, mid + 1, r) + ); } } diff --git a/src/main/java/linkedlist/ReorderList.java b/src/main/java/linkedlist/ReorderList.java new file mode 100644 index 0000000..82574df --- /dev/null +++ b/src/main/java/linkedlist/ReorderList.java @@ -0,0 +1,50 @@ +package linkedlist; +/** + * 题目:206. 反转链表 (reorderList) + * 描述:给定一个单链表 L 的头节点 head ,单链表 L 表示为: + * L0 → L1 → … → Ln - 1 → Ln + * 请将其重新排列后变为: + * L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … + * 不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 + + * 链接:https://leetcode.cn/problems/reorder-list/ + + */ +public class ReorderList { + ListNode findMid(ListNode node){ + if (node == null || node.next == null) return node; + ListNode slow=node,fast=node.next; + while (fast!=null && fast.next!=null){ + slow=slow.next; + fast=fast.next.next; + } + return slow; + } + ListNode reverse(ListNode node){ + ListNode pre=null; + ListNode cur=node; + while (cur!=null){ + ListNode next=cur.next; + cur.next=pre; + pre=cur; + cur=next; + } + return pre; + } + public void reorderList(ListNode head) { + ListNode midNode=findMid(head); + ListNode head2=reverse(midNode.next); + + midNode.next = null; + + + while (head2!=null){ + ListNode nx1=head.next; + ListNode nx2=head2.next; + head.next=head2; + head2.next=nx1; + head=nx1; + head2=nx2; + } + } +} diff --git a/src/main/java/linkedlist/ReverseKGroup.java b/src/main/java/linkedlist/ReverseKGroup.java index 2d99a36..e7c9faf 100644 --- a/src/main/java/linkedlist/ReverseKGroup.java +++ b/src/main/java/linkedlist/ReverseKGroup.java @@ -1,13 +1,17 @@ package linkedlist; /** - * 题目: 82. 删除排序链表中的重复元素 II (deleteDuplicates) - * 描述:给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。 + * 题目: 25. K 个一组翻转链表 (ReverseKGroup) + * 描述:给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。 + * + * k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 + * + * 你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。 示例 2: - 输入:head = [1,2,3,3,4,4,5] - 输出:[1,2,5] + 输入:head = [1,2,3,4,5], k = 2 + 输出:[2,1,4,3,5] - * 链接:https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/ + * 链接:https://leetcode.cn/problems/reverse-nodes-in-k-group/ */ public class ReverseKGroup { // 反转 [head, tail] 这一段,返回新的头和新的尾 diff --git a/src/main/java/sort/ListNode.java b/src/main/java/sort/ListNode.java new file mode 100644 index 0000000..9e52b5d --- /dev/null +++ b/src/main/java/sort/ListNode.java @@ -0,0 +1,11 @@ +package sort; + +public class ListNode { + int val; + ListNode next; + ListNode(int x) { + val = x; + next = null; + } + ListNode(int val, ListNode next) { this.val = val; this.next = next; } +} diff --git a/src/main/java/sort/Test.java b/src/main/java/sort/Test.java new file mode 100644 index 0000000..e01f594 --- /dev/null +++ b/src/main/java/sort/Test.java @@ -0,0 +1,133 @@ +package sort; +import java.util.Random; + +public class Test { + public void quicksort(int[] arr,int left,int right){ + if(left=pivot) { + r--; + } + arr[l]=arr[r]; + while (lpos) + return quickselect(arr,pos+1,right,target); + else + return quickselect(arr,left,pos-1,target); + } + return -1; + } + + void MergeSort(int[]arr){ + mergeSort(arr,0,arr.length-1); + } + + public void mergeSort(int[] arr,int left,int right){ + if(left i; j--) { + if(arr[j] maxVal) { + maxVal = nums[j]; + } + } + ans[i] = maxVal; + } + + return ans; + } + + /** * 思路说明:用优先队列(大顶堆)维护滑动窗口中的最大值 * 滑动窗口长度为 k,我们每次都想拿到窗口内的最大值。 @@ -81,10 +109,12 @@ public class MaxSlidingWindow { * 维护一个单调队列。 在这个滑动窗口最大值的算法中,双端队列的两端各自承担不同的职责: 队头(Deque Front): - 队头始终保存当前窗口内最大元素的索引。由于我们维护队列中元素对应的数值是单调递减的,所以队头的元素必定是最大的。当窗口滑动时,如果队头的索引超出窗口范围,会将其移除,以保证队头始终代表当前窗口的最大值。 + 队头始终保存当前窗口内最大元素的索引。由于我们维护队列中元素对应的数值是单调递减的,所以队头的元素必定是最大的。 + 当窗口滑动时,如果队头的索引超出窗口范围,会将其移除,以保证队头始终代表当前窗口的最大值。 队尾(Deque Rear): - 队尾用于存放候选的元素索引,它们按照数值从大到小的顺序排列。在加入新元素前,会从队尾移除所有比新元素小的元素索引,因为这些较小的元素在未来的窗口中不可能成为最大值。这样既保证了队列的单调递减性质,也为未来的窗口维护了正确的候选顺序。 + 队尾用于存放候选的元素索引,它们按照数值从大到小的顺序排列。在加入新元素前,会从队尾移除所有比新元素小的元素索引, + 因为这些较小的元素在未来的窗口中不可能成为最大值。这样既保证了队列的单调递减性质,也为未来的窗口维护了正确的候选顺序。 */ public int[] maxSlidingWindow(int[] nums, int k) { int n = nums.length; @@ -117,7 +147,7 @@ public class MaxSlidingWindow { deque.offerLast(i); // 如果队头的下标已经滑出窗口左边,就移除它 - while (deque.peekFirst() <= i - k) { + while (!deque.isEmpty() && deque.peekFirst() <= i - k) { deque.pollFirst(); } diff --git a/src/main/java/tree/Flatten.java b/src/main/java/tree/Flatten.java index d08af07..953e441 100644 --- a/src/main/java/tree/Flatten.java +++ b/src/main/java/tree/Flatten.java @@ -40,7 +40,7 @@ public class Flatten { if (root == null) { return; } - Deque stack = new LinkedList(); + Deque stack = new LinkedList<>(); stack.push(root); TreeNode prev = null; while (!stack.isEmpty()) { diff --git a/src/main/java/tree/PathSum.java b/src/main/java/tree/PathSum.java index b7921ea..800d2a3 100644 --- a/src/main/java/tree/PathSum.java +++ b/src/main/java/tree/PathSum.java @@ -42,7 +42,7 @@ public class PathSum { return 0; } - int ret = 0; + int ret; // 更新当前累计前缀和:加上当前节点的值 curr += root.val; diff --git a/src/main/java/实现类功能/LRUCache.java b/src/main/java/实现类功能/LRUCache.java index 69c6800..2a23ee8 100644 --- a/src/main/java/实现类功能/LRUCache.java +++ b/src/main/java/实现类功能/LRUCache.java @@ -5,7 +5,8 @@ package 实现类功能; * 实现 LRUCache 类: * LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 * int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。 - * void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。 + * void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。 + * 如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。 * 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。 示例 1: diff --git a/src/main/java/实现类功能/MyHashMap.java b/src/main/java/实现类功能/MyHashMap.java new file mode 100644 index 0000000..8e45c2c --- /dev/null +++ b/src/main/java/实现类功能/MyHashMap.java @@ -0,0 +1,55 @@ +package 实现类功能; +/* +数组(table):核心结构,存储键值对(Entry)的桶(bucket)。 +链表:当多个键的哈希值落在同一个桶中时,会形成一个链表。 + */ +class MyHashMap { + static class Node { + K key; + V value; + Node next; + + Node(K k, V v) { + key = k; + value = v; + } + } + + private int SIZE = 16; + private Node[] table = new Node[SIZE]; + + public void put(K key, V value) { + int index = key.hashCode() % SIZE; + Node newNode = new Node<>(key, value); + + Node curr = table[index]; + if (curr == null) { + table[index] = newNode; + } else { + while (true) { + if (curr.key.equals(key)) { + curr.value = value; + return; + } + if (curr.next == null) { + curr.next = newNode; + return; + } + curr = curr.next; + } + } + } + + public V get(K key) { + int index = key.hashCode() % SIZE; + Node curr = table[index]; + while (curr != null) { + if (curr.key.equals(key)) { + return curr.value; + } + curr = curr.next; + } + return null; + } +} +