feat(ForJdk17): 添加 LeetCode 题目解答和 Excel 导出功能

- 新增 LeetCode221、LeetCode673 和 LeetCode931 的解答代码
- 实现了每日温度计算和二叉树循环移位算法
- 添加了 Excel 导出用户列表的功能
- 更新了 SpringDemo项目的依赖,增加了 Apache POI- 移除了 TransactionConfig 类的代码
This commit is contained in:
whai 2024-11-21 14:54:24 +08:00
parent d9b00d6d15
commit 2b3f4c8995
8 changed files with 494 additions and 133 deletions

View File

@ -1,6 +1,7 @@
package cn.whaifree.interview.Dws; package cn.whaifree.interview.Dws;
import cn.whaifree.leetCode.model.TreeNode; import cn.whaifree.leetCode.model.TreeNode;
import org.junit.Test;
import java.util.*; import java.util.*;
@ -15,8 +16,9 @@ public class P1 {
class Solution { class Solution {
/** /**
* 代码中的类名方法名参数名已经指定请勿修改直接返回方法规定的值即可 * 代码中的类名方法名参数名已经指定请勿修改直接返回方法规定的值即可
* * <p>
* 每日温度 * 每日温度
*
* @param dailyTemperatures int整型一维数组 * @param dailyTemperatures int整型一维数组
* @return int整型一维数组 * @return int整型一维数组
*/ */
@ -42,49 +44,71 @@ public class P1 {
class Solution { class Solution {
static class Node{
int parentIndex;
int currentIndex;
int flag;
TreeNode currentNode;
public Node(int parentIndex, int currentIndex, int flag, TreeNode currentNode) { public static void main(String[] args) {
Solution solution = new Solution();
// {1,2,3,#,#,4,5},1
TreeNode treeNode = TreeNode.constructTree(new Integer[]{1, 2, 3, null, null, 4, 5});
System.out.println(solution.cyclicShiftTree(treeNode, 1));
}
// Node类封装了节点的层次信息便于后续重构指针
static class Node {
int parentIndex;// 父节点在当前层的位置
int currentIndex; // 当前节点在该层的索引位置
boolean leftFlag; // 标记当前节点是左孩子(0)还是右孩子(1)
TreeNode currentNode; // 当前节点的引用
public Node(int parentIndex, int currentIndex, boolean leftFlag, TreeNode currentNode) {
this.parentIndex = parentIndex; this.parentIndex = parentIndex;
this.currentIndex = currentIndex; this.currentIndex = currentIndex;
this.flag = flag; this.leftFlag = leftFlag;
this.currentNode = currentNode; this.currentNode = currentNode;
} }
} }
/** /**
* https://blog.csdn.net/ouyang_peng/article/details/143254632 * https://blog.csdn.net/ouyang_peng/article/details/143254632
* *
*
* @param root TreeNode类 * @param root TreeNode类
* @param k int整型 * @param k int整型
* @return TreeNode类 * @return TreeNode类
*/ */
public TreeNode cyclicShiftTree(TreeNode root, int k) { public TreeNode cyclicShiftTree(TreeNode root, int k) {
// write code here if (root == null) return null; //
// 存储每层的节点信息最后用来重构
List<List<Node>> levels = new ArrayList<>(); List<List<Node>> levels = new ArrayList<>();
Queue<Node> queue = new LinkedList<>(); Queue<Node> queue = new LinkedList<>();
queue.offer(new Node(0,0,0,root)); // 根节点加入队列
int parentNum = 1; queue.offer(new Node(0, 0, true, root));
int nextNum = 0;
List<Node> tempLevel = new ArrayList<>(); // `parentNum`记录当前层节点数`nextNum`记录下一层节点数
int parentNum = 1; // 根节点只有1个节点
int nextNum = 0; // 层次遍历每次进入一个到这一层++就能统计这一层的元素个数
List<Node> tempLevel = new ArrayList<>(); // 当前层的节点列表
while (!queue.isEmpty()) { while (!queue.isEmpty()) {
Node node = queue.poll(); Node node = queue.poll();
tempLevel.add(node); tempLevel.add(node); // 加入当前层
parentNum--; parentNum--;
if (node.currentNode.left != null) { if (node.currentNode.left != null) {
queue.offer(new Node(node.currentIndex,nextNum++,0,node.currentNode.left)); queue.offer(
new Node(
node.currentIndex, // 父节点位置 node为父亲节点在当前层的位置
nextNum++, // 当前节点位置
true,
node.currentNode.left
)
);
} }
if (node.currentNode.right != null) { if (node.currentNode.right != null) {
queue.offer(new Node(node.currentIndex,nextNum++,1,node.currentNode.right)); queue.offer(new Node(node.currentIndex, nextNum++, false, node.currentNode.right));
} }
if (parentNum == 0) { if (parentNum == 0) {
// 每层最后一个元素
parentNum = nextNum; parentNum = nextNum;
nextNum = 0; nextNum = 0;
levels.add(tempLevel); levels.add(tempLevel);
@ -93,20 +117,47 @@ class Solution {
} }
int depth = levels.size() - 1; int depth = levels.size() - 1;
// 从最底层开始逐层向上进行位移操作
// 对于每一层首先计算出这一层需要位移的步数然后根据位移步数调整每个节点的左右子节点指针
for (int i = depth; i > 0; i--) { for (int i = depth; i > 0; i--) {
List<Node> parentLev = levels.get(i - 1); List<Node> parentLev = levels.get(i - 1); // 上一层的节点
int parentSize = parentLev.size(); int parentSize = parentLev.size();
// 这一层节点左右都设置为空
for (Node node : parentLev) { for (Node node : parentLev) {
node.currentNode.left = null; node.currentNode.left = null;
node.currentNode.right = null; node.currentNode.right = null;
} }
// 计算这一层需要位移的位置位移后在哪个父节点之下
// 上一层的个数决定位移个数
/**
* 比如
* 1
\
3
/ \
4 5
第3层的位移个数是根据第二层有几个元素确定的这个位置和父亲节点的距离为move
*/
int move = k % (2 * parentSize); int move = k % (2 * parentSize);
tempLevel = levels.get(i); tempLevel = levels.get(i); // 本层
for (Node node : tempLevel) { for (Node node : tempLevel) {
int targetIndex = node.flag == 0 ? (node.parentIndex + move / 2) % parentSize : (node.parentIndex + (move + 1) / 2) % parentSize; int targetIndex = 0; // 在本层的新位置
int targetFlag = node.flag == 0?move%2:(move+1); if (node.leftFlag) {
targetIndex = (node.parentIndex + move / 2) % parentSize;
} else {
targetIndex = (node.parentIndex + (move + 1) / 2) % parentSize;
}
int targetFlag = 0;
if (node.leftFlag) {
targetFlag = move % 2;
} else {
targetFlag = (move + 1) % 2;
}
Node targetP = parentLev.get(targetIndex); Node targetP = parentLev.get(targetIndex);
if (targetFlag == 0) { if (targetFlag == 0) {
targetP.currentNode.left = node.currentNode; targetP.currentNode.left = node.currentNode;

View File

@ -0,0 +1,57 @@
package cn.whaifree.leetCode;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/11/20 12:20
* @注释
*/
public class LeetCode221 {
@Test
public void test() {
Solution solution = new Solution();
System.out.println(solution.maximalSquare(new char[][]{{'1', '0', '1', '0', '0'}, {'1', '0', '1', '1', '1'}, {'1', '1', '1', '1', '1'}, {'1', '0', '0', '1', '0'}}));
}
class Solution {
/**
* 如果三个位置都为x那么本节点就是变长为x的
*
* @param matrix
* @return
*/
public int maximalSquare(char[][] matrix) {
int maxLen = 0;
int[][] dp = new int[matrix.length][matrix[0].length];
for (int i = 0; i < matrix[0].length; i++) {
if (matrix[0][i] == '1') {
dp[0][i] = 1;
maxLen = 1;
}
}
for (int i = 0; i < matrix.length; i++) {
if (matrix[i][0] == '1') {
dp[i][0] = 1;
maxLen = 1;
}
}
for (int i = 1; i < matrix.length; i++) {
for (int j = 1; j < matrix[0].length; j++) {
if (matrix[i - 1][j] == '1' && matrix[i][j - 1] == '1' && matrix[i - 1][j - 1] == '1') {
if (matrix[i][j] == '1') {
dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
}
} else if (matrix[i][j] == '1') {
dp[i][j] = 1;
}
maxLen = Math.max(maxLen, dp[i][j]);
}
}
return maxLen * maxLen;
}
}
}

View File

@ -0,0 +1,85 @@
package cn.whaifree.leetCode;
import org.junit.Test;
import java.util.Arrays;
import java.util.function.IntPredicate;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/11/20 12:57
* @注释
*/
public class LeetCode673 {
@Test
public void test() {
// 2 2 2 2 2
System.out.println(new Solution().findNumberOfLIS(new int[]{1}));
}
class Solution {
/**
* dp[i] 表示0-i最长递增子序列子序列长度
* count[i] 以nums[i]为结尾的字符串最长递增子序列的个数为count[i]
*
* @param nums
* @return
*/
public int findNumberOfLIS(int[] nums) {
if (nums.length <= 1) return nums.length;
int max = 0;
int[] dp = new int[nums.length];
// 初始化
Arrays.fill(dp, 1);
int[] count = new int[nums.length];
Arrays.fill(count, 1);
for (int i = 1; i < nums.length; i++) {
int left = i - 1;
while (left >= 0) {
if (nums[left] < nums[i]) {
if (dp[left] + 1 > dp[i]) {
// 找到一个更长的子序列
// 那么数量应该为left的count表示最长递增子序列的个数更新为left处的
count[i] = count[left];
} else if (dp[left] + 1 == dp[i]) {
// 如果找到的子序列长度和原来的一样那么就加上left处的
// 增加left处的最长递增因为这时最长递增子序列的长度都一样
count[i] += count[left];
}
dp[i] = Math.max(dp[i], dp[left] + 1); // 最长递增子序列的长度
}
max = Math.max(max, dp[i]);
left--;
}
}
int res = 0;
// 统计所有最长递增子序列的个数为max的
for (int i = 0; i < nums.length; i++) {
if (dp[i] == max) {
res += count[i];
}
}
return res;
}
}
}
class Test989 {
private int a = 10;
int b = 20;
static int c = 30;
public static void main(String[] args) {
Test989 t = new Test989(); // 创建 Test 类的对象
System.out.println(t.a); // 错误a private
System.out.println(t.b); // 正确b 是实例变量
// System.out.println(this.c); // 正确c static 变量
}
}

View File

@ -0,0 +1,58 @@
package cn.whaifree.leetCode;
import org.junit.Test;
import java.util.Arrays;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/11/20 11:59
* @注释
*/
public class LeetCode931 {
@Test
public void test() {
Solution solution = new Solution();
// [[2,1,3],[6,5,4],[7,8,9]]
System.out.println(solution.minFallingPathSum(new int[][]{{2, 1}, {6, 5}}));
}
class Solution {
/**
* int[i][j] 表示从最顶到i j 的价值
*
* 第一层为对应格子的值
*
* 最最左边和最右边只能由 2个推出
*
* @param matrix
* @return
*/
public int minFallingPathSum(int[][] matrix) {
int n = matrix.length;
int[][] dp = new int[n][n];
// 第一层
for (int i = 0; i < matrix.length; i++) {
dp[0][i] = matrix[0][i];
}
for (int i = 1; i < n; i++) {
// 每层 第一个元素只能由上一个
dp[i][0] = Math.min(dp[i - 1][0], dp[i - 1][1])+ matrix[i][0];
for (int j = 1; j < n - 1; j++) {
dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i - 1][j]), dp[i - 1][j + 1]) + matrix[i][j];
}
dp[i][n - 1] = Math.min(dp[i - 1][n - 1], dp[i - 1][n - 2]) + matrix[i][n - 1];
}
int min = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
min = Math.min(min, dp[n - 1][i]);
}
return min;
}
}
}

View File

@ -30,6 +30,20 @@
<java.version>17</java.version> <java.version>17</java.version>
</properties> </properties>
<dependencies> <dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.0.0</version>
</dependency>
<!-- caffeine 缓存使用姿势 --> <!-- caffeine 缓存使用姿势 -->
<dependency> <dependency>
<groupId>com.github.ben-manes.caffeine</groupId> <groupId>com.github.ben-manes.caffeine</groupId>

View File

@ -1,97 +1,97 @@
package cn.whaifree.springdemo.config; //package cn.whaifree.springdemo.config;
//
import jakarta.annotation.Resource; //import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; //import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; //import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; //import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager; //import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager; //import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition; //import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionManager; //import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.TransactionStatus; //import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.TransactionManagementConfigurer; //import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import org.springframework.transaction.annotation.Transactional; //import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition; //import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionCallback; //import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate; //import org.springframework.transaction.support.TransactionTemplate;
//
import javax.sql.DataSource; //import javax.sql.DataSource;
//
/** ///**
* @version 1.0 // * @version 1.0
* @Author whai文海 // * @Author whai文海
* @Date 2024/11/15 16:37 // * @Date 2024/11/15 16:37
* @注释 // * @注释
*/ // */
@Configuration //@Configuration
@Slf4j //@Slf4j
public class TransactionConfig implements TransactionManagementConfigurer { //public class TransactionConfig implements TransactionManagementConfigurer {
//
//
@Autowired // @Autowired
private TransactionTemplate transactionTemplate; // private TransactionTemplate transactionTemplate;
//
//配置事务管理器 // //配置事务管理器
@Bean // @Bean
public TransactionManager transactionManager(DataSource dataSource) { // public TransactionManager transactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource); // DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
// 打印参数 // // 打印参数
log.info("transactionManager: {}", transactionManager); // log.info("transactionManager: {}", transactionManager);
log.info("dataSource: {}", dataSource); // log.info("dataSource: {}", dataSource);
return transactionManager; // return transactionManager;
} // }
//
@Resource(name="txManager1") // @Resource(name="txManager1")
private PlatformTransactionManager txManager1; // private PlatformTransactionManager txManager1;
//
// 创建事务管理器1 // // 创建事务管理器1
@Bean(name = "txManager1") // @Bean(name = "txManager1")
public PlatformTransactionManager txManager(DataSource dataSource) { // public PlatformTransactionManager txManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource); // return new DataSourceTransactionManager(dataSource);
} // }
//
@Override // @Override
public TransactionManager annotationDrivenTransactionManager() { // public TransactionManager annotationDrivenTransactionManager() {
return txManager1; // return txManager1;
} // }
//
@Transactional(value="txManager1") // @Transactional(value="txManager1")
public void addUser() { // public void addUser() {
//
} // }
//
public void addUser2() { // public void addUser2() {
DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition(); // DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); // transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED); // transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
TransactionStatus transaction = txManager1.getTransaction(transactionDefinition); // TransactionStatus transaction = txManager1.getTransaction(transactionDefinition);
try { // try {
txManager1.commit(transaction); // txManager1.commit(transaction);
} catch (Exception e) { // } catch (Exception e) {
txManager1.rollback(transaction); // txManager1.rollback(transaction);
} // }
} // }
//
/** // /**
* 编程事务 // * 编程事务
* TransactionTemplate // * TransactionTemplate
* PlatformTransactionManager // * PlatformTransactionManager
* DataSourceTransactionManager // * DataSourceTransactionManager
*/ // */
//
public void adduser3() { // public void adduser3() {
Object execute = transactionTemplate.execute(new TransactionCallback<Object>() { // Object execute = transactionTemplate.execute(new TransactionCallback<Object>() {
@Override // @Override
public Object doInTransaction(TransactionStatus status) { // public Object doInTransaction(TransactionStatus status) {
return null; // return null;
} // }
}); // });
} // }
//
//
} //}
//
class Tran{ //class Tran{
//
} //}

View File

@ -0,0 +1,96 @@
package cn.whaifree.springdemo.controller.workBook;
import cn.hutool.http.server.HttpServerResponse;
import cn.hutool.poi.excel.WorkbookUtil;
import com.google.common.collect.Lists;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Data;
import lombok.Setter;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/11/20 16:35
* @注释
*/
@Controller
@RequestMapping("/workBook")
public class WorkBookController {
@GetMapping(value = "/exportUser")
public void export(HttpServletResponse response) throws UnsupportedEncodingException {
// WorkBook
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder
.encode("导出成员工时.xlsx", "UTF-8"));
response.setContentType("application/vnd.ms-excel;charset=utf-8");
try (
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("template/project_member_workHours.xlsx");
OutputStream out = response.getOutputStream()
) {
Workbook query = query(inputStream);
query.write(out);
out.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public List<User> getUserList() {
List<User> userList = new ArrayList<>();
for (int i = 0; i < 30; i++) {
User user = new User();
user.setNickName("张三" + i);
user.setDepartment("研发部");
user.setFullName("张三" + i);
userList.add(user);
}
return userList;
}
public Workbook query(InputStream inputStream) {
Workbook workbook = WorkbookUtil.createSXSSFBook(inputStream);
Sheet sheet = workbook.getSheetAt(0); // 获取第一个工作表
List<User> userList = getUserList();
for (int i = 0; i < userList.size(); i++) {
Row row = sheet.createRow(i + 1);
Cell cell = row.createCell(0);
cell.setCellValue(userList.get(i).getNickName());
cell = row.createCell(1);
cell.setCellValue(userList.get(i).getFullName());
cell = row.createCell(2);
cell.setCellValue(userList.get(i).getDepartment());
}
return workbook;
}
@Data
@Setter
static class User {
private String nickName;
private String fullName;
private String department;
}
}