回溯算法(更新中。。。

一:回溯算法(加剪枝、去重

1、 #17 电话号码的字母组合

在这里插入图片描述

class Solution {
     public static List<String> letterCombinations(String digits) {
        if (digits.length()==0){
            return new ArrayList<>();
        }
        String[] strings = new String[]{"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
        List<String> res = new ArrayList<>();
        int index = 0;
        return letterCombinationsHelp(strings,0,digits,res,"");
    }
    public static List<String> letterCombinationsHelp(String[] strings,int index ,String digits,List<String> list,String temp) {
        if (index<digits.length()-1){
            int digit = digits.charAt(index)-'0';//当前数字字符对应的整型数字
            for (int j=0;j<strings[digit].length();j++){
                list = letterCombinationsHelp(strings,index+1,digits,list,temp+strings[digit].charAt(j));
            }
        }else{
            int digit = digits.charAt(index)-'0';//当前数字字符对应的整型数字
            for (int j=0;j<strings[digit].length();j++){
                list.add(temp+strings[digit].charAt(j));
            }
        }
        return list;
    }
}

2、 #22 括号生成

在这里插入图片描述

class Solution {
    public static List<String> generateParenthesis(int n) {
        if (n==0) return new ArrayList<>();
        int left=0,right=0;//左括号好有括号初始个数都是0
        List<String> list = new ArrayList<>();
        generateParenthesisHelp(list,n,left,right,"");
        return list;
    }
    public static void generateParenthesisHelp(List<String> list,int n,int left,int right,String temp) {
        if (left==n&&right==n){
            list.add(temp);
            return;
        }
        if (left < n) { // 如果左括号还剩余的话,可以拼接左括号
            generateParenthesisHelp(list,n,left+1,right,temp+"(");
        }
        if (left>right) { // 如果右括号剩余多于左括号剩余的话,可以拼接右括号
            generateParenthesisHelp(list,n,left,right+1,temp+")");
        }
    }
}

3、 #39. 组合总和

在这里插入图片描述

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        Arrays.sort(candidates);//升序排列
        combinationSumHelp(new ArrayList<>(),candidates,target,0);
        return res;
    }
    public void  combinationSumHelp(List<Integer> list,int[] candidates, int target,int index){
        if (target<0) return;
        if (target==0) {
            res.add(new ArrayList<>(list));
            return;
        }
        //target>0
        for (int i=index;i<candidates.length;i++){
            if (target-candidates[i]<0) break;//如果当前数字不满足,后面的都不满足,直接break
            list.add(candidates[i]);
            target-=candidates[i];
            combinationSumHelp(list,candidates,target,i);
            target+=list.remove(list.size()-1);
        }
    }
}

4、 #组合总和 II

在这里插入图片描述

class Solution {
    public static List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(candidates);
        combinationSum2Help(result,new ArrayList<Integer>(),candidates,target,0);
        return result;
    }
    public static void combinationSum2Help(List<List<Integer>> result,List<Integer> list,int[] candidates, int target,int index) {
        if (target<0){
            return;
        }
        if (target==0&&!result.contains(list)){
            result.add(new ArrayList<>(list));
            return;
        }
        for (int i=index;i<candidates.length;i++){
            if (target-candidates[i]<0){
                break;
            }
            list.add(candidates[i]);
            target-=candidates[i];
            combinationSum2Help(result,list,candidates,target,i+1);
            target+=list.remove(list.size()-1);

        }
    }
}

5、 #46 全排列

在这里插入图片描述

class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>>  res = new ArrayList<>();
        permuteHelp(nums,res,new ArrayList<>());
        return res;
    }
    public void permuteHelp(int[] nums,List<List<Integer>>  res,List<Integer> list) {
        if (list.size()==nums.length){
            res.add(new ArrayList<>(list));
            return;
        }
        for (int i =0 ;i<nums.length;i++){
            if (!list.contains(nums[i])){
                list.add(nums[i]);
                permuteHelp(nums,res,list);
                list.remove(list.size()-1);
            }
        }
    }
}

6、 #47全排列 II

在这里插入图片描述

class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        int[] visited=new int[nums.length];
        permuteUniqueHelp(res,new ArrayList<>(),nums,visited);
        return res;
    }
    public void permuteUniqueHelp(List<List<Integer>> res,List<Integer> list,int[] nums,int[] visited){
        if (list.size()==nums.length){
            res.add(new ArrayList<>(list));
        }
        for (int i =0;i<nums.length;i++){
            if (visited[i]==0){
                if (i>0&&nums[i]==nums[i-1]&&visited[i-1]==0){
                    //重点就是剪枝:如果这个数和之前的数一样,并且之前的数还未使用过(说明已经回溯过)
                    continue;
                }
                visited[i]=1;
                list.add(nums[i]);
                permuteUniqueHelp(res,list,nums,visited);
                list.remove(list.size()-1);
                visited[i]=0;
            }
        }
    }
}

7、 #51. N皇后

在这里插入图片描述
在这里插入图片描述

