回溯算法问题

组合

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

List<List<Integer>> res = new ArrayList<>();
List<Integer> temp = new ArrayList<>();
public List<List<Integer>> combine(int n, int k) {
  dfs(n,k,1);
  return res;
}
private void dfs(int n, int k, int index) {
  if (temp.size() == k){
    res.add(new ArrayList<>(temp));
    return;
  }
  for (int i = index; i <= n ; i++) {
    temp.add(i);
    dfs(n,k,i+1);
    temp.remove(temp.size()-1);
  }
}

组合总和三

找出所有相加之和为 n 的 k 个数的组合,只使用数字1到9,每个数字只能使用一次

List<List<Integer>> res1 = new ArrayList<>();
LinkedList<Integer> temp1 = new LinkedList<>();
public List<List<Integer>> combinationSum3(int k, int n) {
  dfs1(k,n,1,0);
  return res1;
}
private void dfs1(int k, int n, int index,int sum) {
  if (sum > n){
    return;
  }
  if (temp1.size() == k){
    if (sum == n){
      res1.add(new ArrayList<>(temp1));
      return;
    }
  }
  for(int i = index;i<=9;i++){
    temp1.add(i);
    sum+=i;
    dfs1(k,n,i+1,sum);
    sum-=i;
    temp1.removeLast();
  }
}

电话号码的字母组合

class Solution {
    String letterMap[] = {" ", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    ArrayList<String> res;

    public List<String> letterCombinations(String digits) {
        res = new ArrayList<String>();
        if (digits.equals(""))
            return res;

        dfs(digits, 0, "");
        return res;
    }

    public void dfs(String digits, int index, String s) {
        if (index == digits.length()) {
            res.add(s);
            return;
        }
        Character c=digits.charAt(index);
        String letters=letterMap[c-'0'];
        for(int i=0;i<letters.length();i++){
            dfs(digits,index+1,s+letters.charAt(i));
        }

        return;
    }
}

组合总和

给定一个数组和target,无限次使用,求能组成的序列

List<List<Integer>> res2 = new ArrayList<>();
LinkedList<Integer> temp2 = new LinkedList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
  Arrays.sort(candidates);
  dfs3(candidates,target,0,0);
  return res2;
}

private void dfs3(int[] candidates, int target, int index,int sum) {
  if (sum > target){
    return;
  }
  if (sum == target){
    res2.add(new ArrayList<>(temp2));
    return;
  }
  for(int i = index;i<candidates.length;i++){
    if (sum+candidates[i] > target){
      break;
    }
    temp2.add(candidates[i]);
    dfs3(candidates,target,i,sum+candidates[i]);
    temp2.removeLast();
  }
}

组合总和二

给定一个数组和target,每个数字只能使用一次,求能组成的序列

class Solution {
    List<List<Integer>> res2 = new ArrayList<>();
    LinkedList<Integer> temp2 = new LinkedList<>();

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        dfs3(candidates, target, 0, 0);
        return res2;
    }

    private void dfs3(int[] candidates, int target, int index, int sum) {
        if (sum > target) {
            return;
        }
        if (sum == target) {
            res2.add(new ArrayList<>(temp2));
            return;
        }
        for (int i = index; i < candidates.length; i++) {
            if (i > index && candidates[i] == candidates[i - 1]) {
                continue;
            }
            if (sum + candidates[i] > target) {
                break;
            }
            temp2.add(candidates[i]);
            dfs3(candidates, target, i + 1, sum + candidates[i]);
            temp2.removeLast();
        }

    }
}

分割回文串

class Solution {
    ArrayList<List<String>> res = new ArrayList<>();
    ArrayDeque<String> path = new ArrayDeque<>();

