组合I
class Solution {List<List<Integer>> result = new ArrayList(); // 所有结果集List<Integer> list = new ArrayList(); // 当前结果集public List<List<Integer>> combine(int n, int k) {dfs(n, k, 1);return result;}public void dfs(int n, int k, int index) {if (list.size() == k) { // 当前结果集等于要收集的数量即可存入最终结果集List<Integer> tem = new ArrayList(list);result.add(tem);return;}for (int i = index; i <= n; i++) {list.add(i); // 元素加入当前结果集dfs(n, k, i + 1); // 递归list.remove(list.size() - 1); // 该元素组合完成可以移除(回溯)}}
}
组合II
class Solution {List<List<Integer>> result = new ArrayList(); // 所有结果集Set<List<Integer>> set = new HashSet(); // 结果集去重List<Integer> list = new ArrayList(); // 当前结果集public List<List<Integer>> combinationSum2(int[] candidates, int target) {backTring(candidates, 0, target, 0);return result;}public void backTring(int[] candidates, int sum, int target, int index) {if (candidates == null || candidates.length < 0) return; if (sum == target) { // 总和等于目标值是返回当前结果集List<Integer> tem = new ArrayList(list);Collections.sort(tem); // 去重(如:1 1 2 和 2 1 1 是一组结果集)if (!set.contains(tem)) { result.add(new ArrayList(list));set.add(tem);}return;}if (sum > target) { // 当前结果集大于目标值说明当前结果集不对return;}for (int i = index; i < candidates.length; i++) {sum += candidates[i]; // 当前总和list.add(candidates[i]); // 当前结果集backTring(candidates, sum, target, i + 1);sum -= candidates[i]; // 回溯总和list.remove(list.size() - 1); // 回溯结果集}}
}
组合III
class Solution {List<List<Integer>> result = new ArrayList(); // 最终结果集List<Integer> list = new ArrayList(); // 当前结果集public List<List<Integer>> combinationSum3(int k, int n) {backCheck(k, n, 1, 0, 0);return result;}public void backCheck(int k, int n, int num, int count, int sum) {if (count == k && n == sum) { // 元素数量等于k 且 sum等于 n 时为符合的结果集result.add(new ArrayList(list));return;}if (count > k || n < sum) { // 要求的数量或者总和不对则返回return;}for (int i = num; i <= 9; i++) {list.add(i);sum += i;count++;backCheck(k, n, i + 1, count, sum);list.remove(list.size() - 1);sum -= i;count--;}}
}
分割回文串
class Solution {List<List<String>> result = new ArrayList(); // 最终结果集List<String> list = new ArrayList(); // 当前结果集public String[][] partition(String s) {int n = s.length();dfs(0, n, s);return listToArrays(result); // 集合转换为数组}public void dfs(int index, int n, String s) {if (index == n) { // 指针指向n时说明遍历到字符串末尾,可以返回结果集result.add(new ArrayList(list));return;}for (int i = index; i < n; i++) {if (isPalindrome(s.substring(index, i + 1))) { // 如果是回文串则加入当前结果集 list.add(s.substring(index, i + 1)); // 加入结果集dfs(i + 1, n, s);list.remove(list.size() - 1); // 回溯}}}public boolean isPalindrome(String str) { // 判断是否为回文串int l = 0;int r = str.length() - 1;while (l < r) {if (str.charAt(l) != str.charAt(r)) {return false;}l++;r--;}return true;}public String[][] listToArrays (List<List<String>> list) { // 集合转换为数组int n = list.size();String[][] arrs = new String[n][];for (int i = 0; i < n; i++) {List<String> tem = list.get(i);String[] arr = tem.toArray(new String[tem.size()]);arrs[i] = arr;}return arrs;}
}
复原 IP 地址
class Solution {List<String> res = new ArrayList(); // 所有结果集List<String> tem = new ArrayList(); // 当前结果集public List<String> restoreIpAddresses(String s) {int n = s.length(); // 字符串长度if (n < 0 || n > 12) return res; // 剪枝dfs(s, 0, n);return res;}public void dfs(String s, int index, int n) {if (tem.size() == 4) { // ip地址为四个数字组成,当前结果集等于4即可返回if (index == n) { // 当前指针指向末尾即可加入最终结果集StringBuilder sb = new StringBuilder(); // 拼凑成需要的字符串for (int i = 0; i < 4; i++) {sb.append(tem.get(i));if (i != 3) {sb.append(".");}}res.add(sb.toString()); // 加入到最终结果集}return;}for (int i = index; i < n && i < index + 3; i++) { // 当前指针if (isNum(s.substring(index, i + 1))) { //tem.add(s.substring(index, i + 1));dfs(s, i + 1, n);tem.remove(tem.size() - 1);}}}public boolean isNum(String s) { // 判断是否为合法数字if (s.length() >= 2 && s.charAt(0) == '0') return false;Integer num = Integer.valueOf(s);if (num > 255) return false;return true;}
}
子集I
class Solution {List<List<Integer>> res = new ArrayList();List<Integer> tem = new ArrayList();public List<List<Integer>> subsets(int[] nums) {dfs(nums, 0, nums.length);return res;}public void dfs(int[] nums, int index, int n) {res.add(new ArrayList(tem)); // 每次递归都是一个新子集for (int i = index; i < n; i++) {tem.add(nums[i]);dfs(nums, i + 1, n);tem.remove(tem.size() - 1);}}
}
子集II
class Solution {List<List<Integer>> res = new ArrayList(); // 所有结果集List<Integer> list = new ArrayList(); // 当前子集Set<List<Integer>> set = new HashSet(); // 子集去重public List<List<Integer>> subsetsWithDup(int[] nums) {Arrays.sort(nums); // 排序dfs(nums, 0, nums.length);return res;}public void dfs(int[] nums, int index, int n) {res.add(new ArrayList(list)); // 每次递归都是新子集for (int i = index; i < n; i++) {if (i != index && nums[i] == nums[i - 1]) continue; // 数组已经排序,如果当前元素等于上一个元素进行递归会有重复子集(如:数组 {1 1} 的子集为 {1} {1 1},如果索引到第二个元素再进行递归则会有重复子集{1}list.add(nums[i]); dfs(nums, i + 1, n);list.remove(list.size() - 1);}}
}
最长递增子序列
class Solution {public int lengthOfLIS(int[] nums) {int[] dp = new int[nums.length]; // 动态规划+暴力枚举Arrays.fill(dp, 1); // 每个子序列起始都是1int max = dp[0];for (int i = 1; i < nums.length; i++) {for (int j = 0; j < i; j++) { // 判断当前位置最长子序列是多少if (nums[j] < nums[i]) {dp[i] = Math.max(dp[i], dp[j] + 1);}}max = max > dp[i] ? max : dp[i];}return max;}
}
全排列I
class Solution {List<List<Integer>> res = new ArrayList(); // 所有结果集List<Integer> list = new ArrayList(); // 当前结果集public List<List<Integer>> permute(int[] nums) {boolean[] used = new boolean[nums.length]; // 判断当前元素是否加入结果集dfs(nums, used);return res;}public void dfs(int[] nums, boolean[] used) {if (list.size() == nums.length) { // 当前结果集长度等于数组长度即可加入所有结果集res.add(new ArrayList(list));}for (int i = 0; i < nums.length; i++) {if (used[i] == false) { // 判断元素是否加入当前结果集list.add(nums[i]); // 元素入集合used[i] = true; // 设置元素状态为被使用dfs(nums, used);used[i] = false; // 回溯list.remove(list.size() - 1);}}}
}
全排列II
class Solution {List<List<Integer>> res = new ArrayList(); // 所有结果集合List<Integer> list = new ArrayList(); // 当前结果集合Set<List<Integer>> set = new HashSet(); // 结果集去重public List<List<Integer>> permuteUnique(int[] nums) {boolean[] flag = new boolean[nums.length]; // 判断元素是否加入当前结果集dfs(nums, flag);return res;}public void dfs(int[] nums, boolean[] flag) {if (list.size() == nums.length) { // 当前结果集合等于数组长度即可加入最终结果集List<Integer> tem = new ArrayList(list);if (!set.contains(tem)) { // 判断该结果集是否在最终结果集中存在set.add(tem); // 该结果集的顺序存入去重集合中,避免重复加入最终结果集res.add(tem);}}for (int i = 0; i < nums.length; i++) {if (flag[i] == false) {list.add(nums[i]);flag[i] = true;dfs(nums, flag);flag[i] = false;list.remove(list.size() - 1);}}}
}
N皇后
class Solution {List<List<String>> res = new ArrayList(); // 最终结果集合List<String> list = new ArrayList(); // public List<List<String>> solveNQueens(int n) {char[][] board = new char[n][n]; // 创建棋盘并初始化for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {board[i][j] = '.';}}dfs(board, n, 0);return res;}public void dfs(char[][] board, int n, int row) {if (row == n) { // 当第row行也可以放棋子说明该方法合法res.add(printResult(board, n));return;}for (int col = 0; col < n; col++) {// 判断该位置是否可以填棋if (isFlag(board, row, col)) {board[row][col] = 'Q';dfs(board, n, row + 1);board[row][col] = '.';}}}// 核心方法判断棋子放置位置是否合法public boolean isFlag(char[][] board, int row, int col) { // 判断该位置放棋子是否合法int n = board.length;for (int i = 0; i < n; i++) { // 同一列不能有皇后if (board[i][col] == 'Q') return false;}for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) { // 右斜线不能有皇后if (board[i][j] == 'Q') return false;}for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { // 左斜线不能有皇后if (board[i][j] == 'Q') return false;}return true; // 合法}public List<String> printResult(char[][] board, int n) { // 按照题目要求打印结果集List<String> list = new ArrayList();for (int i = 0; i < n; i++) {StringBuilder sb = new StringBuilder();for (int j = 0; j < n; j++) {sb.append(board[i][j]);}list.add(sb.toString());}return list;}
}
解数独
class Solution {public void solveSudoku(char[][] board) {dfs(board);}public boolean dfs(char[][] board) {for (int i = 0; i < 9; i++) {for (int j = 0; j < 9; j++) {if (board[i][j] == '.') {// 填充数字for (char c = '1'; c <= '9'; c++) {if (isFlag(board, i, j, c)) {board[i][j] = c; // 暂时填充该数字if (dfs(board)) return true;board[i][j] = '.'; // 递归到后面不合法,回溯}}return false;}}}return true;}// 核心方法,判断该位置的数字是否合法public boolean isFlag(char[][] board, int row, int col, char c) { // 判断该数字是否重复for (int i = 0; i < 9; i++) {// 同行出现过if (board[i][col] == c) return false; // 同列出现过if (board[row][i] == c) return false; // 九宫格出现过if (board[(row / 3) * 3 + i / 3][(col / 3) * 3 + i % 3] == c) return false;}return true;}
}