递归与回溯

递归与回溯

  • 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。

    返回 s 所有可能的分割方案。

    输入: "aab"
    输出:
    [
      ["aa","b"],
      ["a","a","b"]
    ]
    
    LeetCode 131
    
    class Solution {
        public List<List<String>> partition(String s) {
            List<List<String>> result=new ArrayList<>();
            DFS(result,s,new ArrayList<String>());
            return result;   
        }
        public void DFS(List<List<String>> result,String s,List<String> temp){
            if(s.length()==0){
                //每次需要新new一个ArrayList 把temp赋值过去
                //不能直接使用temp temp还会因为回溯动态变化
                result.add(new ArrayList<String>(temp));
                return;
            }
            for(int i=1;i<=s.length();i++){
                if(isPalindrome(s.substring(0,i))){
                    temp.add(s.substring(0,i));
                    DFS(result,s.substring(i,s.length()),temp);
                    //回溯
                    temp.remove(temp.size()-1);
                }
            }
        }
        public boolean isPalindrome(String s){
           for(int l=0,r=s.length()-1;l<r;l++,r--){
               if(s.charAt(l)!=s.charAt(r)){
                   return false;
               }
           }
           return true;
        }
    }
    
  • 给定一个 没有重复 数字的序列,返回其所有可能的全排列。

    输入: [1,2,3]
    输出:
    [
      [1,2,3],
      [1,3,2],
      [2,1,3],
      [2,3,1],
      [3,1,2],
      [3,2,1]
    ]
    
    leetcode -- 46
    
    class Solution {
        public List<List<Integer>> permute(int[] nums) {
            List<List<Integer>> result=new ArrayList<>();
            boolean[] used=new boolean[nums.length];
            return DFS(result,nums,used,new ArrayList<>());
        }
        public List<List<Integer>> DFS(List<List<Integer>> result,int[] nums,boolean[] used,List<Integer> temp){
            //表明temp添加完了所有数 递归出口
            if(temp.size()==nums.length){
                result.add(new ArrayList<>(temp));
                return result;
            }
            for(int i=0;i<nums.length;i++){
                if(used[i]!=true){
                    //temp在动态保存添加过程中的结果值
                    temp.add(nums[i]);
                    used[i]=true;
                    DFS(result,nums,used,temp);
                    used[i]=false;
                    temp.remove(temp.size()-1);
                }
            }
            return result;
        }
    }
    
  • 给定一个可包含重复数字的序列,返回所有不重复的全排列。

    输入: [1,1,2]
    输出:
    [
      [1,1,2],
      [1,2,1],
      [2,1,1]
    ]
    
    leetcode - 47
    
    class Solution {
        public List<List<Integer>> permuteUnique(int[] nums) {
            //排序
            Arrays.sort(nums);
            List<List<Integer>> result=new ArrayList<>();
            boolean[] used=new boolean[nums.length];
            return DFS(result,nums,used,new ArrayList<>());
        }
        public List<List<Integer>> DFS(List<List<Integer>> result,int[] nums,boolean[] used,List<Integer> temp){
            if(temp.size()==nums.length){
                result.add(new ArrayList<>(temp));
                return result;
            }
            for(int i=0;i<nums.length;i++){
                if(used[i]!=true){
                    //剪枝
                    //注意used[i-1]==false 表示nums[i-1]刚刚被撤销 这种就需要剪枝
                    //如果used[i-1]!=false 表示nums[i]在正常添加过程中 如果剪枝反而错误
                    if(i>0&&nums[i]==nums[i-1]&&!used[i-1])
                        continue;
                    temp.add(nums[i]);
                    used[i]=true;
                    DFS(result,nums,used,temp);
                    used[i]=false;
                    temp.remove(temp.size()-1);
                }
            }
            return result;
        }
    }
    
    
  • 给定两个整数 nk,返回 1 … n 中所有可能的 k 个数的组合。

输入: n = 4, k = 2
 输出:
 [
   [2,4],
   [3,4],
   [2,3],
   [1,2],
   [1,3],
   [1,4],
 ]
 
 leetcode -77
