回溯面试常考题

本文介绍了多个使用递归解决的算法问题,包括二叉树路径和、子集生成(考虑重复元素)、字符串排列、全排列(含重复元素)、加和目标值的组合以及数字字符串转IP地址等。这些算法均采用深度优先搜索(DFS)策略,通过回溯找到所有可能的解决方案。同时,还涵盖了组合问题,如无重复元素的组合总和和含有重复元素的集合。
摘要由CSDN通过智能技术生成

二叉树和为某一路径值

https://leetcode-cn.com/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof/

class Solution {
    List<List<Integer>> ret = new LinkedList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> pathSum(TreeNode root, int target) {
        if(root == null) {
            return ret;
        }
        dfs(root, target);
        return ret;
    }
    public void dfs(TreeNode root, int target) {
        if(root == null) {
            return ;
        }
        path.add(root.val);
        target -= root.val;
        if(target == 0 && root.left == null && root.right == null) {
            ret.add(new LinkedList(path));
        }
        dfs(root.left, target);
        dfs(root.right, target);
        path.removeLast();
    }
}

子集I(无重复元素,返回幂集)

https://leetcode-cn.com/problems/subsets/

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> ret = new ArrayList<>();
        ret.add(new ArrayList<>());
        for (int i = 0; i < nums.length; i++) {
           int size = ret.size();
            for (int j = 0; j < size; j++) {
                List<Integer> tmp = new ArrayList<>(ret.get(j));
                tmp.add(nums[i]);
                ret.add(tmp);
            }
        }
        return ret;
    }
}

子集II含义重复元素,返回幂集)

https://leetcode-cn.com/problems/subsets-ii/

class Solution {
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> ret = new ArrayList<>();
        ret.add(new ArrayList<>());
        if(nums == null || nums.length == 0) {
            return ret;
        }
        Arrays.sort(nums);
        List<Integer> list = new ArrayList<>();
        list.add(nums[0]);
        ret.add(list);
        if(nums.length == 1) {
            return ret;
        }
        int len = 1;
        for(int i = 1; i < nums.length; i++){
            int size = ret.size();
            if(nums[i] != nums[i-1]){
                len = size;
            }
            
            for(int j = size - len; j < size; j++){
                List<Integer> tmp = new ArrayList(ret.get(j));
                tmp.add(nums[i]);
                ret.add(tmp);
            }
        }
        return ret;
    }
}

字符串的排列

class Solution {
    List<String> ret = new ArrayList<>();
    public String[] permutation(String s) {
        if(s.length() == 0) {
            return new String[0];
        }
        int n = s.length();
        char[] str = s.toCharArray();
        Arrays.sort(str);
        StringBuffer path = new StringBuffer();
        boolean[] used = new boolean[n];
        dfs(str, n, 0, used, ret, path);
        return ret.toArray(new String[0]);
    }
    public void dfs(char[] str, int len, int depth, boolean[] used, List<String> ret, StringBuffer path ) {
        if(depth == len) {
            ret.add(path.toString());
        }
        for(int i = 0; i < len; i++) {
         if(used[i]) {
             continue;
         }
        
        if(i > 0 && str[i] == str[i - 1] && !used[i - 1]) {
            continue;
        }
        path.append(str[i]);
        used[i] = true;
        dfs(str, len, depth + 1, used, ret, path);
        used[i] = false;
        path.deleteCharAt(path.length() - 1);
         }
    }
}

没有重复数字的所有排列(全排列I)

https://leetcode-cn.com/problems/permutations/

class Solution {
    public List<List<Integer>> ret = new ArrayList<>();
    public List<Integer> path = new ArrayList<>();

    public List<List<Integer>> permute(int[] nums) {
        if(nums == null || nums.length == 0) {
            return ret;
        }
        int n = nums.length;
        boolean[] used = new boolean[n];
        dfs(nums, n, 0, used, ret, path);
        return ret;
    }
    public void dfs(int[] nums, int len, int depth, boolean[] used, List<List<Integer>> ret,
    List<Integer> path) {
        if(depth == len) {
            ret.add(new ArrayList<>(path));
        }
        for(int i = 0; i < nums.length; i++) {
            if(!used[i]) {
                path.add(nums[i]);
                used[i] = true;
                dfs(nums, len, depth + 1, used, ret, path);
                used[i] = false;
                path.remove(path.size() - 1);
            }
        }
    } 
}

含有重复数字的所有排列(全排列II)

