From c9c55164b7bcf3782286c5a9dcbaec45c1bac25a Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Wed, 1 Feb 2023 13:29:43 +0800 Subject: [PATCH] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...nationSum.java => T04_CombinationSum.java} | 2 +- ...tionSum2.java => T05_CombinationSum2.java} | 2 +- .../{partition.java => T06_Partition.java} | 2 +- ...esses.java => T07_RestoreIpAddresses.java} | 2 +- .../backtrace/second/T04_CombinationSum.java | 86 ++++++++++ .../backtrace/second/T05_CombinationSum2.java | 46 ++++++ .../backtrace/second/T06_Partition.java | 155 ++++++++++++++++++ .../second/T07_RestoreIpAddresses.java | 130 +++++++++++++++ 8 files changed, 421 insertions(+), 4 deletions(-) rename Leecode/src/main/java/com/markilue/leecode/backtrace/{combinationSum.java => T04_CombinationSum.java} (99%) rename Leecode/src/main/java/com/markilue/leecode/backtrace/{combinationSum2.java => T05_CombinationSum2.java} (99%) rename Leecode/src/main/java/com/markilue/leecode/backtrace/{partition.java => T06_Partition.java} (99%) rename Leecode/src/main/java/com/markilue/leecode/backtrace/{RestoreIpAddresses.java => T07_RestoreIpAddresses.java} (99%) create mode 100644 Leecode/src/main/java/com/markilue/leecode/backtrace/second/T04_CombinationSum.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/backtrace/second/T05_CombinationSum2.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/backtrace/second/T06_Partition.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/backtrace/second/T07_RestoreIpAddresses.java diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/combinationSum.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/T04_CombinationSum.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/backtrace/combinationSum.java rename to Leecode/src/main/java/com/markilue/leecode/backtrace/T04_CombinationSum.java index 2524849..4092a32 100644 --- a/Leecode/src/main/java/com/markilue/leecode/backtrace/combinationSum.java +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/T04_CombinationSum.java @@ -17,7 +17,7 @@ import java.util.List; * 对于给定的输入,保证和为 target 的不同组合数少于 150 个。 * @Version: 1.0 */ -public class combinationSum { +public class T04_CombinationSum { @Test public void test() { diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/combinationSum2.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/T05_CombinationSum2.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/backtrace/combinationSum2.java rename to Leecode/src/main/java/com/markilue/leecode/backtrace/T05_CombinationSum2.java index 4a1377e..4c878bf 100644 --- a/Leecode/src/main/java/com/markilue/leecode/backtrace/combinationSum2.java +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/T05_CombinationSum2.java @@ -15,7 +15,7 @@ import java.util.*; * 注意:解集不能包含重复的组合。 * @Version: 1.0 */ -public class combinationSum2 { +public class T05_CombinationSum2 { @Test public void test(){ diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/partition.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/T06_Partition.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/backtrace/partition.java rename to Leecode/src/main/java/com/markilue/leecode/backtrace/T06_Partition.java index 8963810..0ca26fd 100644 --- a/Leecode/src/main/java/com/markilue/leecode/backtrace/partition.java +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/T06_Partition.java @@ -15,7 +15,7 @@ import java.util.List; * 回文串 是正着读和反着读都一样的字符串。 * @Version: 1.0 */ -public class partition { +public class T06_Partition { @Test public void test() { diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/RestoreIpAddresses.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/T07_RestoreIpAddresses.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/backtrace/RestoreIpAddresses.java rename to Leecode/src/main/java/com/markilue/leecode/backtrace/T07_RestoreIpAddresses.java index 65977b2..fa5ac57 100644 --- a/Leecode/src/main/java/com/markilue/leecode/backtrace/RestoreIpAddresses.java +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/T07_RestoreIpAddresses.java @@ -17,7 +17,7 @@ import java.util.List; * 给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。 * @Version: 1.0 */ -public class RestoreIpAddresses { +public class T07_RestoreIpAddresses { @Test public void test1() { diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T04_CombinationSum.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T04_CombinationSum.java new file mode 100644 index 0000000..ec61d5c --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T04_CombinationSum.java @@ -0,0 +1,86 @@ +package com.markilue.leecode.backtrace.second; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.backtrace.second + *@Author: dingjiawen + *@CreateTime: 2023-02-01 09:53 + *@Description: + * TODO 二刷力扣39题 组合总和: + * 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。 + * candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 + * 对于给定的输入,保证和为 target 的不同组合数少于 150 个。 + *@Version: 1.0 + */ +public class T04_CombinationSum { + + + List> result = new ArrayList<>(); + List cur = new ArrayList<>(); + + public List> combinationSum(int[] candidates, int target) { + Arrays.sort(candidates); + backtracking(candidates,target,0,0); + return result; + + } + + public void backtracking(int[] candidates, int target, int sum,int now) { + if (sum == target) { + result.add(new ArrayList<>(cur)); + return; + } + + for (int i = now; i < candidates.length; i++) { + if (sum + candidates[i] > target) {//剪枝 + return; + } + cur.add(candidates[i]); + backtracking(candidates, target, sum + candidates[i],i); + cur.remove(cur.size()-1); + } + + } + + + /** + * 官方最快,form记录一个数最多能用多少次,小于0就不能用了 + * @param con + * @param target + * @param form + * @param cur + * @param sum + * @param start + */ + private void deal(List> con,int target,int[] form,List cur,int sum,int start){ + //dfs + if(sum==target) { + con.add(new ArrayList(cur)); + return; + } + for(int i=start;i<=target-sum;++i){ + if(form[i]>0){ + cur.add(i); + --form[i]; + sum+=i; + deal(con,target,form,cur,sum,i); + sum-=i; + ++form[i]; + cur.remove(cur.size()-1); + } + } + } + public List> combinationSum2(int[] candidates, int target) { + int[] form=new int[51]; + for(int i=0;i> con=new ArrayList>(); + deal(con,target,form,new ArrayList(),0,1); + return con; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T05_CombinationSum2.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T05_CombinationSum2.java new file mode 100644 index 0000000..c6bf754 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T05_CombinationSum2.java @@ -0,0 +1,46 @@ +package com.markilue.leecode.backtrace.second; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.backtrace.second + *@Author: dingjiawen + *@CreateTime: 2023-02-01 10:22 + *@Description: + * TODO 二刷力扣40题 组合总和II: + * 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 + * candidates 中的每个数字在每个组合中只能使用 一次 。 + * 注意:解集不能包含重复的组合。 + *@Version: 1.0 + */ +public class T05_CombinationSum2 { + + List cur=new ArrayList<>(); + List> result=new ArrayList<>(); + public List> combinationSum2(int[] candidates, int target) { + Arrays.sort(candidates); + backtracking(candidates,target,0,0); + return result; + } + + public void backtracking(int[] candidates, int target,int sum ,int startIndex) { + if(target==sum){ + result.add(new ArrayList<>(cur)); + return; + } + + for (int i = startIndex; i < candidates.length; i++) { + if(sum+candidates[i]>target){ + return; + } + if(i!=startIndex&&candidates[i]==candidates[i-1])continue; + cur.add(candidates[i]); + backtracking(candidates,target,sum+candidates[i],i+1); + cur.remove(cur.size()-1); + } + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T06_Partition.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T06_Partition.java new file mode 100644 index 0000000..46834f2 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T06_Partition.java @@ -0,0 +1,155 @@ +package com.markilue.leecode.backtrace.second; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.backtrace.second + *@Author: dingjiawen + *@CreateTime: 2023-02-01 11:01 + *@Description: + * TODO 二刷力扣131题 分割回文串: + * 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。 + * 回文串 是正着读和反着读都一样的字符串。 + *@Version: 1.0 + */ +public class T06_Partition { + + @Test + public void test() { + String s = "abbab"; + + System.out.println(partition(s)); + } + + List> result = new ArrayList<>(); + List cur = new ArrayList<>(); + boolean[][] flag; + + public List> partition(String s) { + flag = new boolean[s.length()][s.length()]; + computePalindrome1(s); + backtracking(s.toCharArray(), 0); + return result; + } + + /** + * 使用动态规划前:速度击败73.84%,内存击败55.32% 7ms + * 使用动态规划后:速度击败99.22%,内存击败47.98% 6ms + * @param chars + * @param start + */ + public void backtracking(char[] chars, int start) { + if (start == chars.length) { + //分完了,直接加入 + result.add(new ArrayList<>(cur)); + return; + } + StringBuilder builder = new StringBuilder(); + for (int i = start; i < chars.length; i++) { + builder.append(chars[i]); + if (flag[start][i]) { + cur.add(builder.toString()); + backtracking(chars, i + 1); + cur.remove(cur.size() - 1); + } + } + + } + + public boolean isPalindrome(char[] chars, int start, int end) { + if (start == end) { + return true; + } + while (start < end) { + if (chars[start++] != chars[end--]) { + return false; + } + } + return true; + + } + + /** + * 事实上判断回文不需要一个一个进行判断,可以通过动态规划递归进行判断 + * TODO 动态规划五部曲: + * 1)dp定义:dp[i][j]表示start为i,end为j的字符串是否是回文 + * 2)dp状态转移方程:dp[i][j]可以通过dp[i+1][j-1]来推断 + * dp[i][j]=char[i]==char[j]&&dp[i+1][j-1] + * 3)dp遍历顺序:由于需要知道i+1,j-1所以需要从下到上,左到右 + * 4)dp初始化:dp[i][i]=true;dp[i][i>j]=true + * 5)dp距离推导: s="aab" + * [a a b] + * i=0: t t f + * i=1: t t f + * i=2: t t t + * + * + * @param s + */ + public void computePalindrome(String s) { + char[] chars = s.toCharArray(); + //初始化,下三角全为true + for (int i = 0; i < s.length(); i++) { + for (int j = 0; j <= i; j++) { + flag[i][j] = true; + } + } + + for (int i = s.length() - 2; i >= 0; i--) { + for (int j = s.length() - 1; j > i; j--) { + flag[i][j] = chars[i] == chars[j] && flag[i + 1][j - 1]; + } + } + } + + + /** + * 根据官方的优化 + * @param s + */ + public void computePalindrome1(String s) { + char[] chars = s.toCharArray(); +// //初始化,下三角全为true +// for (int i = 0; i < s.length(); i++) { +// for (int j = 0; j <= i; j++) { +// flag[i][j] = true; +// } +// } + + for (int i = s.length() - 1; i >= 0; i--) { + for (int j = i; j = 0; i--) { + for (int j = i; j result = new ArrayList<>(); + + /** + * 本质上类似于切割回文T06,核心在于最后一层一定要切完 + * @param s + * @return + */ + public List restoreIpAddresses(String s) { + backtracking(s, 0, 0); + return result; + } + + public void backtracking(String s, int level, int start) { + if (level == 4) { + builder.deleteCharAt(builder.length() - 1); + result.add(builder.toString()); + builder.append("."); + return; + } + int flag = start + 3 > s.length() ? s.length() : start + 3; + for (int i = start; i < flag; i++) { + String now; + if (level == 3) { + now = s.substring(i); + if (!isFit(now)) return; + } else { + now = s.substring(start, i + 1); + } + if (isFit(now)) { + builder.append(now).append("."); + backtracking(s, level + 1, i + 1); + int last = builder.length(); + builder.delete(last - now.length() - 1, last); + } + if (level == 3) { + //最后一层就一次 + return; + } + } + + } + + public boolean isFit(String s) { + if (s.length() == 0) { + return false; + } + if (s.length() > 1 && s.charAt(0) == '0') { + return false; + } + long num = Long.parseLong(s); + + return num >= 0 && num <= 255; + + + } + + + /** + * 官方最快0ms + * 使用segment记录pasInt的数,最后在拼接,避免了一系列删除增加“.”的操作 + */ + List res = new ArrayList<>(); + int[] segment = new int[4]; + public List restoreIpAddresses1(String s) { + dfs(s,0,0); + return res; + } + public void dfs(String s,int segnum,int p){ + if(segnum == 4){ + if(p == s.length()){ + StringBuilder sb = new StringBuilder(); + for(int i = 0;i < 4;i++){ + sb.append(segment[i]); + if(i != 3){ + sb.append('.'); + } + } + res.add(sb.toString()); + } + return; + } + if(p == s.length()){ + return; + } + if(s.charAt(p) == '0'){ + segment[segnum] = 0; + dfs(s,segnum+1,p+1); + } + int sum = 0; + for(int i = p;i < s.length();i++){ + sum = sum * 10 + s.charAt(i) - '0'; + if(sum > 0 && sum <= 255){ + segment[segnum] = sum; + dfs(s,segnum+1,i+1); + }else{ + break; + } + } + + } +}