class Solution {
    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> result=new ArrayList<>();
        int[] nums=new int[n];
        for(int i=0;i<n;i++){
            nums[i]=i+1;
        }
        return DFS(result,k,new ArrayList<Integer>(),0,nums);
    }
    public List<List<Integer>> DFS(List<List<Integer>>  result,int k,ArrayList<Integer> temp,int index,int[] nums){
        if(temp.size()==k){
            result.add(new ArrayList(temp));
            return result;
        }
        for(int i=index;i<nums.length;i++){
                temp.add(nums[i]);
            	//这里下一次DFS的时候 index赋值为i+1 保证已经选出的元素不在出现
                DFS(result,k,temp,i+1,nums);   
                temp.remove(temp.size()-1);
        }
        return result;
    }
}
  • 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

    输入: candidates = [2,3,5], target = 8,
    所求解集为:
    [
      [2,2,2,2],
      [2,3,3],
      [3,5]
    ]
    
     所有数字(包括 `target`)都是正整数。
     解集不能包含重复的组合。 
    
    (LeetCode -- 39)
    
    class Solution {
        public List<List<Integer>> combinationSum(int[] candidates, int target) {
            List<List<Integer>> result=new ArrayList<>();
            return DFS(candidates,result,new ArrayList<Integer>(),target,0);
        }
        public List<List<Integer>> DFS(int[] candidates,List<List<Integer>> result,List<Integer> temp,int target,int start){
            
            if(target<0)
                return result;
    
            if(target==0){
                result.add(new ArrayList<>(temp));
                return result;
            }
            
            //对于解集不能包含重复的组合问题 循环从start开始 保证解集中没有重复
            for(int i=start;i<candidates.length;i++){
                temp.add(candidates[i]);
                //这里下一次DFS的start赋值为i 是因为解中可以出现2 2 2 。。这样重复元素的情况
                DFS(candidates,result,temp,target-candidates[i],i);
                temp.remove(temp.size()-1);
            }
            return result;
        }
    }
    
  • 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

    candidates 中的每个数字在每个组合中只能使用一次。
    
    输入: candidates = [10,1,2,7,6,1,5], target = 8,
    所求解集为:
    [
      [1, 7],
      [1, 2, 5],
      [2, 6],
      [1, 1, 6]
    ]
    
    (LeetCode --40)
    
    class Solution {
        public List<List<Integer>> combinationSum2(int[] candidates, int target) {
            //先排序
            Arrays.sort(candidates);
            List<List<Integer>> result=new ArrayList<>();
            boolean[] used=new boolean[candidates.length];
            return DFS(candidates,result,new ArrayList<Integer>(),target,used,0);
        }
        public List<List<Integer>> DFS(int[] candidates,List<List<Integer>> result,List<Integer> temp,int target,boolean[] used,int start){
            if(target<0)
                return result;
    
            if(target==0){
                result.add(new ArrayList<>(temp));
                return result;
            }
    		//定义start索引 解决解集不能包含重复的组合
            for(int i=start;i<candidates.length;i++){
                if(!used[i]){
                    //剪枝 给定的样例中包含重复元素 为了解集不能包含重复的组合 剪枝
                    if(i>0&&candidates[i]==candidates[i-1]&&!used[i-1])
                       continue;               
                    temp.add(candidates[i]);
                    used[i]=true;
                    DFS(candidates,result,temp,target-candidates[i],used,i+1);
                    used[i]=false;
                    temp.remove(temp.size()-1);
                }
            }
            return result;
        }
    }
    
  • 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

    说明:
    
    所有数字都是正整数。
    解集不能包含重复的组合。 
    
    ​```xml
    输入: k = 3, n = 9
    输出: [[1,2,6], [1,3,5], [2,3,4]]
    ​```
    
    leetcode 216
    
    class Solution {
        public List<List<Integer>> combinationSum3(int k, int n) {
            List<List<Integer>> result=new ArrayList<>();
            int[] nums=new int[9];
            for(int i=0;i<9;i++){
                nums[i]=i+1;
            }
            return DFS(result,nums,new ArrayList<>(),n,k,0);
        }
        public List<List<Integer>> DFS(List<List<Integer>> result,int[] nums,List<Integer> temp,int n,int k,int start){
            if(n<0){
                return result;
            }
    
            //递归终止条件有2个  temp的大小为3 且这3个数和为给定的值
            if(temp.size()==k&&n==0){
                result.add(new ArrayList<>(temp));
                return result;
            }
    
            //解集不能包含重复的组合问题 从start开始循环 不每次从0开始
            for(int i=start;i<nums.length;i++){
                temp.add(nums[i]);
                DFS(result,nums,temp,n-nums[i],k,i+1);
                temp.remove(temp.size()-1);
            }
            return result;
        }
    }
    
    
  • 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

    说明:解集不能包含重复的子集。
    
    输入: nums = [1,2,3]
    输出:
    [
      [3],
      [1],
      [2],
      [1,2,3],
      [1,3],
      [2,3],
      [1,2],
      []
    ]
    
    来源:力扣(LeetCode--78)
    
    class Solution {
        public List<List<Integer>> subsets(int[] nums) {
            List<List<Integer>> result=new ArrayList<>();
            //对元素个数k做一次循环 这个k对应了DFS时候的终止条件
            for(int k=0;k<=nums.length;k++){
                DFS(result,new ArrayList<>(),k,nums,0);
            }
            return result;
        }
        public void  DFS(List<List<Integer>> result,List<Integer> temp,int k,int[] nums,int start){
            if(temp.size()==k){
                result.add(new ArrayList<>(temp));
                return;
            }
            for(int i=start;i<nums.length;i++){
                temp.add(nums[i]);
                DFS(result,temp,k,nums,i+1);
                temp.remove(temp.size()-1);
            }
            return;
        }
    }
    
  • 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

    **说明:**解集不能包含重复的子集。

    输入: [1,2,2]
    输出:
    [
      [2],
      [1],
      [1,2,2],
      [2,2],
      [1,2],
      []
    ]
    
    leetcode -90
    
    class Solution {
        public List<List<Integer>> subsetsWithDup(int[] nums) {
            Arrays.sort(nums);
            List<List<Integer>> result=new ArrayList<>();
            boolean[] flags=new boolean[nums.length];
            for(int k=0;k<=nums.length;k++){
                DFS(result,new ArrayList<>(),k,nums,0,flags);
            }
            return result;
        }
         public void  DFS(List<List<Integer>> result,List<Integer> temp,int k,int[] nums,int start,boolean[] flags){
            if(temp.size()==k){
                result.add(new ArrayList<>(temp));
                return;
            }
            for(int i=start;i<nums.length;i++){
                if(!flags[i]){
                    //给定输入样例中包含重复元素 就要先排序 后剪枝
                    if(i>0&&nums[i]==nums[i-1]&&!flags[i-1])
                            continue;
                        temp.add(nums[i]);
                        flags[i]=true;
                        DFS(result,temp,k,nums,i+1,flags);
                        flags[i]=false;
                        temp.remove(temp.size()-1);
                    
                }
            }
            return;
         }
    }
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值