leecode更新

This commit is contained in:
markilue 2023-02-20 14:58:49 +08:00
parent 89e6456d89
commit 947ed0fbf5
6 changed files with 357 additions and 2 deletions

View File

@ -13,7 +13,7 @@ import java.util.List;
import java.util.Properties;
/**
* kafka消费者
* kafka消费者自动提交offset
*
*
*/

View File

@ -15,7 +15,7 @@ import java.util.Map;
public class TimeStampInterceptor implements ProducerInterceptor<String,String> {
/**
* 拦截器的心处理方法
* 拦截器的心处理方法
* @param record 被拦截处理的消息
* @return
*/

View File

@ -0,0 +1,119 @@
package com.markilue.leecode.dynamic.second;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
*@Author: markilue
*@CreateTime: 2023-02-20 09:40
*@Description:
* TODO 力扣139 单词拆分:
* 给你一个字符串 s 和一个字符串列表 wordDict 作为字典请你判断是否可以利用字典中出现的单词拼接出 s
* 注意不要求字典中出现的单词全部都使用并且字典中的单词可以重复使用
*@Version: 1.0
*/
public class T17_WordBreak {
@Test
public void test(){
String s = "leetcode";
List<String> wordDict = new ArrayList<>(Arrays.asList("leet", "code"));
System.out.println(wordBreak(s,wordDict));
}
/**
* 思路: 难点查分之后如何去和wordDict中的单词进行匹配如果匹配应该从何处进行匹配
* TODO DP五部曲:
* 1.dp定义: dp[i][j]表示使用words[0-i]能否匹配上s[0-j]
* 2.dp状态转移方程: dp[i][j] :使用当前这个word或者不使用当前这个word
* dp[i][j]=dp[i-1][j] || dp[i][j-word[i].length]&&s[j-word[i].length - j]==words[i]
* 3.dp初始化: dp[i][0]=true
* 4.dp遍历顺序: 先遍历s再遍历words 因为words里面的单词可以重复使用
* 5.dp举例推导
* 速度击败71.9% 内存击败74.85% 6ms
* @param s
* @param wordDict
* @return
*/
public boolean wordBreak(String s, List<String> wordDict) {
boolean[] dp = new boolean[s.length() + 1];
dp[0] = true;
for (int i = 0; i < dp.length; i++) {
for (int j = 0; j < wordDict.size(); j++) {
int length = wordDict.get(j).length();
if (i >= length) dp[i] |= (dp[i - length] && isEqual(i, length, s, wordDict.get(j)));
}
}
return dp[s.length()];
}
public boolean isEqual(int j, int length, String s, String wordDict) {
return wordDict.equals(s.substring(j - length, j));
}
/**
* 官方一维dp优化: 1.for循环优化2.等于true不需要继续遍历words往下判断了
* 速度击败93.3% 内存击败92.28% 2ms
* @param s
* @param wordDict
* @return
*/
public boolean wordBreak1(String s, List<String> wordDict) {
boolean[] dp = new boolean[s.length() + 1];
dp[0] = true;
for (int i = 1; i <= s.length(); i++) {
for (String word : wordDict) {
int len = word.length();
if (i >= len && dp[i - len] && word.equals(s.substring(i - len, i))) {
dp[i] = true;//
break;
}
}
}
return dp[s.length()];
}
/**
* 官方最快:回溯+记忆化搜索
* 速度击败100% 内存击败99.56%
* @param s
* @param wordDict
* @return
*/
public boolean wordBreak3(String s, List<String> wordDict) {
int[] memo = new int[s.length()];
Arrays.fill(memo, -1);
return check(s, 0, wordDict, memo);
}
private boolean check(String s, int idx, List<String> wordDict, int[] memo) {
if (idx == s.length()) return true;
if (memo[idx] != -1) return memo[idx] != 0;//记忆化回溯
for (String word : wordDict)
if (s.startsWith(word, idx) && check(s, idx + word.length(), wordDict, memo)) {
memo[idx] = 1;//找到了
return true;
}
//没找到
memo[idx] = 0;
return false;
}
}

View File

@ -0,0 +1,74 @@
package com.markilue.leecode.dynamic.second;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
*@Author: markilue
*@CreateTime: 2023-02-20 10:39
*@Description:
* TODO 力扣198题 打家劫舍:
* 你是一个专业的小偷计划偷窃沿街的房屋每间房内都藏有一定的现金影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统如果两间相邻的房屋在同一晚上被小偷闯入系统会自动报警
* 给定一个代表每个房屋存放金额的非负整数数组计算你 不触动警报装置的情况下 一夜之内能够偷窃到的最高金额
*@Version: 1.0
*/
public class T18_Rob {
@Test
public void test(){
int[] nums ={1,2,3,1};
System.out.println(rob(nums));
}
/**
* 思路: 打家劫舍问题: 本质上可以分为 偷不偷当前在偷和不偷之间找最优
* TODO DP五部曲:
* 1.dp定义: dp[i][0]表示不偷i的最大值 dp[i][1]表示偷i的最大值
* 2.dp状态转移方程:
* 1.dp[i][0] 不偷当前 : 昨天偷了今天不偷 或者 昨天没偷今天偷了
* dp[i][0]=max(dp[i-1][0],dp[i-1][1])
* 2.dp[i][1] 偷当前 昨天没偷今天偷了
* dp[i][1]=dp[i-1][0]+nums[i]
* 3.dp初始化:dp[0][0]=0; dp[0][1]=nums[0]
* 4.dp遍历顺序:从前往后
* 5.dp举例推导:
* @param nums
* @return
*/
public int rob(int[] nums) {
int[][] dp = new int[nums.length][2];
dp[0][0]=0; dp[0][1]=nums[0];
for (int i = 1; i < dp.length; i++) {
dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]);
dp[i][1]=dp[i-1][0]+nums[i];
}
return Math.max(dp[dp.length-1][0],dp[dp.length-1][1]);
}
/**
* 滚动数组优化
* @param nums
* @return
*/
public int rob1(int[] nums) {
int dp0=0; int dp1=nums[0];
int temp=0;
for (int i = 1; i < nums.length; i++) {
temp=dp0;
dp0=Math.max(dp0,dp1);
dp1=temp+nums[i];
}
return Math.max(dp0,dp1);
}
}

