9.10 复习+一些juc
This commit is contained in:
parent
8b91ec0731
commit
585a2321f3
3
.gitignore
vendored
3
.gitignore
vendored
@ -33,4 +33,5 @@ Thumbs.db
|
||||
# 忽略其他临时文件
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*.swp
|
||||
/src/main/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/
|
||||
* 链接:<a href="https://leetcode.cn/problems/longest-continuous-increasing-subsequence/">...</a>
|
||||
*/
|
||||
//二刷会做
|
||||
public class FindLengthOfLCIS {
|
||||
|
||||
45
src/main/java/dynamic_programming/MinFallingPathSum.java
Normal file
45
src/main/java/dynamic_programming/MinFallingPathSum.java
Normal file
@ -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<col)
|
||||
dp[i][j]=Math.min(dp[i][j],dp[i-1][j+1]);
|
||||
dp[i][j]=Math.min(dp[i][j],dp[i-1][j])+matrix[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < col; i++) {
|
||||
minPath=Math.min(dp[row-1][i],minPath);
|
||||
}
|
||||
return minPath;
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,6 @@
|
||||
package graph;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 题目: 207. 课程表 (canFinish)
|
||||
@ -40,7 +37,6 @@ public class CanFinish {
|
||||
List<List<Integer>> graph = new ArrayList<>();
|
||||
// 记录每个课程的入度(即需要先修课程的数量)
|
||||
int[] indegree = new int[numCourses];
|
||||
|
||||
// 初始化图
|
||||
for (int i = 0; i < numCourses; i++) {
|
||||
graph.add(new ArrayList<>());
|
||||
|
||||
76
src/main/java/graph/LongestIncreasingPath.java
Normal file
76
src/main/java/graph/LongestIncreasingPath.java
Normal file
@ -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];
|
||||
}
|
||||
}
|
||||
38
src/main/java/juc/BlockingqueueTest.java
Normal file
38
src/main/java/juc/BlockingqueueTest.java
Normal file
@ -0,0 +1,38 @@
|
||||
package juc;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class BlockingqueueTest {
|
||||
private static final BlockingQueue<String> 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();
|
||||
}
|
||||
}
|
||||
18
src/main/java/juc/Countdownlatch.java
Normal file
18
src/main/java/juc/Countdownlatch.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
24
src/main/java/juc/SemaphoreTest.java
Normal file
24
src/main/java/juc/SemaphoreTest.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
42
src/main/java/juc/test.java
Normal file
42
src/main/java/juc/test.java
Normal file
@ -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<target){
|
||||
synchronized (lock){
|
||||
if(count%2==0) {
|
||||
System.out.println("thread1:" + count++);
|
||||
lock.notify();
|
||||
}else {
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},"thread1").start();
|
||||
new Thread(()->{
|
||||
while (count<target){
|
||||
synchronized (lock){
|
||||
if(count%2==1) {
|
||||
System.out.println("thread2:" + count++);
|
||||
lock.notify();
|
||||
}else {
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},"thread2").start();
|
||||
}
|
||||
}
|
||||
@ -13,7 +13,6 @@ import java.util.List;
|
||||
//二刷会做
|
||||
public class IsPalindrome {
|
||||
public boolean isPalindrome1(ListNode head) {
|
||||
ListNode temp=head;
|
||||
List<Integer>list=new ArrayList<>();
|
||||
while (head!=null){
|
||||
list.add(head.val);
|
||||
|
||||
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
50
src/main/java/linkedlist/ReorderList.java
Normal file
50
src/main/java/linkedlist/ReorderList.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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] 这一段,返回新的头和新的尾
|
||||
|
||||
11
src/main/java/sort/ListNode.java
Normal file
11
src/main/java/sort/ListNode.java
Normal file
@ -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; }
|
||||
}
|
||||
133
src/main/java/sort/Test.java
Normal file
133
src/main/java/sort/Test.java
Normal file
@ -0,0 +1,133 @@
|
||||
package sort;
|
||||
import java.util.Random;
|
||||
|
||||
public class Test {
|
||||
public void quicksort(int[] arr,int left,int right){
|
||||
if(left<right) {
|
||||
int pos = partition(arr, left, right);
|
||||
quicksort(arr,left,pos-1);
|
||||
quicksort(arr,pos+1,right);
|
||||
}
|
||||
}
|
||||
int partition(int[] arr,int left,int right){
|
||||
Random random=new Random();
|
||||
int start=random.nextInt(right-left+1)+left;
|
||||
int temp=arr[left];
|
||||
arr[left]=arr[start];
|
||||
arr[start]=temp;
|
||||
int pivot=arr[left];
|
||||
int l=left,r=right;
|
||||
while (l<r){
|
||||
while (l<r && arr[r]>=pivot) {
|
||||
r--;
|
||||
}
|
||||
arr[l]=arr[r];
|
||||
while (l<r && arr[l]<=pivot)
|
||||
l++;
|
||||
arr[r]=arr[l];
|
||||
}
|
||||
arr[l]=pivot;
|
||||
return l;
|
||||
}
|
||||
public int quickselect(int[] arr,int left,int right,int target){
|
||||
if(left<=right){
|
||||
int pos=partition(arr,left,right);
|
||||
if(target==pos) return arr[pos];
|
||||
else if(target>pos)
|
||||
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<right){
|
||||
int mid=(left+right)/2;
|
||||
mergeSort(arr,left,mid);
|
||||
mergeSort(arr,mid+1,right);
|
||||
merge(arr,left,mid,right);
|
||||
}
|
||||
}
|
||||
public void merge(int[]arr,int left,int mid,int right){
|
||||
int idx1=left;
|
||||
int idx2=mid+1;
|
||||
int[] temp=new int[right-left+1];
|
||||
int idx=0;
|
||||
while (idx1<=mid && idx2<=right){
|
||||
if(arr[idx1]<=arr[idx2]) {
|
||||
temp[idx++] = arr[idx1];
|
||||
idx1++;
|
||||
}
|
||||
else {
|
||||
temp[idx++]=arr[idx2];
|
||||
idx2++;
|
||||
}
|
||||
}
|
||||
while(idx1<=mid) {
|
||||
temp[idx++] = arr[idx1];
|
||||
idx1++;
|
||||
}
|
||||
while(idx2<=right) {
|
||||
temp[idx++] = arr[idx2];
|
||||
idx2++;
|
||||
}
|
||||
for (int i = 0; i < temp.length; i++) {
|
||||
arr[left + i] = temp[i];
|
||||
}
|
||||
}
|
||||
|
||||
void bubble(int[]arr){
|
||||
for (int i = 0; i < arr.length-1; i++) {
|
||||
boolean flag=false;
|
||||
for (int j = arr.length-1; j > i; j--) {
|
||||
if(arr[j]<arr[j-1]){
|
||||
flag=true;
|
||||
int temp=arr[j];
|
||||
arr[j]=arr[j-1];
|
||||
arr[j-1]=temp;
|
||||
}
|
||||
}
|
||||
if(!flag)return;
|
||||
}
|
||||
}
|
||||
ListNode findMidNode(ListNode head){
|
||||
ListNode fast=head.next,slow=head;
|
||||
while (fast!=null &&fast.next!=null){
|
||||
fast=fast.next.next;
|
||||
slow=slow.next;
|
||||
}
|
||||
return slow;
|
||||
}
|
||||
|
||||
ListNode linkMergeSort(ListNode head) {
|
||||
if (head == null || head.next == null) return head;
|
||||
ListNode mid = findMidNode(head);
|
||||
ListNode head2 = mid.next;
|
||||
mid.next = null;
|
||||
|
||||
ListNode left = linkMergeSort(head);
|
||||
ListNode right = linkMergeSort(head2);
|
||||
return mergeLink(left, right);
|
||||
}
|
||||
|
||||
ListNode mergeLink(ListNode l1, ListNode l2) {
|
||||
ListNode dummy = new ListNode(-1), cur = dummy;
|
||||
while (l1 != null && l2 != null) {
|
||||
if (l1.val <= l2.val) {
|
||||
cur.next = l1;
|
||||
l1 = l1.next;
|
||||
} else {
|
||||
cur.next = l2;
|
||||
l2 = l2.next;
|
||||
}
|
||||
cur = cur.next;
|
||||
}
|
||||
cur.next = (l1 != null ? l1 : l2);
|
||||
return dummy.next;
|
||||
}
|
||||
}
|
||||
@ -27,9 +27,37 @@ import java.util.*;
|
||||
输入:nums = [1], k = 1
|
||||
输出:[1]
|
||||
*/
|
||||
//本题求的是每个滑动窗口中最大的数字!!!
|
||||
//普通方法超时 需重做
|
||||
//二刷也没想到低复杂度方法
|
||||
public class MaxSlidingWindow {
|
||||
|
||||
/**
|
||||
* 普通法 暴力求解
|
||||
*/
|
||||
public int[] maxSlidingWindowBruteForce(int[] nums, int k) {
|
||||
if (nums == null || nums.length == 0 || k <= 0) {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
int n = nums.length;
|
||||
int[] ans = new int[n - k + 1];
|
||||
|
||||
for (int i = 0; i <= n - k; i++) {
|
||||
int maxVal = nums[i];
|
||||
// 遍历当前窗口 [i, i+k-1]
|
||||
for (int j = i; j < i + k; j++) {
|
||||
if (nums[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();
|
||||
}
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@ public class Flatten {
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
Deque<TreeNode> stack = new LinkedList<TreeNode>();
|
||||
Deque<TreeNode> stack = new LinkedList<>();
|
||||
stack.push(root);
|
||||
TreeNode prev = null;
|
||||
while (!stack.isEmpty()) {
|
||||
|
||||
@ -42,7 +42,7 @@ public class PathSum {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
int ret;
|
||||
// 更新当前累计前缀和:加上当前节点的值
|
||||
curr += root.val;
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
55
src/main/java/实现类功能/MyHashMap.java
Normal file
55
src/main/java/实现类功能/MyHashMap.java
Normal file
@ -0,0 +1,55 @@
|
||||
package 实现类功能;
|
||||
/*
|
||||
数组(table):核心结构,存储键值对(Entry)的桶(bucket)。
|
||||
链表:当多个键的哈希值落在同一个桶中时,会形成一个链表。
|
||||
*/
|
||||
class MyHashMap<K, V> {
|
||||
static class Node<K, V> {
|
||||
K key;
|
||||
V value;
|
||||
Node<K, V> next;
|
||||
|
||||
Node(K k, V v) {
|
||||
key = k;
|
||||
value = v;
|
||||
}
|
||||
}
|
||||
|
||||
private int SIZE = 16;
|
||||
private Node<K, V>[] table = new Node[SIZE];
|
||||
|
||||
public void put(K key, V value) {
|
||||
int index = key.hashCode() % SIZE;
|
||||
Node<K, V> newNode = new Node<>(key, value);
|
||||
|
||||
Node<K, V> 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<K, V> curr = table[index];
|
||||
while (curr != null) {
|
||||
if (curr.key.equals(key)) {
|
||||
return curr.value;
|
||||
}
|
||||
curr = curr.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user