mirror of
https://gitee.com/yudaocode/SpringBoot-Labs.git
synced 2026-09-03 05:53:54 +08:00
删除和 Spring Boot Labs 无关的项目
This commit is contained in:
@@ -385,18 +385,10 @@
|
||||
|
||||
如下是草稿目录,未来需要整理下
|
||||
|
||||
# lab-08
|
||||
|
||||
简单测试,Tomcat + Redis 提供最小接口,看看 QPS
|
||||
|
||||
# lab-9
|
||||
|
||||
记录阅读极客时间《数据结构与算法之美》的题目。
|
||||
|
||||
# lab-10
|
||||
|
||||
Spring Boot 优雅关闭示例。
|
||||
|
||||
# lab-50
|
||||
|
||||
Email 示例
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.4.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>lab-08</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||
<!-- <artifa ctId>spring-boot-starter-data-jpa</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-redis</artifactId>
|
||||
<version>1.4.7.RELEASE</version>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.data</groupId>-->
|
||||
<!-- <artifactId>spring-data-redis</artifactId>-->
|
||||
<!-- <version>2.1.6.RELEASE</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -1,13 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab08;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class UserApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(UserApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab08;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/user")
|
||||
public class UserController {
|
||||
|
||||
@Autowired
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@GetMapping("/get_user_id")
|
||||
public String getUserId(@RequestParam("token") String token) {
|
||||
String userIdStr = stringRedisTemplate.opsForValue().get(token);
|
||||
if (userIdStr != null) {
|
||||
// return Integer.valueOf(userIdStr);
|
||||
return userIdStr;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
spring:
|
||||
application:
|
||||
name: user-application
|
||||
# jpa
|
||||
redis:
|
||||
password:
|
||||
database: 0
|
||||
port: 6379
|
||||
host: 127.0.0.1
|
||||
timeout: 0
|
||||
jedis:
|
||||
pool:
|
||||
max-wait:
|
||||
max-idle: 8
|
||||
min-idle: 0
|
||||
|
||||
|
||||
# server
|
||||
server:
|
||||
port: 16003
|
||||
servlet:
|
||||
context-path: /user-api/
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>labs-parent</artifactId>
|
||||
<groupId>cn.iocoder.springboot.labs</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>lab-09</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -1,71 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.graph;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class DijkstraTest {
|
||||
|
||||
public static class Graph {
|
||||
|
||||
/**
|
||||
* 顶点的个数
|
||||
*/
|
||||
private int v;
|
||||
/**
|
||||
* 邻接表
|
||||
*/
|
||||
private List<Edge>[] adj;
|
||||
|
||||
public Graph(int v) {
|
||||
this.v = v;
|
||||
adj = new LinkedList[v];
|
||||
for (int i = 0; i < v; i++) {
|
||||
adj[i] = new LinkedList<>();
|
||||
}
|
||||
}
|
||||
|
||||
public void addEdge(int s, int t, int w) {
|
||||
adj[s].add(new Edge(s, t, w));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Edge {
|
||||
|
||||
/**
|
||||
* 来源顶点
|
||||
*/
|
||||
private int s;
|
||||
/**
|
||||
* 目标顶点
|
||||
*/
|
||||
private int t;
|
||||
/**
|
||||
* 权重(距离)
|
||||
*/
|
||||
private int w;
|
||||
|
||||
public Edge(int s, int t, int w) {
|
||||
this.s = s;
|
||||
this.t = t;
|
||||
this.w = w;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Vertex {
|
||||
|
||||
/**
|
||||
* 顶点编号 id
|
||||
*/
|
||||
private int id;
|
||||
|
||||
/**
|
||||
* 从起始顶点,到达此处的最短距离。
|
||||
*/
|
||||
private int dist;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.graph;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class Graph {
|
||||
|
||||
/**
|
||||
* 顶点的个数
|
||||
*/
|
||||
private int v;
|
||||
/**
|
||||
* 邻接表
|
||||
*/
|
||||
private List<Integer>[] adj;
|
||||
|
||||
public Graph(int v) {
|
||||
this.v = v;
|
||||
adj = new LinkedList[v];
|
||||
for (int i = 0; i < v; i++) {
|
||||
adj[i] = new LinkedList<>();
|
||||
}
|
||||
}
|
||||
|
||||
public void addEdge(int s, int t) {
|
||||
adj[s].add(t);
|
||||
adj[t].add(s);
|
||||
}
|
||||
|
||||
public void print() {
|
||||
for (int i = 0; i < v; i++) {
|
||||
System.out.print(i + " :");
|
||||
System.out.println(adj[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void bfs(int s, int t) {
|
||||
if (s == t) {
|
||||
throw new IllegalStateException("参数不合理");
|
||||
}
|
||||
// 初始化已访问
|
||||
boolean[] visited = new boolean[v];
|
||||
visited[s] = true;
|
||||
|
||||
// 当前走到的路径
|
||||
Queue<Integer> queue = new LinkedList<>();
|
||||
queue.add(s);
|
||||
|
||||
// 记录哪个节点走到这里。通过它,实现路径的记录
|
||||
int[] prev = new int[v];
|
||||
Arrays.fill(prev, -1);
|
||||
|
||||
while (queue.size() != 0) {
|
||||
int w = queue.poll();
|
||||
for (int i = 0; i < adj[w].size(); i++) {
|
||||
int q = adj[w].get(i);
|
||||
if (!visited[q]) {
|
||||
// 记录是从 w 走到 q
|
||||
prev[q] = w;
|
||||
// 判断是否到达目的地
|
||||
if (q == t) {
|
||||
print(prev, s, t);
|
||||
return;
|
||||
}
|
||||
visited[q] = true;
|
||||
queue.add(q);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void dfs(int s, int t) {
|
||||
if (s == t) {
|
||||
throw new IllegalStateException("参数不合理");
|
||||
}
|
||||
// 创建,标记是否找到
|
||||
AtomicBoolean found = new AtomicBoolean(false);
|
||||
|
||||
// 初始化已访问
|
||||
boolean[] visited = new boolean[v];
|
||||
|
||||
// 记录哪个节点走到这里。通过它,实现路径的记录
|
||||
int[] prev = new int[v];
|
||||
Arrays.fill(prev, -1);
|
||||
|
||||
// dfs 遍历
|
||||
dfs(s, t, found, visited, prev);
|
||||
|
||||
if (found.get()) {
|
||||
print(prev, s, t);
|
||||
} else {
|
||||
System.out.println("未找到路径...");
|
||||
}
|
||||
}
|
||||
|
||||
private void dfs(int w, int t, AtomicBoolean found, boolean[] visited, int[] prev) {
|
||||
// 判断是否已经找到
|
||||
if (found.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 标记已完成
|
||||
visited[w] = true;
|
||||
|
||||
// 判断是否到达目的地
|
||||
if (w == t) {
|
||||
found.set(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// 遍历
|
||||
for (int i = 0; i < adj[w].size(); i++) {
|
||||
int q = adj[w].get(i);
|
||||
if (!visited[q]) {
|
||||
// 记录是从 w 走到 q
|
||||
prev[q] = w;
|
||||
// 继续递归
|
||||
dfs(q, t, found, visited, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 递归打印从 s 到 t 的点
|
||||
public void print(int[] prev, int s, int t) {
|
||||
if (prev[t] != -1 && t != s) {
|
||||
print(prev, s, prev[t]);
|
||||
}
|
||||
System.out.print(t + " ");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Graph graph = new Graph(10);
|
||||
graph.addEdge(1, 3);
|
||||
graph.addEdge(3, 5);
|
||||
graph.addEdge(5, 7);
|
||||
// graph.addEdge(9, 6);
|
||||
// graph.print();
|
||||
// graph.bfs(1, 7);
|
||||
graph.dfs(1, 7);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0035;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// new Solution01().solveNQueens(4);
|
||||
new Solution02().solveNQueens(4);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0035;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class Solution01 {
|
||||
|
||||
public List<List<String>> solveNQueens(int n) {
|
||||
if (n == 0) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 初始化变量
|
||||
List<List<String>> results = new ArrayList<>();
|
||||
int[] used = new int[n]; // 标记,指定层,使用的位置
|
||||
for (int i = 0; i < n; i++) {
|
||||
used[i] = -1;
|
||||
}
|
||||
|
||||
// 递归
|
||||
gen(results, used, 0, n);
|
||||
|
||||
// 返回结果
|
||||
return results;
|
||||
}
|
||||
|
||||
private void gen(List<List<String>> results, int[] used, int index, int max) {
|
||||
// 到达最大值,结束递归
|
||||
if (index == max) {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (int i = 0; i < max; i++) {
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (int j = 0; j < max; j++) {
|
||||
if (used[i] == j) {
|
||||
str.append("Q");
|
||||
} else {
|
||||
str.append(".");
|
||||
}
|
||||
}
|
||||
result.add(str.toString());
|
||||
}
|
||||
results.add(result);
|
||||
return;
|
||||
}
|
||||
|
||||
// 递归
|
||||
for (int i = 0; i < max; i++) { // i 表示第几个位置
|
||||
boolean isOK = true;
|
||||
// 判断该位置,是否可用
|
||||
for (int j = 0; j < index; j++) {
|
||||
// 纵方法,判断
|
||||
if (used[j] == i) {
|
||||
isOK = false;
|
||||
break;
|
||||
}
|
||||
// 斜方法,判断
|
||||
int diff = index - j; // 判断差的层级
|
||||
if (used[j] + diff == i || used[j] - diff == i) {
|
||||
isOK = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 如果不合法,continue
|
||||
if (!isOK) {
|
||||
continue;
|
||||
}
|
||||
// 标记已使用
|
||||
used[index] = i;
|
||||
// 递归
|
||||
gen(results, used, index + 1, max);
|
||||
// 标记未使用,继续循环
|
||||
used[index] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0035;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 在 {@link Solution01} 的基础上,做一个优化
|
||||
*/
|
||||
public class Solution02 {
|
||||
|
||||
public List<List<String>> solveNQueens(int n) {
|
||||
if (n == 0) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 初始化变量
|
||||
List<List<String>> results = new ArrayList<>();
|
||||
int[] used = new int[n]; // 标记,指定层,使用的位置
|
||||
for (int i = 0; i < n; i++) {
|
||||
used[i] = -1;
|
||||
}
|
||||
boolean[] usedCol = new boolean[n]; // 使用的列的标记
|
||||
boolean[] usedSum = new boolean[2 * n]; // x + y = c ,即“撇” 。
|
||||
boolean[] usedMinus = new boolean[2 * n]; // x - y = c ,即“捺” 。
|
||||
|
||||
|
||||
// 递归
|
||||
gen(results, used, usedCol, usedSum, usedMinus, 0, n);
|
||||
|
||||
// 返回结果
|
||||
return results;
|
||||
}
|
||||
|
||||
private void gen(List<List<String>> results, int[] used, boolean[] usedCol, boolean[] usedSum, boolean[] usedMinus, int index, int max) {
|
||||
// 到达最大值,结束递归
|
||||
if (index == max) {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (int i = 0; i < max; i++) {
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (int j = 0; j < max; j++) {
|
||||
if (used[i] == j) {
|
||||
str.append("Q");
|
||||
} else {
|
||||
str.append(".");
|
||||
}
|
||||
}
|
||||
result.add(str.toString());
|
||||
}
|
||||
results.add(result);
|
||||
return;
|
||||
}
|
||||
|
||||
// 递归
|
||||
for (int i = 0; i < max; i++) { // i 表示第几个位置
|
||||
boolean isOK = true;
|
||||
// 判断该位置,是否可用
|
||||
if (usedCol[i]) { // 列已经使用
|
||||
continue;
|
||||
}
|
||||
int usedSumIndex = index + i; // “撇”已经使用
|
||||
if (usedSum[usedSumIndex]) {
|
||||
continue;
|
||||
}
|
||||
int usedMinusIndex = max + index - i; // “捺”已经使用
|
||||
if (usedMinus[usedMinusIndex]) {
|
||||
continue;
|
||||
}
|
||||
// 标记已使用
|
||||
used[index] = i;
|
||||
usedCol[i] = true;
|
||||
usedSum[usedSumIndex] = true;
|
||||
usedMinus[usedMinusIndex] = true;
|
||||
// 递归
|
||||
gen(results, used, usedCol, usedSum, usedMinus, index + 1, max);
|
||||
// 标记未使用,继续循环
|
||||
used[index] = -1;
|
||||
usedCol[i] = false;
|
||||
usedSum[usedSumIndex] = false;
|
||||
usedMinus[usedMinusIndex] = false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0036;
|
||||
|
||||
public class Solution01 {
|
||||
|
||||
private void reset(boolean[] flags) {
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
flags[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValidSudoku(char[][] board) {
|
||||
int n = 9;
|
||||
int m = 3;
|
||||
boolean[] flags = new boolean[n];
|
||||
|
||||
// 横线
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
if (board[i][j] == '.') {
|
||||
continue;
|
||||
}
|
||||
if (flags[board[i][j ] - '1']) {
|
||||
return false;
|
||||
}
|
||||
flags[board[i][j ] - '1'] = true;
|
||||
}
|
||||
reset(flags);
|
||||
}
|
||||
|
||||
// 竖线
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
if (board[j][i] == '.') {
|
||||
continue;
|
||||
}
|
||||
if (flags[board[j][i ] - '1']) {
|
||||
return false;
|
||||
}
|
||||
flags[board[j][i ] - '1'] = true;
|
||||
}
|
||||
reset(flags);
|
||||
}
|
||||
|
||||
// 每个方块
|
||||
for (int i = 0; i < n; i = i + m) {
|
||||
for (int j = 0; j < n; j = j + m) {
|
||||
for (int p = i; p < i + m; p++) {
|
||||
for (int q = j; q < j + m; q++) {
|
||||
if (board[p][q] == '.') {
|
||||
continue;
|
||||
}
|
||||
if (flags[board[p][q] - '1']) {
|
||||
return false;
|
||||
}
|
||||
flags[board[p][q] - '1'] = true;
|
||||
}
|
||||
}
|
||||
reset(flags);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
char[][] board = {{'.','.','.','.','5','.','.','1','.'},{'.','4','.','3','.','.','.','.','.'},{'.','.','.','.','.','3','.','.','1'},{'8','.','.','.','.','.','.','2','.'},{'.','.','2','.','7','.','.','.','.'},{'.','1','5','.','.','.','.','.','.'},{'.','.','.','.','.','2','.','.','.'},{'.','2','.','9','.','.','.','.','.'},{'.','.','4','.','.','.','.','.','.'}};
|
||||
// for (int i = 0; i < board.length; i++) {
|
||||
// for (int j = 0; j < board[i].length; j++) {
|
||||
// System.out.print(board[i][j] + "\t");
|
||||
// }
|
||||
// System.out.println();
|
||||
// }
|
||||
System.out.println(new Solution01().isValidSudoku(board));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0036;
|
||||
|
||||
public class Solution02 {
|
||||
|
||||
private void reset(boolean[] flags) {
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
flags[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValidSudoku(char[][] board) {
|
||||
int n = 9;
|
||||
int m = 3;
|
||||
// boolean[] flags = new boolean[n];
|
||||
boolean[][] rows = new boolean[n][n];
|
||||
boolean[][] cols = new boolean[n][n];
|
||||
boolean[][] boxes = new boolean[n][n];
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
if (board[i][j] == '.') {
|
||||
continue;
|
||||
}
|
||||
int number = board[i][j] - '1'; // 减 1 而不是 0 ,因为数组从 0 开始。
|
||||
// 行
|
||||
if (rows[i][number]) {
|
||||
return false;
|
||||
}
|
||||
rows[i][number] = true;
|
||||
// 列
|
||||
if (cols[j][number]) {
|
||||
return false;
|
||||
}
|
||||
cols[j][number] = true;
|
||||
// 小方格
|
||||
int boxIndex = i / m * m + j / m;
|
||||
if (boxes[boxIndex][number]) {
|
||||
return false;
|
||||
}
|
||||
boxes[boxIndex][number] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (false) {
|
||||
char[][] board = {{'.', '.', '.', '.', '5', '.', '.', '1', '.'}, {'.', '4', '.', '3', '.', '.', '.', '.', '.'}, {'.', '.', '.', '.', '.', '3', '.', '.', '1'}, {'8', '.', '.', '.', '.', '.', '.', '2', '.'}, {'.', '.', '2', '.', '7', '.', '.', '.', '.'}, {'.', '1', '5', '.', '.', '.', '.', '.', '.'}, {'.', '.', '.', '.', '.', '2', '.', '.', '.'}, {'.', '2', '.', '9', '.', '.', '.', '.', '.'}, {'.', '.', '4', '.', '.', '.', '.', '.', '.'}};
|
||||
// for (int i = 0; i < board.length; i++) {
|
||||
// for (int j = 0; j < board[i].length; j++) {
|
||||
// System.out.print(board[i][j] + "\t");
|
||||
// }
|
||||
// System.out.println();
|
||||
// }
|
||||
System.out.println(new Solution02().isValidSudoku(board));
|
||||
}
|
||||
if (true) {
|
||||
char[][] board = {{'5','3','.','.','7','.','.','.','.'},{'6','.','.','1','9','5','.','.','.'},{'.','9','8','.','.','.','.','6','.'},{'8','.','.','.','6','.','.','.','3'},{'4','.','.','8','.','3','.','.','1'},{'7','.','.','.','2','.','.','.','6'},{'.','6','.','.','.','.','2','8','.'},{'.','.','.','4','1','9','.','.','5'},{'.','.','.','.','8','.','.','7','9'}};
|
||||
System.out.println(new Solution02().isValidSudoku(board));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0072;
|
||||
|
||||
public class Solution {
|
||||
|
||||
public int minDistance(String word1, String word2) {
|
||||
// + 1 的原始是,
|
||||
// 1. 字符串的长度可以是 0 。例如说,word1 为 abc ,word2 为空串。
|
||||
// 2. 而数组的下标,代表的是第几个字符串。
|
||||
// 所以需要 + 1 。
|
||||
int[][] dp = new int[word1.length() + 1][word2.length() + 1];
|
||||
|
||||
// 初始化
|
||||
for (int i = 0; i <= word1.length(); i++) { // i 变成 words2 0 的位置,就是意味着 words2 是空串,则需要不断删除
|
||||
dp[i][0] = i;
|
||||
}
|
||||
for (int j = 0; j <= word2.length(); j++) { // words[0] 变成 words2 j 的位置,就是意味着,需要不断添加。
|
||||
dp[0][j] = j;
|
||||
}
|
||||
|
||||
// dp
|
||||
for (int i = 1; i <= word1.length(); i++) {
|
||||
for (int j = 1; j <= word2.length(); j++) {
|
||||
if (word1.charAt(i - 1) == word2.charAt(j - 1)) { // -1 的原因,正如上面所说 + 1 的原因,dp 的下标,对应 word 的下标 - 1 。
|
||||
dp[i][j] = dp[i - 1][j - 1];
|
||||
} else {
|
||||
dp[i][j] = this.min(
|
||||
dp[i - 1][j] + 1, // 删除 a[i]
|
||||
dp[i][j - 1] + 1, // 插入 b[j]
|
||||
dp[i - 1][j - 1] + 1 // 替换 a[i] 到 b[j]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[word1.length()][word2.length()];
|
||||
}
|
||||
|
||||
private int min(int a, int b, int c) {
|
||||
return Math.min(Math.min(a, b), c);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Solution solution = new Solution();
|
||||
System.out.println(solution.minDistance("horse", "ros"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0120;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自上而下,进行 DP
|
||||
*/
|
||||
public class Solution01 {
|
||||
|
||||
public int minimumTotal(List<List<Integer>> triangle) {
|
||||
if (triangle == null || triangle.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
// 只有一层,就不要求解了
|
||||
if (triangle.size() == 1) {
|
||||
return triangle.get(0).get(0);
|
||||
}
|
||||
|
||||
// 通过 ways ,记录最大路径
|
||||
int size = triangle.size();
|
||||
int[] ways = new int[triangle.get(size - 1).size()];
|
||||
Arrays.fill(ways, Integer.MAX_VALUE);
|
||||
// 计算下一层的时候,临时使用
|
||||
int[] tmps = new int[ways.length];
|
||||
// 用于在最后一层,计算 ways 中的最小值。
|
||||
int min = Integer.MAX_VALUE;
|
||||
|
||||
// 开始动态规划
|
||||
ways[0] = triangle.get(0).get(0);
|
||||
tmps[0] = triangle.get(0).get(0);
|
||||
for (int i = 1; i < size; i++) {
|
||||
int levelSize = triangle.get(i).size();
|
||||
for (int j = 0; j < levelSize; j++) {
|
||||
// 选取能到达当前节点的较小值
|
||||
int result;
|
||||
if (j == 0) {
|
||||
result = ways[j];
|
||||
} else if (j == levelSize - 1) {
|
||||
result = ways[j - 1];
|
||||
} else {
|
||||
result = Math.min(ways[j], ways[j - 1]);
|
||||
}
|
||||
// 记录当前节点需要的最小路径,到 tmps 中。
|
||||
tmps[j] = result + triangle.get(i).get(j);
|
||||
// 如果是最后一层,开始计算最小值。
|
||||
if (i == size - 1) {
|
||||
if (tmps[j] < min) {
|
||||
min = tmps[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
System.arraycopy(tmps, 0, ways, 0, levelSize);
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<List<Integer>> triangle = new ArrayList<>();
|
||||
triangle.add(Arrays.asList(2));
|
||||
triangle.add(Arrays.asList(3, 4));
|
||||
triangle.add(Arrays.asList(6, 5, 7));
|
||||
triangle.add(Arrays.asList(4, 1, 8, 3));
|
||||
System.out.println(new Solution01().minimumTotal(triangle));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0120;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自下而上,进行 DP
|
||||
*/
|
||||
public class Solution02 {
|
||||
|
||||
public int minimumTotal(List<List<Integer>> triangle) {
|
||||
if (triangle == null || triangle.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 通过 ways ,记录最大路径
|
||||
int size = triangle.size();
|
||||
int[] ways = new int[triangle.get(size - 1).size()];
|
||||
for (int j = 0; j < triangle.get(size - 1).size(); j++) {
|
||||
ways[j] = triangle.get(size - 1).get(j);
|
||||
}
|
||||
|
||||
// 自下而上 DP
|
||||
for (int i = size - 2; i >= 0; i--) {
|
||||
for (int j = 0; j < triangle.get(i).size(); j++) {
|
||||
ways[j] = Math.min(ways[j], ways[j + 1]) + triangle.get(i).get(j);
|
||||
}
|
||||
}
|
||||
|
||||
return ways[0];
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<List<Integer>> triangle = new ArrayList<>();
|
||||
triangle.add(Arrays.asList(2));
|
||||
triangle.add(Arrays.asList(3, 4));
|
||||
triangle.add(Arrays.asList(6, 5, 7));
|
||||
triangle.add(Arrays.asList(4, 1, 8, 3));
|
||||
System.out.println(new Solution02().minimumTotal(triangle));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0123;
|
||||
|
||||
public class Solution {
|
||||
|
||||
public int maxProfit(int[] prices) {
|
||||
if (prices == null || prices.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
int k = 2; // 最大交易次数,只能两次
|
||||
// 第一维度 k ,表示当前【买入股票】的次数;
|
||||
// 第二维度 2 ,表示 0 - 未持有,1 - 持有 1 股
|
||||
// 值为最大利润
|
||||
int[][] dp = new int[k + 1][2];
|
||||
// 初始化第一个股票的处理
|
||||
dp[1][1] = -prices[0]; // 买入
|
||||
dp[2][1] = -prices[0]; // 买入 + 卖出 + 买入
|
||||
dp[0][1] = Integer.MIN_VALUE; // 相当于赋值为空,避免直接认为持有一股时,利润为 0 。
|
||||
|
||||
// 遍历,进行买卖
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
for (int j = 0; j <= k; j++) {
|
||||
// 尝试卖出
|
||||
dp[j][0] = Math.max(dp[j][0], dp[j][1] + prices[i]);
|
||||
// 尝试买入
|
||||
if (j > 0) {
|
||||
dp[j][1] = Math.max(dp[j][1], dp[j - 1][0] - prices[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Math.max(dp[1][0], dp[2][0]);
|
||||
}
|
||||
|
||||
// public int maxProfit(int[] prices) {
|
||||
// if (prices == null || prices.length == 0) {
|
||||
// return 0;
|
||||
// }
|
||||
// int k = 2; // 最大交易次数,只能两次
|
||||
// // 第一维度 k ,表示当前【买入股票】的次数;
|
||||
// // 第二维度 2 ,表示 0 - 未持有,1 - 持有 1 股
|
||||
// int[][][] dp = new int[prices.length][k + 1][2];
|
||||
// // 初始化第一个股票的处理
|
||||
// dp[0][1][1] = -prices[0]; // 买入
|
||||
//// dp[2][1] = -prices[0]; // 买入 + 卖出 + 买入
|
||||
//
|
||||
// // 遍历,进行买卖
|
||||
// for (int i = 1; i < prices.length; i++) {
|
||||
// for (int j = 0; j <= k; j++) {
|
||||
// // 尝试卖出
|
||||
// dp[i][j][0] = Math.max(dp[i][j][0], dp[i][j][1] + prices[i]);
|
||||
// // 尝试买入
|
||||
// if (j > 0) {
|
||||
// dp[i][j][1] = Math.max(dp[i][j][1], dp[i][j - 1][0] - prices[i]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return Math.max(dp[prices.length -1][1][0], dp[prices.length - 1][2][0]);
|
||||
// }
|
||||
|
||||
public static void main(String[] args) {
|
||||
Solution solution = new Solution();
|
||||
System.out.println(solution.maxProfit(new int[]{3,3,5,0,0,3,1,4}));
|
||||
System.out.println(solution.maxProfit(new int[]{1,2,3,4,5}));
|
||||
System.out.println(solution.maxProfit(new int[]{7, 6, 4, 3, 1}));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0146;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class LRUCache {
|
||||
|
||||
private Map<Integer, Integer> cache;
|
||||
|
||||
public LRUCache(int capacity) {
|
||||
this.cache = new LinkedHashMap<Integer, Integer>((int) Math.ceil(capacity / 0.75f) + 1, 0.75f, true) {
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
|
||||
return size() > capacity;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public int get(int key) {
|
||||
Integer val = cache.get(key);
|
||||
return val != null ? val : -1;
|
||||
}
|
||||
|
||||
public void put(int key, int value) {
|
||||
cache.put(key, value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0146;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class LRUCache02 {
|
||||
|
||||
private class Node {
|
||||
|
||||
private int key;
|
||||
private int value;
|
||||
private Node prev;
|
||||
private Node next;
|
||||
|
||||
public Node(int key, int value, Node prev, Node next) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.prev = prev;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 容量
|
||||
*/
|
||||
private int capacity;
|
||||
/**
|
||||
* 缓存
|
||||
*/
|
||||
private Map<Integer, Node> cache;
|
||||
/**
|
||||
* 指向头
|
||||
*/
|
||||
private Node head;
|
||||
/**
|
||||
* 指向尾.
|
||||
*
|
||||
* 最新的元素,放在尾部
|
||||
*/
|
||||
private Node tail;
|
||||
|
||||
public LRUCache02(int capacity) {
|
||||
this.capacity = capacity;
|
||||
this.cache = new HashMap<>(capacity, 1F);
|
||||
}
|
||||
|
||||
public int get(int key) {
|
||||
Node node = this.getNode(key);
|
||||
return node != null ? node.value : -1;
|
||||
}
|
||||
|
||||
public void put(int key, int value) {
|
||||
Node node = getNode(key);
|
||||
|
||||
// 获得到值,设置其值
|
||||
if (node != null) {
|
||||
node.value = value;
|
||||
return;
|
||||
}
|
||||
|
||||
// 移除最老访问的
|
||||
removeIfFull();
|
||||
|
||||
// 容量足够
|
||||
node = new Node(key, value, tail, null);
|
||||
cache.put(key, node);
|
||||
// 设置新的尾节点
|
||||
if (head == null) {
|
||||
head = tail = node;
|
||||
} else {
|
||||
tail.next = node;
|
||||
tail = node;
|
||||
}
|
||||
}
|
||||
|
||||
private Node getNode(int key) {
|
||||
// head 为空,说明无元素
|
||||
if (head == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 获得元素
|
||||
Node node = cache.get(key);
|
||||
if (node == null) { // 如果获得不到,返回空
|
||||
return null;
|
||||
}
|
||||
|
||||
// 如果尾部并未指向 node ,则重新指向
|
||||
if (node != tail) {
|
||||
if (node == head) {
|
||||
head = head.next;
|
||||
head.prev = null;
|
||||
} else {
|
||||
node.next.prev = node.prev;
|
||||
node.prev.next = node.next;
|
||||
}
|
||||
|
||||
// 添加到尾部
|
||||
node.prev = tail;
|
||||
tail.next = node;
|
||||
node.next = null;
|
||||
tail = node;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private void removeIfFull() {
|
||||
if (cache.size() < capacity) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 移除 cache
|
||||
cache.remove(head.key);
|
||||
// 更新新的 head
|
||||
head = head.next;
|
||||
if (head != null) { // 主要为了处理 capacity 为 1 的情况
|
||||
head.prev = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (false) {
|
||||
LRUCache02 cache = new LRUCache02(2 /* 缓存容量 */);
|
||||
|
||||
cache.put(1, 1);
|
||||
cache.put(2, 2);
|
||||
System.out.println(cache.get(1)); // 返回 1
|
||||
cache.put(3, 3); // 该操作会使得密钥 2 作废
|
||||
System.out.println(cache.get(2)); // 返回 -1 (未找到)
|
||||
cache.put(4, 4); // 该操作会使得密钥 1 作废
|
||||
System.out.println(cache.get(1)); // 返回 -1 (未找到)
|
||||
System.out.println(cache.get(3)); // 返回 3
|
||||
System.out.println(cache.get(4)); // 返回 4
|
||||
}
|
||||
if (true) {
|
||||
LRUCache02 cache = new LRUCache02(1 /* 缓存容量 */);
|
||||
cache.put(2, 1);
|
||||
System.out.println(cache.get(2)); // 返回 1
|
||||
cache.put(3, 2);
|
||||
System.out.println(cache.get(2)); // 返回
|
||||
System.out.println(cache.get(3)); // 返回
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0152;
|
||||
|
||||
@Deprecated // 解法不对
|
||||
public class Solution01 {
|
||||
|
||||
public int maxProduct(int[] nums) {
|
||||
Integer max = Integer.MIN_VALUE; // 最大值
|
||||
Integer x = null; // 正数
|
||||
Integer y = null; // 负数
|
||||
|
||||
// 遍历
|
||||
for (int num : nums) {
|
||||
if (num >= 0) { // 正数
|
||||
if (x == null) {
|
||||
x = num;
|
||||
} else {
|
||||
if (num * x > x) {
|
||||
x = num * x;
|
||||
} else {
|
||||
x = num;
|
||||
}
|
||||
}
|
||||
if (y != null) {
|
||||
if (num == 0) {
|
||||
y = null;
|
||||
} else {
|
||||
y = y * num;
|
||||
}
|
||||
}
|
||||
} else { // 负数
|
||||
if (y == null) {
|
||||
if (x == null) {
|
||||
y = num;
|
||||
} else {
|
||||
y = num * x;
|
||||
x = null;
|
||||
}
|
||||
} else {
|
||||
y = num * y;
|
||||
if (y > 0) {
|
||||
x = y;
|
||||
y = num;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 判断是否超过
|
||||
if (x != null && x > max) {
|
||||
max = x;
|
||||
}
|
||||
if (y != null && y > max) { // 处理,整个数组只有一个负数的情况。
|
||||
max = y;
|
||||
}
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Solution01 solution = new Solution01();
|
||||
// System.out.println(solution.maxProduct(new int[]{2, 3, -2, -4}));
|
||||
// System.out.println(solution.maxProduct(new int[]{2, 3, -2, 4}));
|
||||
// System.out.println(solution.maxProduct(new int[]{-2, 0, 1}));
|
||||
// System.out.println(solution.maxProduct(new int[]{0, 2}));
|
||||
// System.out.println(solution.maxProduct(new int[]{2, -5, -2, -4, 3}));
|
||||
System.out.println(solution.maxProduct(new int[]{-1, -2, -9, -6}));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0152;
|
||||
|
||||
/**
|
||||
* dp 方程
|
||||
*
|
||||
* dp1[i] = max(dp[i - 1] * nums[i], dp2[i -1] * nums[i], nums[i])
|
||||
* dp2[i] = min(dp[i - 1] * nums[i], dp2[i -1] * nums[i], nums[i])
|
||||
*
|
||||
* 通过不断求,使用上当前数值时,能产生的最大值。
|
||||
*
|
||||
* 注意,结果不是 dp1[n - 1] ,而是在这个过程中,产生的最大值。因为 nums 有负数的可能性,导致不一定使用上当前值,就一定是最大值。
|
||||
*/
|
||||
public class Solution02 {
|
||||
|
||||
public int maxProduct(int[] nums) {
|
||||
// 最大值
|
||||
int max = nums[0];
|
||||
// 使用上当前位置的数,最大值。max 和 dp1 并不等价,因为使用上当前数字后,可能不一定大于 max
|
||||
int[] dp1 = new int[nums.length];
|
||||
dp1[0] = nums[0];
|
||||
// 使用上当前位置的数,最小值。使用最小值的原因是,可以有机会负负得正
|
||||
int[] dp2 = new int[nums.length];
|
||||
dp2[0] = nums[0];
|
||||
|
||||
// 开始 dp
|
||||
for (int i = 1; i < nums.length; i++) {
|
||||
int num = nums[i];
|
||||
dp1[i] = max(dp1[i - 1] * num, // 如果 num 是正数的情况下,乘以 dp1,会变大
|
||||
dp2[i - 1] * num, // 如果 num 是负数的情况,乘以 dp2 ,可能反倒比 dp1 大。
|
||||
num); // 可能上面两个,乘了半天,还不如
|
||||
dp2[i] = min(dp1[i - 1] * num, dp2[i - 1] * num, num); // 同上面的想法
|
||||
// 求最大值
|
||||
max = Math.max(dp1[i], max);
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
private int min(int a, int b, int c) {
|
||||
return Math.min(Math.min(a, b), c);
|
||||
}
|
||||
|
||||
private int max(int a, int b, int c) {
|
||||
return Math.max(Math.max(a, b), c);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Solution02 solution = new Solution02();
|
||||
System.out.println(solution.maxProduct(new int[]{2, 3, -2, -4}));
|
||||
System.out.println(solution.maxProduct(new int[]{2, 3, -2, 4}));
|
||||
System.out.println(solution.maxProduct(new int[]{-2, 0, 1}));
|
||||
System.out.println(solution.maxProduct(new int[]{0, 2}));
|
||||
System.out.println(solution.maxProduct(new int[]{2, -5, -2, -4, 3}));
|
||||
System.out.println(solution.maxProduct(new int[]{-1, -2, -9, -6}));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0152;
|
||||
|
||||
/**
|
||||
* {@link Solution02} 的改进,不使用两个一维数组,而是直接使用两个变量。
|
||||
*/
|
||||
public class Solution03 {
|
||||
|
||||
public int maxProduct(int[] nums) {
|
||||
// 最大值
|
||||
int max = nums[0];
|
||||
// 使用上当前位置的数,最大值。max 和 dp1 并不等价,因为使用上当前数字后,可能不一定大于 max
|
||||
int dp1 = nums[0];
|
||||
// 使用上当前位置的数,最小值。使用最小值的原因是,可以有机会负负得正
|
||||
int dp2 = nums[0];
|
||||
|
||||
// 开始 dp
|
||||
for (int i = 1; i < nums.length; i++) {
|
||||
int num = nums[i];
|
||||
int[] results = minAndMax(dp1 * num, dp2* num, num);
|
||||
dp1 = results[1];
|
||||
dp2 = results[0];
|
||||
// 求最大值
|
||||
max = Math.max(dp1, max);
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
private int[] minAndMax(int a, int b, int c) {
|
||||
return new int[]{Math.min(Math.min(a, b), c),
|
||||
Math.max(Math.max(a, b), c)};
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Solution03 solution = new Solution03();
|
||||
System.out.println(solution.maxProduct(new int[]{2, 3, -2, -4}));
|
||||
System.out.println(solution.maxProduct(new int[]{2, 3, -2, 4}));
|
||||
System.out.println(solution.maxProduct(new int[]{-2, 0, 1}));
|
||||
System.out.println(solution.maxProduct(new int[]{0, 2}));
|
||||
System.out.println(solution.maxProduct(new int[]{2, -5, -2, -4, 3}));
|
||||
System.out.println(solution.maxProduct(new int[]{-1, -2, -9, -6}));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0208;
|
||||
|
||||
public class Trie {
|
||||
|
||||
public class Node {
|
||||
|
||||
private Node[] children;
|
||||
private boolean end;
|
||||
|
||||
public Node() {
|
||||
children = new Node['z' - 'a' + 1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Node node;
|
||||
|
||||
/** Initialize your data structure here. */
|
||||
public Trie() {
|
||||
node = new Node();
|
||||
}
|
||||
|
||||
/** Inserts a word into the trie. */
|
||||
public void insert(String word) {
|
||||
if (word == null || word.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 遍历,创建节点
|
||||
Node current = node;
|
||||
for (int i = 0; i < word.length(); i++) {
|
||||
int index = getIndex(word.charAt(i));
|
||||
Node next = current.children[index];
|
||||
if (next == null) {
|
||||
next = new Node();
|
||||
current.children[index] = next;
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
|
||||
// 标记结束
|
||||
current.end = true;
|
||||
}
|
||||
|
||||
/** Returns if the word is in the trie. */
|
||||
public boolean search(String word) {
|
||||
if (word == null || word.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 遍历,寻找节点
|
||||
Node current = node;
|
||||
for (int i = 0; i < word.length(); i++) {
|
||||
int index = getIndex(word.charAt(i));
|
||||
Node next = current.children[index];
|
||||
if (next == null) {
|
||||
return false;
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
|
||||
// 判断找到的节点,是否为根节点
|
||||
return current.end;
|
||||
}
|
||||
|
||||
/** Returns if there is any word in the trie that starts with the given prefix. */
|
||||
public boolean startsWith(String prefix) {
|
||||
if (prefix == null || prefix.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 遍历,寻找节点
|
||||
Node current = node;
|
||||
for (int i = 0; i < prefix.length(); i++) {
|
||||
int index = getIndex(prefix.charAt(i));
|
||||
Node next = current.children[index];
|
||||
if (next == null) {
|
||||
return false;
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
|
||||
// 结果找到
|
||||
return true;
|
||||
}
|
||||
|
||||
private int getIndex(char ch) {
|
||||
return ch - 'a';
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Trie trie = new Trie();
|
||||
|
||||
trie.insert("apple");
|
||||
System.out.println(trie.search("apple")); // 返回 true
|
||||
System.out.println(trie.search("app")); // 返回 false
|
||||
System.out.println(trie.startsWith("app")); // 返回 true
|
||||
|
||||
trie.insert("app");
|
||||
System.out.println(trie.search("app")); // 返回 true
|
||||
|
||||
System.out.println(trie.search("appled"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0231;
|
||||
|
||||
public class Solution01 {
|
||||
|
||||
public boolean isPowerOfTwo(int n) {
|
||||
// 非正整数,非正整数
|
||||
if (n <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int mask = 1;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
// 或运算,如果就是自己,说明是 2 的 n 次方
|
||||
if ((n | mask) == mask) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// mask 超过范围,说明就是不符合
|
||||
if (mask > n) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mask = mask << 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Solution01 solution = new Solution01();
|
||||
System.out.println(solution.isPowerOfTwo(1));
|
||||
System.out.println(solution.isPowerOfTwo(2));
|
||||
System.out.println(solution.isPowerOfTwo(3));
|
||||
System.out.println(solution.isPowerOfTwo(4));
|
||||
System.out.println(solution.isPowerOfTwo(5));
|
||||
System.out.println(solution.isPowerOfTwo(6));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0235;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 寻找路径,然后匹配
|
||||
*/
|
||||
public class Solution01 {
|
||||
|
||||
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
|
||||
// p 节点的路径
|
||||
List<TreeNode> pNodes = new ArrayList<>();
|
||||
binarySearch(root, p, pNodes);
|
||||
// q 节点的路径
|
||||
List<TreeNode> qNodes = new ArrayList<>();
|
||||
binarySearch(root, q, qNodes);
|
||||
|
||||
// 倒序,对比
|
||||
for (int i = pNodes.size() - 1; i >= 0; i--) {
|
||||
TreeNode node = pNodes.get(i);
|
||||
for (int j = qNodes.size() - 1; j >= 0; j--) {
|
||||
TreeNode node2 = qNodes.get(j);
|
||||
if (node.val == node2.val) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void binarySearch(TreeNode root, TreeNode target, List<TreeNode> nodes) {
|
||||
if (root == null) { // 理论不存在,防御性
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加到路径
|
||||
nodes.add(root);
|
||||
|
||||
if (root.val == target.val) {
|
||||
return;
|
||||
}
|
||||
if (root.val > target.val) {
|
||||
binarySearch(root.left, target, nodes);
|
||||
} else {
|
||||
binarySearch(root.right, target, nodes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0235;
|
||||
|
||||
/**
|
||||
* 递归求解父节点
|
||||
*/
|
||||
public class Solution02 {
|
||||
|
||||
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
|
||||
if (p.val < root.val
|
||||
&& root.val > q.val) { // 因为 root.val 大于 q.val ,说明 root 的值过大,需要往左走
|
||||
return lowestCommonAncestor(root.left, p, q);
|
||||
} else if (p.val > root.val // 因为 root.val 小于 p.val ,说明 root 的值过小,需要往右走
|
||||
&& root.val < q.val) {
|
||||
return lowestCommonAncestor(root.right, p, q);
|
||||
} else { // 其他情况,root 都是符合条件的,例如说 root 的泛微在 p and q 之间(或者 q and p 之间)。
|
||||
// 为什么直接返回 root 就可以,因为如果不是最接近的父节点,p 和 q 要么在其左边,要么在其右边。
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0235;
|
||||
|
||||
/**
|
||||
* {@link Solution02} 的改进,非递归方式。
|
||||
*/
|
||||
public class Solution03 {
|
||||
|
||||
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
|
||||
while (true) {
|
||||
if (p.val < root.val
|
||||
&& root.val > q.val) { // 因为 root.val 大于 q.val ,说明 root 的值过大,需要往左走
|
||||
root = root.left;
|
||||
} else if (p.val > root.val // 因为 root.val 小于 p.val ,说明 root 的值过小,需要往右走
|
||||
&& root.val < q.val) {
|
||||
root = root.right;
|
||||
} else { // 其他情况,root 都是符合条件的,例如说 root 的泛微在 p and q 之间(或者 q and p 之间)。
|
||||
return root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0235;
|
||||
|
||||
public class TreeNode {
|
||||
|
||||
int val;
|
||||
TreeNode left;
|
||||
TreeNode right;
|
||||
|
||||
TreeNode(int x) { val = x; }
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0300;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* DP 实现,时间复杂度为 O(N^2) 。
|
||||
*
|
||||
* DP 转换方程是:
|
||||
* dp[i] = MAX(dp[i], dp[j] + 1)
|
||||
* 其中,dp[i] 表示,截止目前,最大的上升的子序列
|
||||
*/
|
||||
public class Solution01 {
|
||||
|
||||
public int lengthOfLIS(int[] nums) {
|
||||
if (nums.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int[] dps = new int[nums.length];
|
||||
Arrays.fill(dps, 1); // 都赋值为 1 先,因为自己是自己的递增。
|
||||
int result = 1;
|
||||
|
||||
// dp
|
||||
for (int i = 1; i < nums.length; i++) {
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (nums[i] > nums[j]) {
|
||||
dps[i] = Math.max(dps[i], dps[j] + 1);
|
||||
}
|
||||
}
|
||||
result = Math.max(result, dps[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0300;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 二分 + 贪心
|
||||
*/
|
||||
public class Solution02 {
|
||||
|
||||
public int lengthOfLIS(int[] nums) {
|
||||
if (nums.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
List<Integer> lis = new ArrayList<>(); // 上升序列
|
||||
for (int num : nums) {
|
||||
int position = binarySearch(lis, num);
|
||||
if (position >= lis.size()) {
|
||||
lis.add(num);
|
||||
} else {
|
||||
lis.set(position, num);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return lis.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得比 num 第一大的值的位置
|
||||
* 如果有和 num 相等的,也返回
|
||||
*
|
||||
* TODO 芋艿,后续,可以使用 Arrays.binarySearch() 简化。
|
||||
*
|
||||
* @param lis
|
||||
* @param num
|
||||
* @return
|
||||
*/
|
||||
private int binarySearch(List<Integer> lis, int num) {
|
||||
int high = lis.size() - 1;
|
||||
|
||||
// 判断,是否超过
|
||||
if (high < 0 || lis.get(high) < num) {
|
||||
return lis.size();
|
||||
}
|
||||
if (num < lis.get(0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 二分查找
|
||||
int low = 0;
|
||||
while (low <= high) {
|
||||
int mid = low + ((high - low) >> 1);
|
||||
if (lis.get(mid) == num) {
|
||||
return mid;
|
||||
} else if (num < lis.get(mid)) {
|
||||
if (lis.get(mid - 1) > num) {
|
||||
return mid;
|
||||
} else {
|
||||
high = mid - 1;
|
||||
}
|
||||
} else {
|
||||
if (lis.get(mid + 1) > num) {
|
||||
return mid + 1;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("不可能出现");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Solution02 solution = new Solution02();
|
||||
// System.out.println(solution.lengthOfLIS(new int[]{10,9,2,5,3,7,101,18}));
|
||||
System.out.println(solution.lengthOfLIS(new int[]{7,8,9,10,1,2,3,4,5,5}));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0703;
|
||||
|
||||
class KthLargest {
|
||||
|
||||
/**
|
||||
* 小顶堆
|
||||
*/
|
||||
private int[] heap;
|
||||
/**
|
||||
* 堆的位置
|
||||
*/
|
||||
private int heapIndex;
|
||||
private int k;
|
||||
|
||||
public KthLargest(int k, int[] nums) {
|
||||
this.heap = new int[k + 1];
|
||||
this.heapIndex = 1;
|
||||
this.k = k;
|
||||
// 初始化
|
||||
for (int num : nums) {
|
||||
add(num);
|
||||
}
|
||||
}
|
||||
|
||||
public int add(int val) {
|
||||
if (heapIndex <= k) {
|
||||
// 赋值
|
||||
heap[heapIndex] = val;
|
||||
heapIndex++;
|
||||
|
||||
// 向上堆化
|
||||
heapifyUp(heapIndex - 1);
|
||||
} else {
|
||||
if (val > heap[1]) { // 大于最小值,才有资格加入其中。因为我们构建的 heap 是小顶堆,最上面存储的是第 k 大。
|
||||
// 赋值
|
||||
heap[1] = val;
|
||||
|
||||
heapifyDown(1);
|
||||
}
|
||||
}
|
||||
|
||||
return heap[1];
|
||||
}
|
||||
|
||||
// private int remove0() {
|
||||
// // 取头元素
|
||||
// int val = heap[1];
|
||||
//
|
||||
// // 将尾巴设置到头
|
||||
// heap[1] = heap[heapIndex - 1];
|
||||
// heapIndex--;
|
||||
//
|
||||
// // 向下堆化
|
||||
// heapifyDown(1);
|
||||
//
|
||||
// return val;
|
||||
// }
|
||||
|
||||
public void heapifyUp(int index) {
|
||||
while (index > 1) { // 注意,此处要大于 1
|
||||
int parent = index / 2;
|
||||
if (heap[index] < heap[parent]) {
|
||||
swap(index, parent);
|
||||
index = parent;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void heapifyDown(int index) {
|
||||
while (true) {
|
||||
int pos = index;
|
||||
// 求子节点中,哪个
|
||||
if (index * 2 < heapIndex && heap[index * 2] < heap[index]) {
|
||||
pos = index * 2;
|
||||
}
|
||||
if (index * 2 + 1 < heapIndex && heap[index * 2 + 1] < heap[pos]) {
|
||||
pos = index * 2 + 1;
|
||||
}
|
||||
// 如果毫无变化,说明已经不需要继续向下
|
||||
if (pos == index) {
|
||||
return;
|
||||
}
|
||||
// 交换
|
||||
swap(index, pos);
|
||||
index = pos;
|
||||
}
|
||||
}
|
||||
|
||||
private void swap(int i, int j) {
|
||||
int tmp = heap[i];
|
||||
heap[i] = heap[j];
|
||||
heap[j] = tmp;
|
||||
}
|
||||
|
||||
// private int findMaxValueIndex() {
|
||||
// int max = Integer.MIN_VALUE;
|
||||
// int maxIndex = -1;
|
||||
// for (int i = log2(heapIndex) * 2; i < heapIndex; i++) { // 从 log2(heapIndex) * 2 的原因是,从叶子节点开始。因为我们构建的是小顶堆,那么最大值必定在叶子节点上。
|
||||
// if (heap[i] > max) {
|
||||
// max = heap[i];
|
||||
// maxIndex = i;
|
||||
// }
|
||||
// }
|
||||
// return maxIndex;
|
||||
// }
|
||||
//
|
||||
// private static int log2(int x) {
|
||||
// return (int) (Math.log(x) / Math.log(2));
|
||||
// }
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (false) {
|
||||
int k = 3;
|
||||
int[] nums = {4, 5, 8, 2};
|
||||
KthLargest kthLargest = new KthLargest(k, nums);
|
||||
System.out.println(kthLargest.add(3));
|
||||
System.out.println(kthLargest.add(5));
|
||||
System.out.println(kthLargest.add(10));
|
||||
System.out.println(kthLargest.add(9));
|
||||
System.out.println(kthLargest.add(4));
|
||||
}
|
||||
if (true) {
|
||||
int k = 1;
|
||||
int[] nums = {};
|
||||
KthLargest kthLargest = new KthLargest(k, nums);
|
||||
System.out.println(kthLargest.add(-3));
|
||||
System.out.println(kthLargest.add(-2));
|
||||
System.out.println(kthLargest.add(-4));
|
||||
System.out.println(kthLargest.add(0));
|
||||
System.out.println(kthLargest.add(4));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode.no0703;
|
||||
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
|
||||
class KthLargest2 {
|
||||
|
||||
private Queue<Integer> queue;
|
||||
private int k;
|
||||
|
||||
public KthLargest2(int k, int[] nums) {
|
||||
queue = new PriorityQueue<>(k);
|
||||
this.k = k;
|
||||
// 初始化
|
||||
for (int num : nums) {
|
||||
add(num);
|
||||
}
|
||||
}
|
||||
|
||||
public int add(int val) {
|
||||
if (queue.size() < k) {
|
||||
// 赋值
|
||||
queue.add(val);
|
||||
} else {
|
||||
if (val > queue.peek()) { // 大于最小值,才有资格加入其中。因为我们构建的 heap 是小顶堆,最上面存储的是第 k 大。
|
||||
queue.poll();
|
||||
queue.add(val);
|
||||
}
|
||||
}
|
||||
|
||||
return queue.peek();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (true) {
|
||||
int k = 3;
|
||||
int[] nums = {4, 5, 8, 2};
|
||||
KthLargest2 kthLargest = new KthLargest2(k, nums);
|
||||
System.out.println(kthLargest.add(3));
|
||||
System.out.println(kthLargest.add(5));
|
||||
System.out.println(kthLargest.add(10));
|
||||
System.out.println(kthLargest.add(9));
|
||||
System.out.println(kthLargest.add(4));
|
||||
}
|
||||
if (false) {
|
||||
int k = 1;
|
||||
int[] nums = {};
|
||||
KthLargest2 kthLargest = new KthLargest2(k, nums);
|
||||
System.out.println(kthLargest.add(-3));
|
||||
System.out.println(kthLargest.add(-2));
|
||||
System.out.println(kthLargest.add(-4));
|
||||
System.out.println(kthLargest.add(0));
|
||||
System.out.println(kthLargest.add(4));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* leetcode 题目解答
|
||||
*/
|
||||
package cn.iocoder.springboot.labs.lab09.leetcode;
|
||||
@@ -1,110 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.linkedlist;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 判断单链表,是否为回文结构
|
||||
*
|
||||
* 核心的逻辑是,顺序遍历,同时反向前半段。
|
||||
*
|
||||
* 对应极客时间《06 | 链表(上):如何实现LRU缓存淘汰算法?》的思考题
|
||||
*/
|
||||
public class HuiWenLinkedListTest {
|
||||
|
||||
public static class Node {
|
||||
|
||||
private Object data;
|
||||
private Node next;
|
||||
|
||||
public Object getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public Node setData(Object data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Node getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
public Node setNext(Node next) {
|
||||
this.next = next;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
huiwen01();
|
||||
huiwen02();
|
||||
}
|
||||
|
||||
private static void huiwen01() {
|
||||
Node node01 = new Node().setData("1");
|
||||
Node node02 = new Node().setData("2");
|
||||
Node node03 = new Node().setData("3");
|
||||
Node node04 = new Node().setData("4");
|
||||
Node node05 = new Node().setData("5");
|
||||
node01.next = node02;
|
||||
node02.next = node03;
|
||||
node03.next = node04;
|
||||
node04.next = node05;
|
||||
|
||||
assert !isHuiWen(node01);
|
||||
}
|
||||
|
||||
private static void huiwen02() {
|
||||
Node node01 = new Node().setData("1");
|
||||
Node node02 = new Node().setData("2");
|
||||
Node node03 = new Node().setData("3");
|
||||
Node node04 = new Node().setData("2");
|
||||
Node node05 = new Node().setData("1");
|
||||
node01.next = node02;
|
||||
node02.next = node03;
|
||||
node03.next = node04;
|
||||
node04.next = node05;
|
||||
|
||||
assert isHuiWen(node01);
|
||||
}
|
||||
|
||||
private static boolean isHuiWen(Node head) {
|
||||
// 如果不存在节点,或者是单节点,不然是回文
|
||||
if (head == null || head.next == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 通过下面的逻辑,将链表的前半段,反转。
|
||||
Node slow = head;
|
||||
Node fast = head; // fast 的用途,是能够保证只反向前半段
|
||||
Node prev = null; // 前半段的反向
|
||||
while (fast != null && fast.next != null) {
|
||||
// fast 节点,按照自己的节奏,每次走 2 步。
|
||||
fast = fast.next.next;
|
||||
// 创建 next 节点,记录 slow 真正下一个节点
|
||||
Node next = slow.next;
|
||||
// 开始反转
|
||||
slow.next = prev;
|
||||
prev = slow;
|
||||
// 设置 slow 为真正的下一个节点
|
||||
slow = next;
|
||||
}
|
||||
|
||||
// 如果 fast 非空,说明 head 是基数个节点。此时,slow 需要跳过最中间的节点
|
||||
if (fast != null) {
|
||||
slow = slow.next;
|
||||
}
|
||||
|
||||
// 开始对比 slow 和 prev
|
||||
while (slow != null && prev != null) {
|
||||
if (!Objects.equals(slow.data, prev.data)) {
|
||||
return false;
|
||||
}
|
||||
slow = slow.next;
|
||||
prev = prev.next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.match;
|
||||
|
||||
/**
|
||||
* 参考 https://blog.csdn.net/jianke0503/article/details/79735928 文章
|
||||
*
|
||||
* 实现 Rabin Karp 字符串查找
|
||||
*/
|
||||
public class RabinKarp {
|
||||
|
||||
// power 指数
|
||||
// base 计算超过范围,则返回 base
|
||||
public static int find(String src, String target, int power, int base) {
|
||||
// 计算长度
|
||||
int n = src.length();
|
||||
int m = target.length();
|
||||
|
||||
// target 的 hashcode
|
||||
int targetCode = 0;
|
||||
int mPower = 1;
|
||||
for (int i = 0; i < m; i++) {
|
||||
targetCode = (targetCode * power + target.charAt(i)) % base;
|
||||
mPower = (mPower * power) % base;
|
||||
}
|
||||
|
||||
int srcCode = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
srcCode = (srcCode * power + src.charAt(i)) % base;
|
||||
if (i < m - 1) { // 不等于的原因是,i 是从 0 开始的。
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i >= m) { // 此时,需要减掉头的
|
||||
srcCode = srcCode - ((src.charAt(i - m) * mPower) % base);
|
||||
|
||||
// 避免减成负数
|
||||
if (srcCode < 0) {
|
||||
srcCode = srcCode + base;
|
||||
}
|
||||
}
|
||||
|
||||
if (srcCode == targetCode) {
|
||||
if (src.substring(i - m + 1, i + 1).equals(target)) {
|
||||
return i - m + 1; // + 1 的原因是,i 是从 0 开始,而 m 是从 1 开始。
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String src = "2359023141526739921";
|
||||
String target = "5902";
|
||||
System.out.println(find(src, target, 31, 100));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.search;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 跳表的一种实现方法。
|
||||
* 跳表中存储的是正整数,并且存储的是不重复的。
|
||||
*
|
||||
* From https://github.com/wangzheng0822/algo/blob/master/java/17_skiplist/SkipList.java
|
||||
*
|
||||
* Author:ZHENG
|
||||
*/
|
||||
@SuppressWarnings("Duplicates")
|
||||
public class SkipList {
|
||||
|
||||
private static final int MAX_LEVEL = 16;
|
||||
|
||||
private int levelCount = 1;
|
||||
|
||||
private Node head = new Node(); // 带头链表
|
||||
|
||||
private Random r = new Random();
|
||||
|
||||
public Node find(int value) {
|
||||
Node p = head;
|
||||
for (int i = levelCount - 1; i >= 0; --i) {
|
||||
while (p.forwards[i] != null && p.forwards[i].data < value) {
|
||||
p = p.forwards[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (p.forwards[0] != null && p.forwards[0].data == value) {
|
||||
return p.forwards[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void insert(int value) {
|
||||
int level = randomLevel();
|
||||
Node newNode = new Node();
|
||||
newNode.data = value;
|
||||
newNode.maxLevel = level;
|
||||
Node[] update = new Node[level];
|
||||
for (int i = 0; i < level; ++i) {
|
||||
update[i] = head;
|
||||
}
|
||||
|
||||
// record every level largest value which smaller than insert value in update[]
|
||||
Node p = head;
|
||||
for (int i = level - 1; i >= 0; --i) {
|
||||
while (p.forwards[i] != null && p.forwards[i].data < value) {
|
||||
p = p.forwards[i];
|
||||
}
|
||||
update[i] = p;// use update save node in search path
|
||||
}
|
||||
|
||||
// in search path node next node become new node forwords(next)
|
||||
for (int i = 0; i < level; ++i) {
|
||||
newNode.forwards[i] = update[i].forwards[i];
|
||||
update[i].forwards[i] = newNode;
|
||||
}
|
||||
|
||||
// update node hight
|
||||
if (levelCount < level) levelCount = level;
|
||||
}
|
||||
|
||||
public void delete(int value) {
|
||||
Node[] update = new Node[levelCount];
|
||||
Node p = head;
|
||||
for (int i = levelCount - 1; i >= 0; --i) {
|
||||
while (p.forwards[i] != null && p.forwards[i].data < value) {
|
||||
p = p.forwards[i];
|
||||
}
|
||||
update[i] = p;
|
||||
}
|
||||
|
||||
if (p.forwards[0] != null && p.forwards[0].data == value) {
|
||||
for (int i = levelCount - 1; i >= 0; --i) {
|
||||
if (update[i].forwards[i] != null && update[i].forwards[i].data == value) {
|
||||
update[i].forwards[i] = update[i].forwards[i].forwards[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 随机 level 次,如果是奇数层数 +1,防止伪随机
|
||||
private int randomLevel() {
|
||||
int level = 1;
|
||||
for (int i = 1; i < MAX_LEVEL; ++i) {
|
||||
if (r.nextInt() % 2 == 1) {
|
||||
level++;
|
||||
}
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
public void printAll() {
|
||||
Node p = head;
|
||||
while (p.forwards[0] != null) {
|
||||
System.out.print(p.forwards[0] + " ");
|
||||
p = p.forwards[0];
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
public class Node {
|
||||
private int data = -1;
|
||||
private Node forwards[] = new Node[MAX_LEVEL];
|
||||
private int maxLevel = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.search;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 参考 {@link SkipList} ,自己实现一遍跳表。
|
||||
*
|
||||
* 通过 {@link Node} 的 forwards 数组实现,确实挺巧妙,代码量也非常精简。
|
||||
*
|
||||
* 目前,网络上找到的 Java 跳表实现,主要是 https://sylvanassun.github.io/2017/12/31/2017-12-31-skip_list/ 这种。实现方式略有差别。
|
||||
*
|
||||
* @author yunai
|
||||
*/
|
||||
@SuppressWarnings("Duplicates")
|
||||
public class SkipList2 {
|
||||
|
||||
private static final int MAX_LEVEL = 16;
|
||||
|
||||
private Random random = new Random();
|
||||
|
||||
/**
|
||||
* 总层级数
|
||||
*/
|
||||
private int levelCount = 1;
|
||||
|
||||
private Node head = new Node(null, MAX_LEVEL);
|
||||
|
||||
public Node find(int value) {
|
||||
// 自最上层索引,开始往下查询
|
||||
Node p = head;
|
||||
for (int i = levelCount - 1; i >= 0; i--) {
|
||||
while (p.forwards[i] != null && p.forwards[i].data < value) { // 这里看的会有点绕,第一次 for ,跳转到对应 i 层,后续的,就是第 i 层的不断向下指向
|
||||
p = p.forwards[i];
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否相等
|
||||
if (p.forwards[0] != null && p.forwards[0].data == value) {
|
||||
return p.forwards[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void insert(int value) {
|
||||
// 创建 Node
|
||||
int maxLevel = randomLevel();
|
||||
Node node = new Node(value, maxLevel);
|
||||
|
||||
// 寻找每一层的指向
|
||||
Node[] update = new Node[maxLevel];
|
||||
// for (int i = 0; i < maxLevel; i++) { // 初始化 node 在一层的指向 。不需要,因为下面的 for 循环,一定会给 update 数组赋值。
|
||||
// update[i] = head;
|
||||
// }
|
||||
Node p = head;
|
||||
for (int i = maxLevel - 1; i >= 0; i--) {
|
||||
while (p.forwards[i] != null && p.forwards[i].data < value) { // 这里看的会有点绕,第一次 for ,跳转到对应 i 层,后续的,就是第 i 层的不断向下指向
|
||||
p = p.forwards[i];
|
||||
}
|
||||
update[i] = p;
|
||||
}
|
||||
|
||||
// 设置指向
|
||||
for (int i = 0; i < maxLevel; i++) {
|
||||
// 设置 node 在第 i 层,指向 update[i].forwards[i]
|
||||
node.forwards[i] = update[i].forwards[i];
|
||||
// 将 update[i].forwards[i] 赋值成 node 。
|
||||
// 这样,就形成了 update[i].forwards[i] = node ,并且 node..forwards[i] = 原 update[i].forwards[i] 。可能有点绕,可以调试下
|
||||
update[i].forwards[i] = node;
|
||||
}
|
||||
|
||||
// 设置新的最高高度
|
||||
if (maxLevel > levelCount) {
|
||||
levelCount = maxLevel;
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(int value) {
|
||||
// 寻找一层对 value 应该 Node 的指向
|
||||
Node[] update = new Node[levelCount];
|
||||
Node p = head;
|
||||
for (int i = levelCount - 1; i >= 0; i--) {
|
||||
while (p.forwards[i] != null && p.forwards[i].data < value) { // 这里看的会有点绕,第一次 for ,跳转到对应 i 层,后续的,就是第 i 层的不断向下指向
|
||||
p = p.forwards[i];
|
||||
}
|
||||
update[i] = p;
|
||||
}
|
||||
|
||||
// 如果找到指定节点
|
||||
if (p.forwards[0] != null && p.forwards[0].data == value) {
|
||||
for (int i = levelCount - 1; i >= 0; i--) {
|
||||
// 指定层,有符合 value 应该 Node 的指向,进行删除
|
||||
if (update[i].forwards[i] != null && update[i].forwards[i].data == value) {
|
||||
update[i].forwards[i] = update[i].forwards[i].forwards[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int randomLevel() {
|
||||
return random.nextInt(MAX_LEVEL - 1) + 1; // 一定建立索引,避免直接添加到第 0 层。不然可能会丢失。
|
||||
// return random.nextInt(MAX_LEVEL); // 因为我们是从 1 层开始计数,可以看 levelCount 参数
|
||||
}
|
||||
|
||||
// // 随机 level 次,如果是奇数层数 +1,防止伪随机
|
||||
// private int randomLevel() {
|
||||
// int level = 1;
|
||||
// for (int i = 1; i < MAX_LEVEL; ++i) {
|
||||
// if (random.nextInt() % 2 == 1) {
|
||||
// level++;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return level;
|
||||
// }
|
||||
|
||||
/**
|
||||
* 节点
|
||||
*
|
||||
* 通过 {@link #forwards} 属性,记录在每一层的指向。
|
||||
*
|
||||
* 注意,相同 {@link #data} ,在多层,通过 {@link #forwards} 属性来实现,而不是指向。
|
||||
*/
|
||||
public class Node {
|
||||
|
||||
// TODO 芋艿,如果想实现类似 HashMap 的功能,可以把 data 改成 key + value 。
|
||||
/**
|
||||
* 数值
|
||||
*/
|
||||
private Integer data;
|
||||
|
||||
/**
|
||||
* 最高层级
|
||||
*/
|
||||
private int maxLevel;
|
||||
/**
|
||||
* 对指定层级的指向
|
||||
*/
|
||||
private Node[] forwards;
|
||||
|
||||
public Node(Integer data, int maxLevel) {
|
||||
this.data = data;
|
||||
this.maxLevel = maxLevel;
|
||||
this.forwards = new Node[maxLevel];
|
||||
// this.forwards = new Node[MAX_LEVEL];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Node{" +
|
||||
"data=" + data +
|
||||
", maxLevel=" + maxLevel +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.search;
|
||||
|
||||
public class SkipListTest {
|
||||
|
||||
public static void main2(String[] args) {
|
||||
SkipList skipList = new SkipList();
|
||||
skipList.insert(1);
|
||||
skipList.insert(2);
|
||||
skipList.insert(3);
|
||||
skipList.insert(1);
|
||||
skipList.insert(1);
|
||||
skipList.insert(1);
|
||||
skipList.delete(1);
|
||||
skipList.printAll();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
SkipList2 skipList = new SkipList2();
|
||||
// SkipList skipList = new SkipList();
|
||||
// 测试添加
|
||||
skipList.insert(2);
|
||||
skipList.insert(1);
|
||||
|
||||
// 测试查询
|
||||
System.out.println(skipList.find(1) != null);
|
||||
assert skipList.find(1) != null;
|
||||
System.out.println(skipList.find(2) != null);
|
||||
assert skipList.find(2) != null;
|
||||
System.out.println(skipList.find(3) == null); // null
|
||||
assert skipList.find(3) == null;
|
||||
|
||||
// 测试删除
|
||||
skipList.delete(1);
|
||||
System.out.println(skipList.find(1) == null); // null
|
||||
assert skipList.find(1) == null;
|
||||
System.out.println(skipList.find(2) != null);
|
||||
assert skipList.find(2) != null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.search;
|
||||
|
||||
/**
|
||||
* 使用二分查找,计算平方根。
|
||||
*/
|
||||
public class SquareTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
double result = sqrt(5, 0.00001D);
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
// precision 表示精度
|
||||
private static double sqrt(int number, double precision) {
|
||||
int rounds = 0; // 用于记录轮次,调试用途
|
||||
double low = 0;
|
||||
double high = number;
|
||||
while (low <= high) {
|
||||
double middle = low + ((high - low) / 2);
|
||||
double result = middle * middle;
|
||||
System.out.println(String.format("第 %d 轮,结果:%f", ++rounds, middle));
|
||||
|
||||
double diff = number - result;
|
||||
if (0 <= diff && diff <= precision) {
|
||||
return middle;
|
||||
}
|
||||
if (result < number) {
|
||||
low = middle;
|
||||
} else if (result > number) {
|
||||
high = middle;
|
||||
} else {
|
||||
throw new IllegalStateException("不可能出现");
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("必然有结果,还能求不出平方根");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.sort;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Random;
|
||||
|
||||
public class BucketSorterTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Random random = new Random();
|
||||
int[] array = new int[1000];
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
array[i] = random.nextInt(10000);
|
||||
}
|
||||
bucketSort(array, 100);
|
||||
}
|
||||
|
||||
// bucketSize - 指的是每个 bucket 的大小
|
||||
public static void bucketSort(int[] array, int bucketSize) {
|
||||
// 求最大最小值
|
||||
int max = Integer.MIN_VALUE;
|
||||
int min = Integer.MAX_VALUE;
|
||||
for (int value : array) {
|
||||
if (value > max) {
|
||||
max = value;
|
||||
}
|
||||
if (value < min) {
|
||||
min = value;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建桶
|
||||
int bucketCounts = (max - min) / bucketSize + 1; // 这里后面要优化下,向上取整。例如说 101 / 10 ,理论来说,应该是 11 个木桶
|
||||
ArrayList<ArrayList<Integer>> buckets = new ArrayList<>(bucketCounts); // 使用 ArrayList ,方便实现,减少扩容等等麻烦
|
||||
for (int i = 0; i < bucketCounts; i++) {
|
||||
buckets.add(new ArrayList<Integer>());
|
||||
}
|
||||
|
||||
// 添加到桶中
|
||||
for (int value : array) {
|
||||
buckets.get((value - min) / bucketSize).add(value); // -min ,因为它是起点
|
||||
}
|
||||
|
||||
// 排序每个桶
|
||||
for (ArrayList<Integer> bucket : buckets) {
|
||||
Collections.sort(bucket); // 方便
|
||||
}
|
||||
System.out.println(buckets);
|
||||
|
||||
// 打印结果
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.sort;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 堆排序
|
||||
*/
|
||||
public class HeapSorterTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (false) {
|
||||
HeapSorter heapSorter = new HeapSorter(10);
|
||||
heapSorter.insert(10);
|
||||
heapSorter.insert(3);
|
||||
heapSorter.insert(5);
|
||||
heapSorter.insert(1);
|
||||
heapSorter.insert(2);
|
||||
heapSorter.insert(20);
|
||||
System.out.println(Arrays.toString(heapSorter.heap));
|
||||
|
||||
heapSorter.remove(2);
|
||||
System.out.println(Arrays.toString(heapSorter.heap));
|
||||
}
|
||||
|
||||
if (true) {
|
||||
int[] array = {0, 10, 3, 5, 1, 2, 20};
|
||||
HeapSorter heapSorter = HeapSorter.create(array, array.length - 1);
|
||||
// System.out.println(Arrays.toString(heapSorter.heap));
|
||||
heapSorter.sort();
|
||||
}
|
||||
}
|
||||
|
||||
public static class HeapSorter {
|
||||
|
||||
/**
|
||||
* 堆
|
||||
*/
|
||||
private int[] heap;
|
||||
/**
|
||||
* 容量
|
||||
*/
|
||||
private int capacity;
|
||||
/**
|
||||
* 元素数量
|
||||
*/
|
||||
private int count;
|
||||
|
||||
public HeapSorter(int[] heap, int count) {
|
||||
this.capacity = heap.length;
|
||||
this.heap = heap;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public HeapSorter(int capacity) {
|
||||
this.capacity = capacity;
|
||||
this.heap = new int[capacity + 1]; // 因为 0 被占用了
|
||||
count = 0;
|
||||
}
|
||||
|
||||
public void insert(int value) {
|
||||
if (count >= capacity) {
|
||||
throw new IllegalStateException("容量已满");
|
||||
}
|
||||
++count;
|
||||
heap[count] = value;
|
||||
|
||||
// 自下向上堆化,如果大于父节点
|
||||
int index = count;
|
||||
while (index >> 1 > 0 && heap[index] > heap[index >> 1]) {
|
||||
swap(index, index >> 1);
|
||||
index = index >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
public int remove(int pos) {
|
||||
if (count == 0) {
|
||||
throw new IllegalStateException("不存在最大值");
|
||||
}
|
||||
int tmp = heap[pos];
|
||||
heap[pos] = heap[count];
|
||||
heap[count] = 0; // 置空,其实非必要。就是为了好看
|
||||
count--;
|
||||
|
||||
heapify(heap, count, pos);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
public void sort() {
|
||||
while (count > 1) {
|
||||
System.out.println(remove(1));
|
||||
}
|
||||
}
|
||||
|
||||
private void swap(int i, int j) {
|
||||
swap(heap, i, j);
|
||||
}
|
||||
|
||||
public static HeapSorter create(int[] heap, int count) {
|
||||
for (int i = count / 2; i >= 1; i--) {
|
||||
heapify(heap, count, i);
|
||||
}
|
||||
return new HeapSorter(heap, count);
|
||||
}
|
||||
|
||||
private static void heapify(int[] heap, int count, int pos) {
|
||||
// 自伤向下,
|
||||
while (true) {
|
||||
int maxPos = pos;
|
||||
if (pos * 2 <= count && heap[pos] < heap[pos * 2]) {
|
||||
maxPos = pos * 2;
|
||||
}
|
||||
if (pos * 2 + 1 <= count && heap[maxPos] < heap[pos * 2 + 1]) {
|
||||
maxPos = pos * 2 + 1;
|
||||
}
|
||||
// 判断相等,说明没变化
|
||||
if (maxPos == pos) {
|
||||
return;
|
||||
}
|
||||
swap(heap, pos, maxPos);
|
||||
}
|
||||
}
|
||||
|
||||
private static void swap(int[] heap, int i, int j) {
|
||||
int tmp = heap[i];
|
||||
heap[i] = heap[j];
|
||||
heap[j] = tmp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.sort;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 合并排序
|
||||
*/
|
||||
public class MergeSorterTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
{
|
||||
int[] array = new int[]{5, 4, 2, 3, 1, 2, 5, 2, 6};
|
||||
mergeSort(array);
|
||||
}
|
||||
}
|
||||
|
||||
private static void mergeSort(int[] array) {
|
||||
int[] tmpArray = new int[array.length];
|
||||
mergeSort(array, tmpArray, 0, array.length - 1);
|
||||
|
||||
System.out.println(Arrays.toString(array));
|
||||
}
|
||||
|
||||
private static void mergeSort(int[] array, int[] tmpArray, int low, int high) {
|
||||
// 递归结束,如果 low 和 high 是相同的
|
||||
if (low >= high) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 折半,进行分解
|
||||
int middle = low + (high - low >> 1); // >> 1 等价于 / 2
|
||||
mergeSort(array, tmpArray, low, middle);
|
||||
mergeSort(array, tmpArray, middle + 1, high);
|
||||
|
||||
// 合并
|
||||
merge(array, tmpArray, low, middle, high);
|
||||
}
|
||||
|
||||
private static void merge(int[] array, int[] tmpArray, int low, int middle, int high) {
|
||||
// 比较排序
|
||||
int highStart = middle + 1;
|
||||
int lowStart = low; // 需要赋值出来,是为了避免 low 被修改
|
||||
int tmpArrayIndex = low; // tmpArray 的 index
|
||||
while (lowStart <= middle && highStart <= high) { // 能够这么操作的原因是,每次递归,最终的结果都是有序的。所以就一直可以有序了。
|
||||
if (array[lowStart] > array[highStart]) {
|
||||
tmpArray[tmpArrayIndex++] = array[highStart++];
|
||||
} else {
|
||||
tmpArray[tmpArrayIndex++] = array[lowStart++];
|
||||
}
|
||||
}
|
||||
|
||||
// 将上述未赋值到 tmpArray 的,继续赋值进去
|
||||
while (lowStart <= middle) {
|
||||
tmpArray[tmpArrayIndex++] = array[lowStart++];
|
||||
}
|
||||
while (highStart <= high) {
|
||||
tmpArray[tmpArrayIndex++] = array[highStart++];
|
||||
}
|
||||
|
||||
// 将排序后的 tmpArrayIndex 赋值到 array 中,从 low 开始到 high 部分。
|
||||
System.arraycopy(tmpArray, low, array, low, high - low + 1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.sort;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 快速排序
|
||||
*/
|
||||
public class QuickSorterTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
{
|
||||
int[] array = new int[]{5, 4, 2, 3, 1, 2, 5, 2, 6};
|
||||
// int[] array = new int[]{6, 11, 8};
|
||||
quickSort(array);
|
||||
}
|
||||
}
|
||||
|
||||
private static void quickSort(int[] array) {
|
||||
quickSort(array, 0, array.length - 1);
|
||||
|
||||
System.out.println(Arrays.toString(array));
|
||||
}
|
||||
|
||||
private static void quickSort(int[] array, int low, int high) {
|
||||
if (low >= high) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 寻找 partition 位置
|
||||
// int partitionIndex = partition(array, low, high);
|
||||
int partitionIndex = partition02(array, low, high);
|
||||
|
||||
// 递归排序
|
||||
quickSort(array, low, partitionIndex - 1);
|
||||
quickSort(array, partitionIndex + 1, high);
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public static int partition(int[] array, int low, int high) {
|
||||
int partitionValue = array[high]; // 首先,选择 high 位置的值,作为 partitionValue 值
|
||||
int pos = low;
|
||||
// 遍历 array 的 low 到 high 区间,将小于 partitionValue 值的部分,顺序放到 [0, pos) 范围内。最终,pos 我们会放 partitionValue 值。
|
||||
for (int i = low; i < high; i++) {
|
||||
if (array[i] < partitionValue) {
|
||||
// 进行交换
|
||||
swap(array, i, pos);
|
||||
// pos + 1 ,用于下一个使用
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
// 将 pos 我们会放 partitionValue 值。
|
||||
swap(array, pos, high);
|
||||
|
||||
// 返回 partitionValue 所在位置
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void swap(int[] array, int pos1, int pos2) {
|
||||
if (pos1 == pos2) {
|
||||
return;
|
||||
}
|
||||
int tmp = array[pos1];
|
||||
array[pos1] = array[pos2];
|
||||
array[pos2] = tmp;
|
||||
}
|
||||
|
||||
// partition 的逻辑,基于 swap ,需要 3 次操作
|
||||
// partition02 的逻辑,基于赋值来做,只需要 1 次操作。相比来说,性能更好。
|
||||
// 当然,第一次看 partition02 的逻辑,可能会有点懵逼。大体的理解是,low 和 high 之间,被不断夹紧,把比 pivot 大的放到右侧,比 pivot 小的放到左侧。
|
||||
// 本质可以理解成:
|
||||
// 1. pivot = arr[low]; =》 A -> B
|
||||
// 2. arr[low] = arr[high]; =》 B -> C
|
||||
// 3. arr[high] = arr[low]; =》 C -> D
|
||||
// 4. 重复循环,我们最终找到真正的 D ,将 原 B ,也就是 A ,复制上去。
|
||||
private static int partition02(int[] arr, int low, int high) {
|
||||
int pivot = arr[low]; //枢轴记录
|
||||
// 循环,达到 arr[low] 左边是比它小,右边是比它大。
|
||||
while (low < high) { // 实际上,最终 break 的条件是,low 和 high 相等。具体可以看里面的两个 while
|
||||
while (low < high && arr[high] >= pivot) --high; // 因为 high 原来就在右侧,所以不需要移动
|
||||
arr[low] = arr[high]; // 交换比枢轴小的记录到左端
|
||||
|
||||
while (low < high && arr[low] <= pivot) ++low; // 因为 low 原来就在左侧,所以不需要移动
|
||||
arr[high] = arr[low]; // 交换比枢轴小的记录到右端
|
||||
}
|
||||
//扫描完成,枢轴到位
|
||||
arr[low] = pivot;
|
||||
//返回的是枢轴的位置
|
||||
return low;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.sort;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 基数排序
|
||||
*
|
||||
* 每个位的排序,通过桶排序实现,从而实现 k * O(n) 的复杂度
|
||||
*/
|
||||
public class RadixSorterTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
int[] array = new int[]{
|
||||
23,
|
||||
50,
|
||||
100,
|
||||
1,
|
||||
10,
|
||||
21,
|
||||
50,
|
||||
};
|
||||
|
||||
radixSort(array);
|
||||
}
|
||||
|
||||
private static void radixSort(int[] array) {
|
||||
int digits = getMaxDigits(array);
|
||||
for (int digit = 0; digit < digits; digit++) {
|
||||
radixSort(array, digit);
|
||||
}
|
||||
|
||||
System.out.println(Arrays.toString(array));
|
||||
}
|
||||
|
||||
private static void radixSort(int[] array, int digit) {
|
||||
// 用于后面,获得第 digit 位
|
||||
int base = (int) Math.pow(10, digit);
|
||||
|
||||
// 创建桶
|
||||
int bucketCounts = 10;
|
||||
ArrayList<ArrayList<Integer>> buckets = new ArrayList<>(bucketCounts);
|
||||
for (int i = 0; i < bucketCounts; i++) {
|
||||
buckets.add(new ArrayList<>());
|
||||
}
|
||||
|
||||
// 添加到桶中
|
||||
for (int value : array) {
|
||||
int bucketIndex = value / base % bucketCounts;
|
||||
buckets.get(bucketIndex).add(value);
|
||||
}
|
||||
|
||||
// 顺序输出,自然有序
|
||||
int index = 0;
|
||||
for (ArrayList<Integer> bucket : buckets) {
|
||||
for (Integer value : bucket) {
|
||||
array[index++] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int getMaxDigits(int[] array) {
|
||||
int max = Integer.MIN_VALUE;
|
||||
for (int value : array) {
|
||||
if (value > max) {
|
||||
max = value;
|
||||
}
|
||||
}
|
||||
int digits = 0;
|
||||
while (max > 0) {
|
||||
digits++;
|
||||
max = max / 10;
|
||||
}
|
||||
return digits;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.sort;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 基于快速排序的方式,实现第 k 大的数
|
||||
*/
|
||||
public class TheFirstBigKTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
{
|
||||
int[] array = new int[]{5, 4, 2, 3, 1, 2, 5, 2, 6};
|
||||
// int[] array = new int[]{6, 11, 8};
|
||||
// quickSort(array, 1);
|
||||
// quickSort(array, 2);
|
||||
// quickSort(array, 3);
|
||||
// quickSort(array, 4);
|
||||
quickSort(array, 5);
|
||||
}
|
||||
}
|
||||
|
||||
private static void quickSort(int[] array, int k) {
|
||||
if (k > array.length) {
|
||||
throw new IllegalStateException("k 不能大于最大数组");
|
||||
}
|
||||
quickSort(array, k - 1, 0, array.length - 1);
|
||||
|
||||
System.out.println(Arrays.toString(array));
|
||||
System.out.println("答案 k :" + array[k - 1]);
|
||||
}
|
||||
|
||||
private static void quickSort(int[] array, int k, int low, int high) {
|
||||
if (low >= high) {
|
||||
return;
|
||||
}
|
||||
|
||||
int partition = partition(array, low, high);
|
||||
if (partition == k) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (partition < k) {
|
||||
quickSort(array, k, partition + 1, high);
|
||||
} else {
|
||||
quickSort(array, k, low, partition - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
private static int partition(int[] array, int low, int high) {
|
||||
int partitionValue = array[high]; // 首先,选择 high 位置的值,作为 partitionValue 值
|
||||
int pos = low;
|
||||
// 遍历 array 的 low 到 high 区间,将小于 partitionValue 值的部分,顺序放到 [0, pos) 范围内。最终,pos 我们会放 partitionValue 值。
|
||||
for (int i = low; i < high; i++) {
|
||||
if (array[i] < partitionValue) {
|
||||
// 进行交换
|
||||
swap(array, i, pos);
|
||||
// pos + 1 ,用于下一个使用
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
// 将 pos 我们会放 partitionValue 值。
|
||||
swap(array, pos, high);
|
||||
|
||||
// 返回 partitionValue 所在位置
|
||||
return pos;
|
||||
}
|
||||
|
||||
private static void swap(int[] array, int pos1, int pos2) {
|
||||
if (pos1 == pos2) {
|
||||
return;
|
||||
}
|
||||
int tmp = array[pos1];
|
||||
array[pos1] = array[pos2];
|
||||
array[pos2] = tmp;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab09.tree;
|
||||
|
||||
/**
|
||||
* MySQL B+Tree
|
||||
*/
|
||||
public class MySQLBTreePlusTest {
|
||||
|
||||
/**
|
||||
* 非叶子节点
|
||||
*/
|
||||
public static class Node {
|
||||
|
||||
/**
|
||||
* 5 叉树
|
||||
*/
|
||||
public static int m = 5;
|
||||
|
||||
/**
|
||||
* 键值的数组
|
||||
*
|
||||
* m - 1 的原因是,keywords 代表的是区间。
|
||||
*
|
||||
* children[0] 的范围是 [ -无穷, keywords[0] ]
|
||||
* children[1] 的泛微是
|
||||
*/
|
||||
private int[] keywords = new int[m - 1];
|
||||
|
||||
/**
|
||||
* 保存子节点的指针
|
||||
*/
|
||||
private Node[] children = new Node[m];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 叶子节点
|
||||
*/
|
||||
public static class LeafNode {
|
||||
|
||||
/**
|
||||
* 假设每个叶子节点存储三个数据行的键值和数据地址信息
|
||||
*/
|
||||
public static int k = 3;
|
||||
|
||||
/**
|
||||
* 数据行的键值
|
||||
*
|
||||
* 不同于 {@link Node#keywords} ,这里表示的是具体值
|
||||
*/
|
||||
private int[] keywords = new int[k];
|
||||
/**
|
||||
* 数据航的地址值
|
||||
*/
|
||||
private int[] dataAddresses = new int[k];
|
||||
|
||||
/**
|
||||
* 前置的叶子节点,用于区间检索
|
||||
*/
|
||||
private LeafNode prev;
|
||||
/**
|
||||
* 后置的叶子节点,用于区间检索
|
||||
*/
|
||||
private LeafNode next;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.4.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>lab-10</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,22 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab10;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class Controller {
|
||||
|
||||
@GetMapping("/hello")
|
||||
public String hello() {
|
||||
// System.out.println(Thread.currentThread().getName());
|
||||
return "world";
|
||||
}
|
||||
|
||||
@GetMapping("/sleep")
|
||||
public String sleep() throws InterruptedException {
|
||||
Thread.sleep(100L);
|
||||
// System.out.println(Thread.currentThread().getName());
|
||||
return "world";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab10;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpringMVCApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringMVCApplication.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab10;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class TestListener implements ApplicationListener<ApplicationEvent> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
System.out.println("事件:" + event);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab10;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
|
||||
//@Component
|
||||
public class UserHealthIndicator implements HealthIndicator {
|
||||
|
||||
/**
|
||||
* user监控 访问: http://localhost:8088/health
|
||||
*
|
||||
* @return 自定义Health监控
|
||||
*/
|
||||
@Override
|
||||
public Health health() {
|
||||
return new Health.Builder().withDetail("usercount", 10) //自定义监控内容
|
||||
.withDetail("userstatus", "up").down().build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab10.lifecycle;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class ServerLifeCycleConfiguration {
|
||||
|
||||
@Bean
|
||||
public ServerLifeCycleHealthIndicator serverLifeCycleHealthIndicator() {
|
||||
return new ServerLifeCycleHealthIndicator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServerLifeCycleListener serverLifeCycleListener() {
|
||||
return new ServerLifeCycleListener(this.serverLifeCycleHealthIndicator());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab10.lifecycle;
|
||||
|
||||
// TODO sleep 时长的配置
|
||||
public class ServerLifeCycleConfigurationProperties {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab10.lifecycle;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
|
||||
public class ServerLifeCycleHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
/**
|
||||
* 服务状态
|
||||
*
|
||||
* 启动阶段:
|
||||
* 1. 项目初始启动时,状态为 OUT_OF_SERVICE 不提供服务。
|
||||
* 2. 服务启动完成(ApplicationReadyEvent)时,状态为 UP 启动。
|
||||
* 3. 服务启动失败(ApplicationFailedEvent)时,状态 DOWN 关闭。
|
||||
*
|
||||
* 关闭阶段:
|
||||
* 1. 服务开始关闭(ContextClosedEvent)时,状态为 OUT_OF_SERVICE 不提供服务。
|
||||
* 2. 因为服务关闭完成,不存在事件,所以暂时不处理。
|
||||
*
|
||||
* 具体的状态变更,通过
|
||||
*/
|
||||
private volatile Status status = Status.OUT_OF_SERVICE;
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
builder.status(status);
|
||||
}
|
||||
|
||||
public void up() {
|
||||
this.status = Status.UP;
|
||||
}
|
||||
|
||||
public void down() {
|
||||
this.status = Status.DOWN;
|
||||
}
|
||||
|
||||
public void outOfService() {
|
||||
this.status = Status.OUT_OF_SERVICE;
|
||||
}
|
||||
|
||||
public Status status() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab10.lifecycle;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.context.event.ApplicationFailedEvent;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextClosedEvent;
|
||||
|
||||
public class ServerLifeCycleListener implements ApplicationListener<ApplicationEvent> {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private ServerLifeCycleHealthIndicator healthIndicator;
|
||||
|
||||
public ServerLifeCycleListener(ServerLifeCycleHealthIndicator healthIndicator) {
|
||||
this.healthIndicator = healthIndicator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
if (event instanceof ApplicationReadyEvent) {
|
||||
this.handleApplicationReadyEvent((ApplicationReadyEvent) event);
|
||||
} else if (event instanceof ApplicationFailedEvent) {
|
||||
this.handleApplicationFailedEvent((ApplicationFailedEvent) event);
|
||||
} else if (event instanceof ContextClosedEvent) {
|
||||
this.handleContextClosedEvent((ContextClosedEvent) event);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void handleApplicationReadyEvent(ApplicationReadyEvent event) {
|
||||
healthIndicator.up();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void handleApplicationFailedEvent(ApplicationFailedEvent event) {
|
||||
healthIndicator.down();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void handleContextClosedEvent(ContextClosedEvent event) {
|
||||
// 标记不提供服务
|
||||
healthIndicator.outOfService();
|
||||
|
||||
// sleep 等待负载均衡完成健康检查
|
||||
for (int i = 0; i < 20; i++) { // TODO 20 需要配置
|
||||
logger.info("[handleContextClosedEvent][优雅关闭,第 {} sleep 等待负载均衡完成健康检查]", i);
|
||||
try {
|
||||
Thread.sleep(1000L);
|
||||
} catch (InterruptedException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package cn.iocoder.springboot.labs.lab10.lifecycle;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController // TODO rest 没生效,得排查下。
|
||||
@RequestMapping("/") // TODO 可配置
|
||||
public class StatusController {
|
||||
|
||||
@Autowired
|
||||
private ServerLifeCycleHealthIndicator serverLifeCycleHealthIndicator;
|
||||
|
||||
@RequestMapping("/status")
|
||||
public ResponseEntity<String> status() {
|
||||
Status status = serverLifeCycleHealthIndicator.status();
|
||||
// 成功
|
||||
if (Status.UP == status) {
|
||||
return new ResponseEntity<>(status.getDescription(), HttpStatus.OK);
|
||||
}
|
||||
// 失败
|
||||
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(status.getDescription());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
management.endpoint.health.show-details=always
|
||||
server.port=9080
|
||||
3
pom.xml
3
pom.xml
@@ -18,9 +18,6 @@
|
||||
<!-- <module>lab-05-benchmark-tomcat-jetty-undertow</module>-->
|
||||
<!-- <module>lab-06</module>-->
|
||||
<!-- <module>lab-07</module>-->
|
||||
<!-- <module>lab-08</module>-->
|
||||
<!-- <module>lab-09</module>-->
|
||||
<!-- <module>lab-10</module>-->
|
||||
<!-- <module>lab-11-spring-data-redis</module>-->
|
||||
<!-- <module>lab-12-mybatis</module>-->
|
||||
<!-- <module>lab-13-spring-data-jpa</module>-->
|
||||
|
||||
Reference in New Issue
Block a user