void dfs(int[] p, boolean[] pb, StringBuilder sb, List<List<String>> res){
//1 截止条件
if(p.length == sb.legth()){
res.add(sb.toString());
return;
}
//2 遍历候选节点
for(int i = 0; i < p.length; i ++){
int c = p[i];
if(!pb[i]){ //2.1 筛选候选节点
pb[i] = true;
sb.append(c);
dfs(p, pb, sb, res);
pb[i] = false;
sb.delete(sb.length() - 1, length());
}
}
}
import java.util.*;
public class Solution {
public ArrayList<String> Permutation(String str) {
ArrayList<String> res = new ArrayList<String>();
if(str.equals("") || str.length()==0)return res;
StringBuilder s = new StringBuilder(str);
dfs(s,0,new StringBuilder(),res);
return res;
}
void dfs(StringBuilder s,int index, StringBuilder sb, ArrayList<String> res){
//判断
if(s.length() == index){
if(!res.contains(sb.toString())){
res.append(sb.add(sb.toString()));
}
return;
}
for(int i = 0; i < s.length(); i ++){ //候选元素
char c = s.charAt(i);
if(c != '0'){ //判断是否被访问过
s.setCharAt(i, '0');
sb.a(c);
dfs(s, index + 1, sb, res);
sb.deleteCharAt(sb.length()-1);
s.setCharAt(i, c);
}
}
}
}
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:
输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。
import java.util.*;
class Solution {
char[][] m = {{},{},{'a', 'b', 'c'}, {'d', 'e', 'f'},
{'g', 'h', 'i'}, {'j', 'k', 'l'}, {'m', 'n', 'o'},
{'p', 'q', 'r', 's'},{'t', 'u', 'v'},
{'w', 'x', 'y', 'z'}}; //0和1是空的,值是从2开始
public List<String> letterCombinations(String str) {
List<String> res = new ArrayList<>();
if(str.equals("")){
return res;
}
dfs(str,0,new StringBuilder(),res);
return res;
}
void dfs(String str,int index,StringBuilder sb, List<String>res){
// 1、截止条件
if (index == str.length()){
res.add(sb.toString());
return;
}
// 2、候选节点
for(char c : m[str.charAt(index) - '0']){
sb.append(c); //保存节点数据
dfs(str,index + 1, sb, res); //递归
sb.deleteCharAt(sb.length() - 1); //恢复现场
}
}
}
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
输入:candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:
输入:candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
提示:
1 <= candidates.length <= 30
1 <= candidates[i] <= 200
candidate 中的每个元素都是独一无二的。
1 <= target <= 500
import java.util.*;
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
dfs(candidates,target,new ArrayList<>(),res);
return res;
}
void dfs(int[] c, int t, List<Integer> chaim, List<List<Integer>> res){
//1、截止条件
int s = sum(chaim);
if(s >= t){
if(s == t){
List<Integer> tmp = new ArrayList<>(chaim);
Collections.sort(tmp);
if(!res.contains(tmp)){
res.add(tmp);
}
}
return;
}
//2、候选节点
for(int i = 0; i < c.length; i ++){
int temp = c[i];
chaim.add(temp);
dfs(c, t, chaim,res);
chaim.remove(chaim.size() - 1);
}
}
int sum(List<Integer> a){
int sum = 0;
for(Integer t : a){
sum += t;
}
return sum;
}
}
执行结果:通过
执行用时:
189 ms
, 在所有 Java 提交中击败了
5.00%
的用户
内存消耗:
40.6 MB
, 在所有 Java 提交中击败了
5.20%
的用户
可以看到上边的结果耗时比较久,这是因为有了这个求和的操作,我们可以省略求和,在dfs递归的参数上做文章
import java.util.*;
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
dfs(candidates,target,new ArrayList<>(),res);
return res;
}
void dfs(int[] c, int t, List<Integer> chaim, List<List<Integer>> res){
//1、截止条件
if(0 >= t){
if(0 == t){
List<Integer> tmp = new ArrayList<>(chaim);
Collections.sort(tmp);
if(!res.contains(tmp)){
res.add(tmp);
}
}
return;
}
//2、候选节点
for(int i = 0; i < c.length; i ++){
int temp = c[i];
chaim.add(temp);
dfs(c, t - temp, chaim,res);
chaim.remove(chaim.size() - 1);
}
}
}
执行结果:通过
执行用时:
78 ms
, 在所有 Java 提交中击败了
5.00%
的用户
内存消耗:
40.3 MB
, 在所有 Java 提交中击败了
16.36%
的用户
这题和牛客第27题很相似,只不过这里不是打印出来而是放到list中
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
import java.util.*;
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
boolean[] dp = new boolean[nums.length];
dfs(nums, dp, new ArrayList<Integer>(), res);
return res;
}
void dfs(int[] p, boolean[]dp, List<Integer> chain, List<List<Integer>> res){
//1 截止条件
if(p.length == chain.size()){
res.add(new ArrayList(chain));
return;
}
//2 候选节点
for(int i = 0; i < p.length; i++){
int c = p[i];
if(!dp[i]){
dp[i] = true;
chain.add(c);
dfs(p,dp,chain,res);
chain.remove(chain.size() - 1);
dp[i] = false;
}
}
}
}
执行用时:
1 ms, 在所有 Java 提交中击败了99.76%的用户
内存消耗:
39.9 MB, 在所有 Java 提交中击败了71.61%的用户
import java.util.*;
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
dfs(nums, new ArrayList<Integer>(), res);
return res;
}
void dfs(int[] p, List<Integer> chain, List<List<Integer>> res){
//1 截止条件
if(p.length == chain.size()){
res.add(new ArrayList(chain));
return;
}
//2 候选节点
for(int i = 0; i < p.length; i++){
int c = p[i];
if(p[i]!=65535){
p[i] = 65535;
chain.add(c);
dfs(p,chain,res);
p[i] = c;
chain.remove(chain.size() - 1);
}
}
}
}
去掉了标志数组之后,直接用传入的数组给某一个下标设置标志:
执行用时:
2 ms, 在所有 Java 提交中击败了81.73%的用户
内存消耗:40.1 MB, 在所有 Java 提交中击败了48.51%的用户
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
此DFS算法,关键是总结截止条件和候选节点!
class Solution {
public List<String> generateParenthesis(int n) {
char[] p = new char[]{'(', ')'};
int[] pb = new int[]{n, n};
List<String> res = new ArrayList<>();
dfs(n, p, pb, new StringBuilder(), res);
return res;
}
void dfs(int n,char[] p, int[] pb, StringBuilder sb, List<String> res){
//关键是截止条件和
if(n*2 == sb.length()){
res.add(new String(sb.toString()));
return;
}
//总结候选节点;
if(pb[0]>0){
pb[0] --;
sb.append(p[0]);
dfs(n, p, pb, sb, res);
sb.delete(sb.length() - 1, sb.length());
pb[0] ++;
}
if(pb[1]>0 && pb[0] != pb[1]){
pb[1] --;
sb.append(p[1]);
dfs(n, p, pb, sb, res);
sb.delete(sb.length() - 1, sb.length());
pb[1] ++;
}
}
}
还是使用DFS来做,只不过对候选元素的判断不同,不能大于256并且除了0本身之外不能以0开头。
class Solution {
public List<String> restoreIpAddresses(String s) {
List<String> res = new ArrayList<>();
if(s.equals("") || s.length() < 4 || s.length() >12){
return res;
}
dfs(s, -1, 1, new StringBuilder(), res);
return res;
}
void dfs(String s, int index, int level, StringBuilder sb, List<String> res){
//1 截止条件
if(level == 5 || index == s.length() - 1){
if(level == 5 && index == s.length() - 1){
res.add(sb.toString().substring(0,sb.length() - 1));
}
return;
}
// 2 候选节点
for(int i = 1; i < 4; i++){ // 只能截取1到3个字符
if(index + i + 1 >= s.length() + 1){
continue;
}
String x = s.substring(index + 1,index + i + 1);
//if(x.equals(""))continue;
//2.1 筛选候选节点
int num = Integer.parseInt(x);
if(num <= 255 && (x.equals("0") || !x.startsWith("0"))){
int len = sb.length();
sb.append(x+".");
dfs(s, index + i, level + 1, sb, res);
sb.delete(len, len + x.length() + 1);
}
}
}
}
或者把level去掉
class Solution {
public List<String> restoreIpAddresses(String s) {
List<String> res = new ArrayList<>();
if(s.equals("") || s.length() < 4 || s.length() >12){
return res;
}
dfs(s, -1, new StringBuilder(), res);
return res;
}
void dfs(String s, int index, StringBuilder sb, List<String> res){
//1 截止条件
if(sb.length() == s.length() + 4 || index == s.length() - 1){//因为要是结果正确,会多出4个'.'
if(sb.length() == s.length() + 4 && index == s.length() - 1){
res.add(sb.toString().substring(0,sb.length() - 1));
}
return;
}
// 2 候选节点
for(int i = 1; i < 4; i++){
if(index + i + 1 >= s.length() + 1){
continue;
}
String x = s.substring(index + 1,index + i + 1);
//if(x.equals(""))continue;
//2.1 筛选候选节点
int num = Integer.parseInt(x);
if(num <= 255 && (x.equals("0") || !x.startsWith("0"))){
int len = sb.length();
sb.append(x+".");
dfs(s, index + i, sb, res);
sb.delete(len, len + x.length() + 1);
}
}
}
}