    public List<List<String>> partition(String s) {
        dfs(s, 0);
        return res;
    }
    public void dfs(String s, int index) {
        if (index >= s.length()) {
            res.add(new ArrayList<>(path));
            return;
        }
        for (int i = index; i < s.length(); i++) {
            if (isPal(s, index, i)) {
                String str = s.substring(index, i + 1);
                path.add(str);
            } else continue;
            dfs(s, i + 1);
            path.removeLast();
        }
    }
    public boolean isPal(String s, int index, int end) {
        for (int i = index, j = end; i < j; i++, j--) {
            if (s.charAt(i) != s.charAt(j))
                return false;
        }
        return true;
    }
}

复原IP地址

List<String> ans = new ArrayList();
public List<String> restoreIpAddresses(String s) {
  if (s.length() > 12){
    return ans;
  }
  backTrack(s,0,0);
  return ans;
}

private void backTrack(String s, int start, int pointNum) {
  if (pointNum == 3) {
    if (isvalid(s,start,s.length()-1)){
      ans.add(s);
    }
    return;
  }
  for (int i = start; i < s.length(); i++) {
    if (isvalid(s,start,i)){
      s = s.substring(0,i+1)+"."+s.substring(i+1);
      pointNum++;
      backTrack(s,i+2,pointNum);//有逗号,所以+2
      pointNum--;
      s = s.substring(0,i+1)+s.substring(i+2);
    }else {
      break;
    }
  }
}

private boolean isvalid(String s, int start, int end) {
  if (start>end){
    return false;
  }
  if (s.charAt(start)=='0' && start !=end){
    return false;
  }
  int num = 0;
  for (int i = start; i <= end; i++) {
    if (s.charAt(i)>'9' || s.charAt(i) < '0'){
      return false;
    }
    num = num * 10 +(s.charAt(i) - '0');
    if (num > 255){
      return false;
    }
  }
  return true;
}

子集

List<List<Integer>> subsets = new ArrayList<>();
List<Integer> subsetsPath = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
  subsetsDfs(nums,0);
  return subsets;
}

private void subsetsDfs(int[] nums, int index) {
  subsets.add(new ArrayList<>(subsetsPath));
  if (index >= nums.length){
    return;
  }
  for (int i = index; i < nums.length; i++) {
    subsetsPath.add(nums[i]);
    subsetsDfs(nums,i+1);
    subsetsPath.remove(subsetsPath.size()-1);
  }
}

全排列

List<List<Integer>> res = new ArrayList();
ArrayDeque<Integer> path = new ArrayDeque();
boolean[] used;
public List<List<Integer>> permute(int[] nums) {
    used = new boolean[nums.length];
    dfs(nums);
    return res;
}

private void dfs(int[] nums){
    if(path.size() == nums.length){
        res.add(new ArrayList(path));
        return;
    }
    for(int i = 0;i<nums.length;i++){
        if(used[i]){
            continue;
        }
        used[i] = true;
        path.add(nums[i]);
        dfs(nums);
        path.removeLast();
        used[i] = false;
    }
}

全排列二

给定一个可包含重复数字的序列,要返回所有不重复的全排列。

class Solution {
    //存放结果
    List<List<Integer>> result = new ArrayList<>();
    //暂存结果
    List<Integer> path = new ArrayList<>();

    public List<List<Integer>> permuteUnique(int[] nums) {
        boolean[] used = new boolean[nums.length];
        Arrays.fill(used, false);
        Arrays.sort(nums);
        backTrack(nums, used);
        return result;
    }

    private void backTrack(int[] nums, boolean[] used) {
        if (path.size() == nums.length) {
            result.add(new ArrayList<>(path));
            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;
            }
            //如果同⼀树⽀nums[i]没使⽤过开始处理
            if (used[i] == false) {
                used[i] = true;//标记同⼀树⽀nums[i]使⽤过,防止同一树枝重复使用
                path.add(nums[i]);
                backTrack(nums, used);
                path.remove(path.size() - 1);//回溯,说明同⼀树层nums[i]使⽤过,防止下一树层重复
                used[i] = false;//回溯
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值