import java.util.*;

public class Solution {
    ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
    ArrayList<Integer> path = new ArrayList<>();
    public ArrayList<ArrayList<Integer>> permuteUnique(int[] nums) {
        if(nums == null || nums.length == 0) {
            return ret;
        }
        Arrays.sort(nums);
        int n = nums.length;
        boolean[] used = new boolean[n];
        dfs(nums, n, 0, used, ret, path);
        return ret;
    }
    public void dfs(int[] nums, int len, int depth, boolean[] used, ArrayList<ArrayList<Integer>> ret, ArrayList<Integer> path) {
        if(len == depth) {
            ret.add(new ArrayList<>(path));
        }
        for(int i = 0; i < nums.length; i++) {
           if(used[i]) {
               continue;
           }
            if(i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) {
                continue;
            }
            path.add(nums[i]);
            used[i] = true;
            dfs(nums, len, depth + 1, used, ret, path);
            used[i] = false;
            path.remove(path.size() - 1);
        }
    }
}

加起来和为目标的值(一)(没有重复的元素)

https://www.nowcoder.com/questionTerminal/172e6420abf84c11840ed6b36a48f8cd

import java.util.*;
public class Solution {
    ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
    public ArrayList<ArrayList<Integer>> combinationCount (int target, int[] nums) {
        // write code here
        dfs(nums, 0, target, new ArrayList<Integer>());
        return ret;
    }
     
    private void dfs(int[] nums, int depth, int rest, ArrayList<Integer> path) {
        if(rest < 0){
            return;      // 凑过头了,直接返回
        }
        if(rest == 0){
            ret.add(new ArrayList<Integer>(path));     // 刚好凑到目标,返回一组结果
        }else{
            for(int i = depth; i < nums.length; i++){
                path.add(nums[i]);
                dfs(nums, i, rest - nums[i], path);
                path.remove(path.size() - 1);     // 回溯
            }
        }
    }
}

加起来和为目标的值(二)(有重复的元素)

https://www.nowcoder.com/practice/75e6cd5b85ab41c6a7c43359a74e869a?tpId=117&&tqId=37742&&companyId=139&rp=1&ru=/company/home/code/139&qru=/ta/job-code-high/question-ranking

import java.util.*;
public class Solution {
      
    ArrayList<ArrayList<Integer>> ret=new ArrayList<>();
    ArrayList<Integer> path = new ArrayList<>();
    public ArrayList<ArrayList<Integer>> combinationSum2(int[] num, int target) {
        //首先排序
        Arrays.sort(num);
        dfs(num,0,target,path);
        return ret;
    }
     
    public void dfs(int []num,int index,int target,ArrayList<Integer> path){
        //我们这里做减法,当target为0 返回正确结果
        if(target == 0){
            ret.add(new ArrayList<>(path));
            return;
        }
        //这里进行循环
        for(int i = index; i < num.length; i++){
            //进行剪枝,当 num[i]>target的时候  肯定不能继续遍历
            if(target - num[i] < 0){
                break;
            }
            //当有相等元素时候,跳过,避免重复
            if(i > index && num[i] ==  num[i-1]){
                continue;
            }
            //代码到这里 已经是有效答案了
            path.add(num[i]);
            //继续进行递归, 注意这里下标不是  index+1   而是  i+1,
            dfs(num, i + 1, target - num[i], path);
            //回溯  这里要remove掉 
            path.remove(path.size()-1);
        }
    }
}

组合总和(允许重复选择元素的组合) 无重复元素,元素可以使用多次

https://leetcode-cn.com/problems/combination-sum/
给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是唯一的。

class Solution {
    List<List<Integer>> res = new ArrayList<>(); //记录答案
    List<Integer> path = new ArrayList<>();  //记录路径

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        dfs(candidates, 0, target);
        return res;
    }
    public void dfs(int[] nums, int u, int target) {
        if(target < 0) return ;
        if(target == 0)
        {
            res.add(new ArrayList(path));
            return ;
        }
        for(int i = u; i < nums.length; i++){
            if( nums[i] <= target)  
            {
                path.add(nums[i]);
                dfs(nums, i, target -  nums[i]); // 因为可以重复使用,所以还是i
                path.remove(path.size() - 1); //回溯,恢复现场
            }
        }
    }
}

含有重复元素的集合(有重复元素,但只能使用一次)

https://leetcode-cn.com/problems/4sjJUc/

给定一个可能有重复数字的整数数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次,解集不能包含重复的组合。