View File

@ -0,0 +1,104 @@
package com.markilue.leecode.dynamic.second;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
*@Author: markilue
*@CreateTime: 2023-02-20 10:57
*@Description:
* TODO 力扣213题 打家劫舍II:
* 你是一个专业的小偷计划偷窃沿街的房屋每间房内都藏有一定的现金
* 这个地方所有的房屋都 围成一圈 这意味着第一个房屋和最后一个房屋是紧挨着的
* 同时相邻的房屋装有相互连通的防盗系统如果两间相邻的房屋在同一晚上被小偷闯入系统会自动报警
* 给定一个代表每个房屋存放金额的非负整数数组计算你 在不触动警报装置的情况下 今晚能够偷窃到的最高金额
*@Version: 1.0
*/
public class T19_Rob {
@Test
public void test(){
int[] nums={2,3,2};
System.out.println(rob(nums));
}
/**
* 思路:与T18的不同之处在于是环形的收尾相连 所以分别考虑只要第一个的时候和只要最后一个的时候结果出现在这两个之中最大的那个
* TODO DP五部曲: 与之前一致只不过一个只考虑不要最后一个一个只考虑不要第一个
* 速度击败2.92% 内存击败48.19%
* @param nums
* @return
*/
public int rob(int[] nums) {
if (nums.length == 1) {
return nums[0];//只有一个的情况直接返回
}
int[][] dp = new int[nums.length][2];//考虑不要最后一个的情况
int[][] dp1 = new int[nums.length][2];//考虑不要第一个的情况
dp[0][0] = 0;
dp[0][1] = nums[0];
dp1[1][0] = 0;
dp1[1][1] = nums[1];
for (int i = 1; i < nums.length-1; i++) {
//不考虑最后一个
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]);
dp[i][1] = dp[i - 1][0] + nums[i];
//不考虑第一个
dp1[i + 1][0] = Math.max(dp1[i][0], dp1[i][1]);
dp1[i + 1][1] = dp1[i][0] + nums[i + 1];
}
int max= Math.max(dp[nums.length - 2][0],dp[nums.length - 2][1]);
int max1=Math.max(dp1[nums.length -1][0],dp1[nums.length -1][1]);
return Math.max(max, max1);
}
/**
* 一维dp优化
* @param nums
* @return
*/
public int rob1(int[] nums) {
if (nums.length == 1) {
return nums[0];//只有一个的情况直接返回
}
int dp0 = 0;//考虑不要最后一个的情况
int dp1 = nums[0];
int temp=0;
int dp10 = 0;//考虑不要第一个的情况
int dp11 = nums[1];
int temp1=0;
for (int i = 1; i < nums.length-1; i++) {
//不考虑最后一个
temp=dp0;
dp0 = Math.max(dp0, dp1);
dp1 = temp + nums[i];
//不考虑第一个
temp1=dp10;
dp10 = Math.max(dp10, dp11);
dp11 = temp1 + nums[i + 1];
}
int max= Math.max(dp0,dp1);
int max1=Math.max(dp10,dp11);
return Math.max(max, max1);
}
}

View File

@ -0,0 +1,58 @@
package com.markilue.leecode.dynamic.second;
import com.markilue.leecode.tree.TreeNode;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
*@Author: markilue
*@CreateTime: 2023-02-20 11:50
*@Description:
* TODO 力扣337 打家劫舍III:
* 小偷又发现了一个新的可行窃的地区这个地区只有一个入口我们称之为 root
* 除了 root 之外每栋房子有且只有一个房子与之相连
* 一番侦察之后聪明的小偷意识到这个地方的所有房屋的排列类似于一棵二叉树
* 如果 两个直接相连的房子在同一天晚上被打劫 房屋将自动报警
* 给定二叉树的 root 返回 在不触动警报的情况下 小偷能够盗取的最高金额
*@Version: 1.0
*/
public class T20_Rob {
/**
* 思路: 不同之处在于 二叉树地区应该如何处理,所以后续遍历遍历完子节点之后考虑当前节点是否偷
* TODO DP五部曲:
* 1.dp定义: dp[i][0]表示当前节点不偷的最大收益;dp[i][1]表示当前节点偷的最大收益
* 2.dp状态转移方程:
* 1.dp[i][0]不偷子节点不偷 或者偷的最大 之和
* 2.dp[i][1]子节点中不偷之和
*
* 3.dp初始化:碰到null节点 dp[i][0]=0; dp[i][1]=0;
* 4.dp遍历顺序:后续遍历最后在考虑当前节点的问题
* 5.dp举例推导:
* 速度击败100% 内存击败76.93%
* @param root
* @return
*/
public int rob(TreeNode root) {
int[] root1 = robSub(root);
return Math.max(root1[0], root1[1]);
}
public int[] robSub(TreeNode root) {
if (root == null) {
return new int[]{0, 0};
}
int[] left = robSub(root.left);
int[] right = robSub(root.right);
int noSteal = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
int Steal = left[0] + right[0] + root.val;
return new int[]{noSteal, Steal};
}
}