class Solution {
    public List<List<String>> solveNQueens(int n) {
        /*
        想法:从第一行开始递归,每一行都有n个选择,当满足n皇后的条件时放置Q,否则剪枝;
              因为有多个选择,所以可以撤销之前的选择,;
         */
        //初始化 n 行 n 列的...
        StringBuffer stringBuffer = new StringBuffer();
        List<String> list = new ArrayList<>();
        List<List<String>> res = new ArrayList<>();
        for (int i =0;i<n;i++){
            stringBuffer.append(".");
        }
        for (int i =0;i<n;i++){
            list.add(stringBuffer.toString());
        }

        solveNQueensHelp(res,list,n,0);
        return res;
    }
    public void solveNQueensHelp(List<List<String>> res,List<String> list,int n,int row) {
        if (row==n){
            res.add(new ArrayList<>(list));
            return;
        }
        for (int j =0;j<n;j++){
            if (!IsSolveNQueens(list,n,row,j)){
                continue;
            }
            String temp = list.get(row);
            temp=temp.substring(0,j)+'Q'+temp.substring(j+1,n);
            list.set(row,temp);
            solveNQueensHelp(res,list,n,row+1);
            String tp = list.get(row);
            tp=tp.substring(0,j)+'.'+tp.substring(j+1,n);
            list.set(row,tp);
        }
    }
    public boolean IsSolveNQueens(List<String> list,int n,int row,int col) {//当前位置是否可以放置Q
        //因为当前行的的后面几行 还没有放置元素,所以直接判断当前列、左上对角线、右上对角线是否有重复元素即可
        for (int i=0;i<n;i++){
            if (list.get(i).charAt(col)=='Q'){
                return false;
            }
        }
        for (int i = row-1,j=col+1;i>=0&&j<n;i--,j++ ){//右上
            if (list.get(i).charAt(j) == 'Q') {
                return false;
            }
        }
        for (int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){//左上
            if (list.get(i).charAt(j) == 'Q') {
                return false;
            }
        }
        return true;
    }
}

8、 #60. 第k个排列

在这里插入图片描述

 public static String getPermutation(int n, int k) {
        /*
        因为是按照顺序排列,1 开头的排列完之后,开始 2 ,然后 3 ,4开头的排列
        分别以 1,2,3,4开头的排列有 (n-1)!个
        比如 n=4,k=18 ,list(1,2,3,4)
        index=ceil(k/3!)=3,找到第一个开头的数字是list中第几个 ,此时 是第3个,也就是 第一个开头的数字是 3
        3之前开头的数字也就是1,2开头的排列有(4-1)!*2种=12
        list中还剩下 1,2,4,所以找第 18 个排列变成了在剩余list中找第 k= 18-12=6个排列
        1,2,4开头的数字分别有 2!个
        index = ceil(k/2!) = 3 是list中的第三个数字      4;
        以此类推  k = k- (3-1)*2!=2;
       list(1,2)
       index = ceil(k/1!) = 2;        list中的第2个数字   2;
       把最后一个数字 1  放在字符串结尾
       最终结果 3421
         */
        List<Integer> list = new ArrayList<>();
        for (int i=1;i<=n;i++){
            list.add(i);
        }
        String res="";
        while (list.size()>1){
            int index = (int) Math.ceil(1.0*k/fb(n-1));//找第k个是以那个数字开头的
            res+=list.remove(index-1);
            //从list中剩下的几个数字里面找新的index
            k = k-(index-1)*fb(n-1);//去掉index之前的排列数,找新的第k个排列
            n=n-1;
        }
        res+=list.get(0);
        return res;
    }
    public static int fb(int n){
        if (n==1)
            return 1;
        return n*fb(n-1);
    }

9、 #77.组合

在这里插入图片描述

public static List<List<Integer>> combine(int n, int k) {
    	List<List<Integer>> res = new ArrayList<>();
    	int[] nums = new int[n];
    	for (int i = 0; i < n; i++) {
			nums[i]=i+1;
		}
    	combineHelp(res,new ArrayList<>(),nums,n,k,0);
    	return res;
    }
    public static void combineHelp(List<List<Integer>> res,List<Integer> list,int[] nums,int n, int k,int index) {
    	if (list.size()==k) {
			res.add(new ArrayList<>(list));
			return;
		}
    	for (int i = index;i<=n-(k-list.size());i++) {
    		/*	1,2,3,4,5 。n=5,k=3时,序号0,1,2,3,4,添加3个数时,i的最大值是2即最后一个组合是(2,3,4),此时max(i)=n-k=2,
    		 * 	当list添加1,list(1),添加2个数时,从序号1,2,3,4里面找两个,最后一个组合是(3,4),此时max(i)=n-k+3;
    		 * 	当list(1,2)时,从3,4里面找1个数,maix(i)=n-k+2=4;
    		 *	可以看成是i<=n-(k-list.size())
    		 *	 i<=n-(k-list.size())减枝
    		 */
    		list.add(nums[i]);
    		combineHelp(res, list, nums, n, k, i+1);
    		list.remove(list.size()-1);
		}
    }

10、#78. 子集

在这里插入图片描述

public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        subsetsHelp(res,new ArrayList<>(),nums,0);
        return res;
    }
    public void subsetsHelp(List<List<Integer>> res,List<Integer> list,int[] nums,int index){
        res.add(new ArrayList<>(list));
        for (int i=index;i<nums.length;i++){
            list.add(nums[i]);
            subsetsHelp(res,list,nums,i+1);
            list.remove(list.size()-1);
        }
    }

11、#90. 子集 II

在这里插入图片描述

public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        subsetsWithDupHelp(res,new ArrayList<>(),nums,0);
        return res;
    }
    public void subsetsWithDupHelp(List<List<Integer>> res,List<Integer> list,int[] nums,int index){
        res.add(new ArrayList<>(list));
        for (int i=index;i<nums.length;i++){
            if (i>index&&nums[i]==nums[i-1]){
                continue;
            }
            list.add(nums[i]);
            subsetsWithDupHelp(res,list,nums,i+1);
            list.remove(list.size()-1);
        }
    }

#93. 复原IP地址

#784. 字母大小写全排列

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值