class Solution {
    List<List<Integer>> ret=new ArrayList<>();
    List<Integer> path = new ArrayList<>();
    public List<List<Integer>> combinationSum2(int[] nums, int target) {
      //首先排序
        Arrays.sort(nums);
        dfs(nums, 0, target, path);
        return ret;
    }
     
    public void dfs(int[] num, int index, int target, List<Integer> path){
        //我们这里做减法,当target为0 返回正确结果
        if(target == 0){
            ret.add(new ArrayList<>(path));
            return;
        }
        //这里进行循环
        for(int i = index; i < num.length; i++){
            //进行剪枝,当 num[i]>target的时候  肯定不能继续遍历
            if(target - num[i] < 0){
                break;
            }
            //当有相等元素时候,跳过,避免重复
            if(i > index && num[i] ==  num[i-1]){
                continue;
            }
            //代码到这里 已经是有效答案了
            path.add(num[i]);
            //继续进行递归, 注意这里下标不是  index+1   而是  i+1,
            dfs(num, i + 1, target - num[i], path);
            //回溯  这里要remove掉 
            path.remove(path.size()-1);
        }
    }
}

数字字符串转换成ip地址

https://www.nowcoder.com/practice/ce73540d47374dbe85b3125f57727e1e?tpId=117&&tqId=37725&&companyId=665&rp=1&ru=/company/home/code/665&qru=/ta/job-code-high/question-ranking

import java.util.*;


public class Solution {
    ArrayList<String> ret = new ArrayList<>();
    ArrayList<String> path = new ArrayList<>();
    public ArrayList<String> restoreIpAddresses (String s) {
        // write code here
        if(s.length() > 12 || s.length() < 4){
            return ret;
        }
        dfs(s, 0, ret, path);
        return ret;
    }
     private void dfs(String s, int depth, List<String> ret, List<String> path){
        int n = s.length();
        int size = path.size();
        if(3 * (4 - size) < n - depth || n - depth < (4 - size)){
            // 剩下的分不完了,剪枝
            return;
        }
        if(size == 4 && depth == n){
            // 正确的情况
            StringBuilder tmp = new StringBuilder();
            boolean first = true;
            for(String str : path){
                if(!first){
                    tmp.append(".");
                }
                first = false;
                tmp.append(str);
            }
            ret.add(tmp.toString());
            return;
        }
        // 如果是0需要特判
        if(s.charAt(depth) == '0'){
            path.add("0");
            dfs(s, depth + 1, ret, path);
            path.remove(path.size() - 1);
        }else{
            // 防止越界
            int right = Math.min(depth + 3, n);
            for(int i = depth; i < right; i++){
                String tmp = s.substring(depth, i + 1);
                if(check(tmp)){
                    path.add(tmp);
                    dfs(s, i + 1, ret, path);
                    path.remove(path.size() - 1);
                }
            }
        }
    }

    private boolean check(String s){
        int num = Integer.valueOf(s);
        return num <= 255 && num >= 0;
    }
}

组合

https://leetcode-cn.com/problems/combinations/
在这里插入图片描述

class Solution {
    List<List<Integer>> ret = new ArrayList<>();
    List<Integer> path = new ArrayList<>();
    public List<List<Integer>> combine(int n, int k) {
        if(k == 0) {
            return ret;
        }
        dfs(n, k, 1);
        return ret;
    }
    
    //1、递归函数的参数和返回值
    public void dfs(int n, int k, int depth){
        //2、递归终止条件
        if(path.size() == k){
            ret.add(new ArrayList<>(path));
            return;
        }
        //3、单层逻辑
        for (int i = depth; i <= n; i++) {
            path.add(i);
            dfs(n, k, i + 1);
            //回溯
            path.remove(path.size() - 1);
        }
    }
}

含有k个元素的组合

https://leetcode-cn.com/problems/uUsW3B/

class Solution {
    private List<List<Integer>> ret = new ArrayList<>();
    private List<Integer> path = new ArrayList<>();
    public List<List<Integer>> combine(int n, int k) {
    dfs(1, n, k, path);
    return ret;
  }

  private void dfs(int num, int n, int k, List<Integer> path) {
    if (k == 0) {
      ret.add(new ArrayList<>(path));
      return;
    }
    for (int i = num; i <= n; i++) {
      path.add(i);
      dfs(i + 1, n, k - 1, path);
      path.remove(path.size() - 1);
    }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值