From ed50ebaeff673761e301241d6b10fc73279e71fb Mon Sep 17 00:00:00 2001 From: whai Date: Tue, 20 Feb 2024 19:34:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9B=9E=E6=BA=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BackTracking/LeetCode332difficult.java | 246 ++++++++++++++++++ .../leetCode/BackTracking/LeetCode46.java | 92 +++++++ .../leetCode/BackTracking/LeetCode47.java | 126 +++++++++ .../leetCode/BackTracking/LeetCode51.java | 113 ++++++++ 4 files changed, 577 insertions(+) create mode 100644 src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode332difficult.java create mode 100644 src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode46.java create mode 100644 src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode47.java create mode 100644 src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode51.java diff --git a/src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode332difficult.java b/src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode332difficult.java new file mode 100644 index 0000000..75d2964 --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode332difficult.java @@ -0,0 +1,246 @@ +package cn.whaifree.leetCode.BackTracking; + +import org.junit.Test; + +import java.util.*; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/2/20 10:29 + * @注释 + */ +public class LeetCode332difficult { + @Test + public void test() { + List> tickets = new ArrayList<>(); + // 加上这一串 [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]] +// tickets.add(new ArrayList() {{ +// add("JFK"); +// add("SFO"); +// }}); +// tickets.add(new ArrayList() {{ +// add("JFK"); +// add("ATL"); +// }}); +// tickets.add(new ArrayList() {{ +// add("SFO"); +// add("ATL"); +// }}); +// tickets.add(new ArrayList() {{ +// add("ATL"); +// add("JFK"); +// }}); +// tickets.add(new ArrayList() {{ +// add("ATL"); +// add("SFO"); +// }}); + + String[][] routes = { + {"JFK", "SFO"}, + {"JFK", "ATL"}, + {"SFO", "JFK"}, + {"ATL", "AAA"}, + {"AAA", "BBB"}, + {"BBB", "ATL"}, + {"ATL", "AAA"}, + {"AAA", "BBB"}, + {"BBB", "ATL"}, + {"ATL", "AAA"}, + {"AAA", "BBB"}, + {"BBB", "ATL"}, + {"ATL", "AAA"}, + {"AAA", "BBB"}, + {"BBB", "ATL"}, + {"ATL", "AAA"}, + {"AAA", "BBB"}, + {"BBB", "ATL"}, + {"ATL", "AAA"}, + {"AAA", "BBB"}, + {"BBB", "ATL"}, + {"ATL", "AAA"}, + {"AAA", "BBB"}, + {"BBB", "ATL"}, + {"ATL", "AAA"}, + {"AAA", "BBB"}, + {"BBB", "ATL"}, + {"ATL", "AAA"}, + {"AAA", "BBB"}, + {"BBB", "ATL"}, + {"ATL", "AAA"}, + {"AAA", "BBB"}, + {"BBB", "ATL"}, + {"ATL", "AAA"}, + {"AAA", "BBB"}, + {"BBB", "ATL"}, + {"ATL", "AAA"}, + {"AAA", "BBB"}, + {"BBB", "ATL"}, + {"ATL", "AAA"}, + {"AAA", "BBB"}, + {"BBB", "ATL"}, + {"ATL", "AAA"}, + {"AAA", "BBB"}, + {"BBB", "ATL"} + }; + + + for (String[] route : routes) { + tickets.add(Arrays.asList(route)); + } + + Solution1 solution = new Solution1(); + solution.findItinerary(tickets).forEach( + list -> { + System.out.println(list); + } + ); + } + + /** + * 超时 + */ + class Solution { + + List res = new ArrayList<>(); + private LinkedList path = new LinkedList<>(); + boolean[] used = null; + public List findItinerary(List> tickets) { + Collections.sort(tickets, new Comparator>() { + @Override + public int compare(List a, List b) { + // 两个字符串比较 + return a.get(1).compareTo(a.get(1)); + } + }); + // 最后,会按照目的地进行排序["JFK","SFO"],["JFK","ATL"],会变成["JFK","ATL"],["JFK","SFO"] + + path.add("JFK"); + used = new boolean[tickets.size()]; + + // 1. 字典排序选择 + // 2. 已经走过的标记 + backTracking(tickets); + return res; + } + + public void backTracking(List> tickets) { + if (path.size() == 1 + tickets.size()) { + res = new LinkedList(path); + return; + } + + int size = tickets.size(); + for (int i = 0; i < size; i++) { + if (!used[i] && path.getLast().equals(tickets.get(i).get(0))) { + String target = tickets.get(i).get(1); + path.add(target); + used[i] = true; + + backTracking(tickets); + + used[i] = false; + path.removeLast(); + + } + + } + + } + +// /** +// * 在tickets返回未被use的索引,多个索引进行比较 +// * +// * @param tickets +// * @return 在tickets中的索引 +// */ +// public int compareAndUnUsed(List> tickets, String start) { +// int res = -1; +// for (int i = 0; i < tickets.size(); i++) { +// List aPath = tickets.get(i); +// String st = aPath.get(0); +// if (start.equals(st) && used[i] == false) { +// if (res != -1) { +// String target = aPath.get(1); +// String beforeRes = tickets.get(res).get(1); +// if (!compareBeforeIsBetter(beforeRes, target)) { +// res = i; +// } +// }else { +// res = i; +// } +// } +// } +// return res; +// } +// +// public boolean compareBeforeIsBetter(String before,String after) { +// for (int i = 0; i < 3; i++) { +// char be = before.charAt(i); +// char af = after.charAt(i); +// if (be > af) { +// return false; +// } else if (be < af) { +// return true; +// } +// // 如果字母相同,比较下一个字母 +// } +// return true; +// } + + + } + + + class Solution1 { + + List res = new ArrayList<>(); + private LinkedList path = new LinkedList<>(); + boolean[] used = null; + public List findItinerary(List> tickets) { + Collections.sort(tickets, new Comparator>() { + @Override + public int compare(List a, List b) { + // 两个字符串比较 + return a.get(1).compareTo(b.get(1)); + } + }); + // 最后,会按照目的地进行排序["JFK","SFO"],["JFK","ATL"],会变成["JFK","ATL"],["JFK","SFO"] + + path.add("JFK"); + used = new boolean[tickets.size()]; + + // 1. 字典排序选择 + // 2. 已经走过的标记 + backTracking(tickets); + return res; + } + + public boolean backTracking(List> tickets) { + if (path.size() == 1 + tickets.size()) { + res = new LinkedList(path); + return true; + } + + for (int i = 0; i < tickets.size(); i++) { + if (!used[i] && path.getLast().equals(tickets.get(i).get(0))) { + String target = tickets.get(i).get(1); + path.add(target); + used[i] = true; + + if (backTracking(tickets)) { + return true; + } + + + used[i] = false; + path.removeLast(); + + } + + } + return false; + + } + } +} diff --git a/src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode46.java b/src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode46.java new file mode 100644 index 0000000..79f31ef --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode46.java @@ -0,0 +1,92 @@ +package cn.whaifree.leetCode.BackTracking; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/2/19 11:01 + * @注释 + */ +public class LeetCode46 { + @Test + public void test() { + new Solution1().permute(new int[]{1, 2, 3}).forEach( + list -> { + System.out.println(list); + } + ); + } + + class Solution { + + List> res = new ArrayList<>(); + List path = new ArrayList<>(); + boolean[] used = null; + + + public List> permute(int[] nums) { + used = new boolean[nums.length]; + backTracking(nums); + return res; + } + + public void backTracking(int[] nums) { + + if (path.size() == nums.length) { + res.add(new ArrayList<>(path)); + return; + } + + for (int i = 0; i < nums.length; i++) { + if (used[i] == true) { + continue; + } + used[i] = true; + path.add(nums[i]); + backTracking(nums); + used[i] = false; + path.remove(path.size() - 1); + } + + } + + + } + + class Solution1 { + + List> res = new ArrayList<>(); + List path = new ArrayList<>(); + + + public List> permute(int[] nums) { + backTracking(nums); + return res; + } + + public void backTracking(int[] nums) { + + if (path.size() == nums.length) { + res.add(new ArrayList<>(path)); + return; + } + + for (int i = 0; i < nums.length; i++) { + if (path.contains(nums[i])) { + continue; + } + path.add(nums[i]); + backTracking(nums); + path.remove(path.size() - 1); + } + + } + + + } +} diff --git a/src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode47.java b/src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode47.java new file mode 100644 index 0000000..ca58e3e --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode47.java @@ -0,0 +1,126 @@ +package cn.whaifree.leetCode.BackTracking; + +import cn.whaifree.leetCode.model.TreeNode; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/2/19 16:41 + * @注释 + */ +public class LeetCode47 { + + @Test + public void test(){ + new Solution1().permuteUnique(new int[]{1, 1, 2}).forEach( + list -> { + System.out.println(list); + + } + ); + } + + /** + * 使用层的set+路径的bool[] + */ + class Solution { + + List> res = new ArrayList<>(); + List path = new ArrayList<>(); + boolean[] used = null; + /** + * 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。 + * 相比46题,不重复 + * @param nums + * @return + */ + public List> permuteUnique(int[] nums) { + used = new boolean[nums.length]; + + backTracking(nums); + + return res; + } + + public void backTracking(int[] nums) { + if (path.size() == nums.length) { + res.add(new ArrayList<>(path)); + return; + } + + // 这个set用来对每层进行过滤,每层不能重复 + // used对每个路径进行过滤,没个路径不会出现同一个index,但有可能多个index都是同一个元素 + HashSet set = new HashSet<>(); + for (int i = 0; i < nums.length; i++) { + if (used[i] == true || set.contains(nums[i])) { + continue; + } + set.add(nums[i]); + used[i] = true; + path.add(nums[i]); + backTracking(nums); + used[i] = false; + path.remove(path.size() - 1); + } + } + } + + /** + * 使用排序+used + */ + class Solution1 { + + List> res = new ArrayList<>(); + List path = new ArrayList<>(); + boolean[] used = null; + /** + * 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。 + * 相比46题,不重复 + * @param nums + * @return + */ + public List> permuteUnique(int[] nums) { + used = new boolean[nums.length]; + Arrays.sort(nums); + + backTracking(nums); + return res; + } + + public void backTracking(int[] nums) { + if (path.size() == nums.length) { + res.add(new ArrayList<>(path)); + return; + } + + + for (int i = 0; i < nums.length; i++) { + // used[i - 1] == false,说明同⼀树层nums[i - 1]使⽤过 + // 如果同⼀树层nums[i - 1]使⽤过则直接跳过 + // 一层 + if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) { + continue; + } + // used[i] == true,说明同⼀树⽀nums[i]使⽤过 + // 这个路径上被使用过 + // 一条路径 + if (used[i]) { + continue; + } + used[i] = true; + path.add(nums[i]); + backTracking(nums); + used[i] = false; + path.remove(path.size() - 1); + } + } + } + + +} diff --git a/src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode51.java b/src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode51.java new file mode 100644 index 0000000..4347219 --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/BackTracking/LeetCode51.java @@ -0,0 +1,113 @@ +package cn.whaifree.leetCode.BackTracking; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/2/20 12:03 + * @注释 + */ +public class LeetCode51 { + + @Test + public void test() { + new Solution().solveNQueens(4).forEach( + list -> { + for (String s : list) { + System.out.println(s); + } + + } + ); + } + + + class Solution { + List> res = new ArrayList<>(); + + // 地图 + char[][] chessMap = null; + + /** + * 1. 形成棋盘 + * 2. 选择点进行填充 + * 填充后,判断该点上列、斜45、45度角是否有被使用过 + * - 如果有,回溯到上次递归 + * - 没有,标记该点Q,去下一行row+1进行填充 + * @param n + * @return + */ + public List> solveNQueens(int n) { + chessMap = new char[n][n]; + for (char[] c : chessMap) { + Arrays.fill(c, '.'); + } + backTracking(n, 0); + + return res; + } + + public void backTracking(int n, int row) { + if (row == n) { + List element = new ArrayList<>(); + for (char[] chars : chessMap) { + StringBuilder s = new StringBuilder(); + for (char aChar : chars) { + s.append(aChar); + } + element.add(s.toString()); + } + res.add(element); + return; + } + + for (int col = 0; col < n; col++) { + if (isValid(n, col, row)) { + + chessMap[row][col] = 'Q'; + backTracking(n, row + 1); + // 回溯 + chessMap[row][col] = '.'; + } + } + + } + + /** + * 判断是否有效 + * + * @param n n皇后 + * @param col 列 + * @param row 行 + * @return + */ + public boolean isValid(int n, int col, int row) { + // 判断某列是否有被使用过的,其实只要该点往上搜索就可以,下面的必定为. + for (int i = 0; i < row; i++) { + if (chessMap[i][col] == 'Q') { + return false; + } + } + // 判断45度 该点左上搜索 + for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { + // 只要让某个点,不断往斜45度向左上检查就可以 + if (chessMap[i][j] == 'Q') { + return false; + } + } + // 判断斜45、135度 该点右边上搜索 + for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) { + // 只要让某个点,不断往斜45度向左上检查就可以 + if (chessMap[i][j] == 'Q') { + return false; + } + } + return true; + } + } +}