diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/Subsets.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/T08_Subsets.java similarity index 98% rename from Leecode/src/main/java/com/markilue/leecode/backtrace/Subsets.java rename to Leecode/src/main/java/com/markilue/leecode/backtrace/T08_Subsets.java index 77367b1..c6e92ee 100644 --- a/Leecode/src/main/java/com/markilue/leecode/backtrace/Subsets.java +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/T08_Subsets.java @@ -16,7 +16,7 @@ import java.util.List; * 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 * @Version: 1.0 */ -public class Subsets { +public class T08_Subsets { @Test public void test(){ diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/SubsetsWithDup.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/T09_SubsetsWithDup.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/backtrace/SubsetsWithDup.java rename to Leecode/src/main/java/com/markilue/leecode/backtrace/T09_SubsetsWithDup.java index bea6c89..7d1768d 100644 --- a/Leecode/src/main/java/com/markilue/leecode/backtrace/SubsetsWithDup.java +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/T09_SubsetsWithDup.java @@ -14,7 +14,7 @@ import java.util.*; * 解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。 * @Version: 1.0 */ -public class SubsetsWithDup { +public class T09_SubsetsWithDup { @Test public void test() { diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/FindSubsequences.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/T10_FindSubsequences.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/backtrace/FindSubsequences.java rename to Leecode/src/main/java/com/markilue/leecode/backtrace/T10_FindSubsequences.java index 8c5f89e..19c0602 100644 --- a/Leecode/src/main/java/com/markilue/leecode/backtrace/FindSubsequences.java +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/T10_FindSubsequences.java @@ -17,7 +17,7 @@ import java.util.Set; * 数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。 * @Version: 1.0 */ -public class FindSubsequences { +public class T10_FindSubsequences { @Test diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/Permute.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/T11_Permute.java similarity index 98% rename from Leecode/src/main/java/com/markilue/leecode/backtrace/Permute.java rename to Leecode/src/main/java/com/markilue/leecode/backtrace/T11_Permute.java index e8dfcca..e3a330b 100644 --- a/Leecode/src/main/java/com/markilue/leecode/backtrace/Permute.java +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/T11_Permute.java @@ -15,7 +15,7 @@ import java.util.List; * 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 * @Version: 1.0 */ -public class Permute { +public class T11_Permute { @Test public void test(){ diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/PermuteUnique.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/T12_PermuteUnique.java similarity index 98% rename from Leecode/src/main/java/com/markilue/leecode/backtrace/PermuteUnique.java rename to Leecode/src/main/java/com/markilue/leecode/backtrace/T12_PermuteUnique.java index ae7369a..b4242be 100644 --- a/Leecode/src/main/java/com/markilue/leecode/backtrace/PermuteUnique.java +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/T12_PermuteUnique.java @@ -16,7 +16,7 @@ import java.util.List; * 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。 * @Version: 1.0 */ -public class PermuteUnique { +public class T12_PermuteUnique { @Test public void test() { diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T08_Subsets.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T08_Subsets.java new file mode 100644 index 0000000..daed256 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T08_Subsets.java @@ -0,0 +1,52 @@ +package com.markilue.leecode.backtrace.second; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.backtrace.second + *@Author: dingjiawen + *@CreateTime: 2023-02-02 10:07 + *@Description: + * TODO 二刷力扣78题 子集: + * 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。 + * 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 + *@Version: 1.0 + */ +public class T08_Subsets { + + @Test + public void test() { + int[] nums={1,2,3}; + System.out.println(subsets(nums)); + } + + List> result = new ArrayList<>(); + List cur = new ArrayList<>(); + + public List> subsets(int[] nums) { + backtracking(nums, 0); + return result; + + } + + public void backtracking(int[] nums, int level) { + if (level == nums.length) { + result.add(new ArrayList<>(cur)); + return; + } + + for (int i = 0; i <= 1; i++) { + if (i == 0) { + backtracking(nums, level + 1); + } else { + cur.add(nums[level]); + backtracking(nums, level+1); + cur.remove(cur.size() - 1); + } + } + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T09_SubsetsWithDup.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T09_SubsetsWithDup.java new file mode 100644 index 0000000..3b93f72 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T09_SubsetsWithDup.java @@ -0,0 +1,100 @@ +package com.markilue.leecode.backtrace.second; + +import org.junit.Test; + +import java.util.*; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.backtrace.second + *@Author: dingjiawen + *@CreateTime: 2023-02-02 10:32 + *@Description: + * TODO 力扣90题 子集II: + * 给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。 + * 解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。 + *@Version: 1.0 + */ +public class T09_SubsetsWithDup { + @Test + public void test() { + int[] nums = {1, 2, 2}; + System.out.println(subsetsWithDup1(nums)); + } + + /** + * 两种思路:1.树层去重2.map记录元素个数,横向遍历使用 + * @param nums + * @return + */ + Map map = new HashMap();// + List key = new ArrayList<>(); + List cur = new ArrayList<>(); + List> result = new ArrayList<>(); + + public List> subsetsWithDup(int[] nums) { + for (int num : nums) { + Integer count = map.getOrDefault(num, 0); + if (count == 0) { + key.add(num); + } + map.put(num, count + 1); + } + backtracking(0); + return result; + } + + /** + * map记录次数法 + * @param level + */ + public void backtracking(int level) { + if (level == key.size()) { + result.add(new ArrayList<>(cur)); + return; + } + Integer keyNow = key.get(level); + Integer count = map.get(keyNow); + for (int i = 0; i <= count; i++) { + if (i != 0) { + cur.add(keyNow); + } + backtracking(level + 1); + } + for (int i = 0; i < count; i++) { + cur.remove(cur.size() - 1); + } + } + + + public List> subsetsWithDup1(int[] nums) { + Arrays.sort(nums); + backtracking1(nums,0); + return result; + } + + /** + * 树层去重法 + * @param nums + */ + public void backtracking1(int[] nums, int startIndex) { + result.add(new ArrayList<>(cur)); + if (startIndex > nums.length) { + return; + } + + for (int i = startIndex; i < nums.length; i++) { + //树层去重 + if (i != startIndex && nums[i - 1] == nums[i]) { + continue; + } + cur.add(nums[i]); + backtracking1(nums, i + 1); + cur.remove(cur.size() - 1); + } + + + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T10_FindSubsequences.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T10_FindSubsequences.java new file mode 100644 index 0000000..546180e --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T10_FindSubsequences.java @@ -0,0 +1,101 @@ +package com.markilue.leecode.backtrace.second; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.backtrace.second + *@Author: dingjiawen + *@CreateTime: 2023-02-02 11:28 + *@Description: + * TODO 二刷力扣491 递增子序列: + * 给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 + * 数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。 + *@Version: 1.0 + */ +public class T10_FindSubsequences { + + @Test + public void test() { + int[] nums = {4, 6, 7, 7}; + System.out.println(findSubsequences(nums)); + } + + + List cur = new ArrayList<>(); + List> result = new ArrayList<>(); + + /** + * 与上一题子集II类似,都是需要树层去重即可 + * @param nums + * @return + */ + public List> findSubsequences(int[] nums) { + backtracking(nums, 0); + return result; + + } + + public void backtracking(int[] nums, int startIndex) { + if (cur.size() >= 2) { + result.add(new ArrayList<>(cur)); + } + if (startIndex == nums.length) return; + HashSet set = new HashSet<>(); + for (int i = startIndex; i < nums.length; i++) { + //同一树层去除,由于相同数不一定连续,所以使用set来进行树层去重 + //这里还可以使用数组来去重,当数组的指定数位置的值为1时则证明使用过 + if (set.contains(nums[i])) { + continue; + } + set.add(nums[i]); + if (cur.isEmpty() || cur.get(cur.size() - 1) <= nums[i]) { + //是递增的 + cur.add(nums[i]); + backtracking(nums, i + 1); + cur.remove(cur.size() - 1); + } + } + + } + + + /** + * 官方最快 2ms,可能快在用lastNum来记录cur(last) + * @param nums + * @return + */ + public List> findSubsequences1(int[] nums) { + List> list = new ArrayList<>(); + if (nums == null || nums.length == 0) return list; + List result = new ArrayList<>(); + + dfs(0, nums, result, list, -101); + return list; + } + + private void dfs(int idx, int[] nums, List result, List> list, int lastNum) { + if (result.size() > 1) { + list.add(new ArrayList<>(result)); + } + + for (int i = idx; i < nums.length; i++) { + if (isRepeat(nums, idx, i)) continue; + if (nums[i] < lastNum) continue; + result.add(nums[i]); + dfs(i + 1, nums, result, list, nums[i]); + result.remove(result.size() - 1); + } + } + + private boolean isRepeat(int[] nums, int idx, int i) { + for (int j = idx; j < i; j++) { + if (nums[j] == nums[i]) return true; + } + return false; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T11_Permute.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T11_Permute.java new file mode 100644 index 0000000..689ae92 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T11_Permute.java @@ -0,0 +1,83 @@ +package com.markilue.leecode.backtrace.second; + +import com.sun.org.apache.bcel.internal.generic.LUSHR; + +import java.util.ArrayList; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.backtrace.second + *@Author: dingjiawen + *@CreateTime: 2023-02-02 11:55 + *@Description: + * TODO 力扣46题 全排列: + * 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 + *@Version: 1.0 + */ +public class T11_Permute { + + List cur = new ArrayList<>(); + List> result = new ArrayList<>(); + boolean[] used; + + /** + * 全排列的题,实际上就是顺序也有关系,所以直接不用传startIndex,每次都从0开始就好 + * 把used放外面速度击败82.16%,内存击败28.47% 1ms + * @param nums + * @return + */ + public List> permute(int[] nums) { + used = new boolean[nums.length]; + backtracking(nums); + return result; + + } + + public void backtracking(int[] nums) { + if(cur.size()==nums.length){ + result.add(new ArrayList<>(cur)); + return; + } + + for (int i = 0; i < nums.length; i++) { + if(!used[i]){ + used[i]=true; + cur.add(nums[i]); + backtracking(nums); + cur.remove(cur.size()-1); + used[i]=false; + } + } + + } + + + /** + * 把used放里面传参 + * 速度击败100%,内存击败83.99% 0ms + * @param nums + * @return + */ + public List> permute1(int[] nums) { + backtracking(nums,new boolean[nums.length]); + return result; + } + public void backtracking(int[] nums, boolean[] used) { + if(cur.size()==nums.length){ + result.add(new ArrayList<>(cur)); + return; + } + + for (int i = 0; i < nums.length; i++) { + if(!used[i]){ + used[i]=true; + cur.add(nums[i]); + backtracking(nums,used); + cur.remove(cur.size()-1); + used[i]=false; + } + } + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T12_PermuteUnique.java b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T12_PermuteUnique.java new file mode 100644 index 0000000..939d530 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/backtrace/second/T12_PermuteUnique.java @@ -0,0 +1,87 @@ +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-02 12:08 + *@Description: + * TODO 力扣47题 全排列II: + * 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。 + *@Version: 1.0 + */ +public class T12_PermuteUnique { + + List cur = new ArrayList<>(); + List> result = new ArrayList<>(); + + /** + * 要做的事似乎还是树层去重 + * @param nums + * @return + */ + public List> permuteUnique(int[] nums) { + backtracking(nums, new boolean[nums.length]); + return result; + } + + public void backtracking(int[] nums, boolean[] used) { + if (nums.length == cur.size()) { + result.add(new ArrayList<>(cur)); + return; + } + boolean[] curUsed = new boolean[21];//本树层是否用过 + for (int i = 0; i < nums.length; i++) { + if (curUsed[nums[i] + 10]) continue; + if (!used[i]) { + curUsed[nums[i] + 10] = true; + used[i] = true; + cur.add(nums[i]); + backtracking(nums, used); + cur.remove(cur.size() - 1); + used[i] = false; + } + } + + } + + + /** + * 可以进一步优化为一个used数组 + * @param nums + * @param + */ + public List> permuteUnique1(int[] nums) { + Arrays.sort(nums); + backtracking(nums, new boolean[nums.length]); + return result; + } + public void backtracking1(int[] nums, boolean[] used) { + if (nums.length == cur.size()) { + result.add(new ArrayList<>(cur)); + return; + } + + for (int i = 0; i < nums.length; i++) { + // used[i - 1] == true,说明同一树枝nums[i - 1]使用过 + // used[i - 1] == false,说明同一树层nums[i - 1]使用过 + // 如果同一树层nums[i - 1]使用过则直接跳过 + if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) { + continue; + } + if (!used[i]) { + used[i] = true; + cur.add(nums[i]); + backtracking1(nums, used); + cur.remove(cur.size() - 1); + used[i] = false; + } + } + + } +} +}