回溯法(深度搜索) 全排列的问题

其实深度搜索和回溯法的区别,在我这里感觉还是很模糊的
总感觉不一样,但是算法的思想是一样的,都是进行不断的尝试,来判断答案的正确性,如果不行的话,我们就回到上一个状态,再进行尝试,如果还是不行,再回去上一个状态…以此类推

最简单的问题就是全排列的问题了,例如leetcode的

46.全排列
给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:

输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

这里使用的leetcode题解的方法,传送门

package Leetcode;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
*@time 2020年2月29日:下午10:45:58
*@author Weirdo
*@version 1.0
**/
public class N46 {

	public static void main(String[] args) {
		N46 n=new N46();
		int[] nums= {1,2,3};
		List<List<Integer>> permute = n.permute(nums);
		System.out.println(permute.toString());
	}
	
	public List<List<Integer>> permute(int[] nums) {

        List<List<Integer>> res = new ArrayList<>();
        int[] visited = new int[nums.length];
        backtrack(res, nums, new ArrayList<Integer>(), visited);
        return res;

    }
    /**
	 * 
	 * @param res 记录结果
	 * @param nums 当前数组
	 * @param tmp 当前结果
	 * @param visited 记录数字被记录的状态
	 */
    private void backtrack(List<List<Integer>> res, int[] nums, ArrayList<Integer> tmp, int[] visited) {
        if (tmp.size() == nums.length) {
        //这里用的是跳出循环的条件
            res.add(new ArrayList<>(tmp));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
        //这里我们先判断当前的数字是否已经被使用,如果已经被使用,跳过
            if (visited[i] == 1) continue;
            //如果没有,我们先使用,再标注为已经使用
            visited[i] = 1;
            tmp.add(nums[i]);
            //添加完了之后,我们进行添加下一个
            backtrack(res, nums, tmp, visited);
            //下一个添加完了,到了这一步,意味着我们到了return条件返回的
            //我们就要去掉这个数字,再去掉标记,再进行尝试
            //这里可能有很多人会懵,只要我们把代码复制到编译器,打开debug模式,走一遍,看看程序是怎么运行的就行了
            visited[i] = 0;
            tmp.remove(tmp.size() - 1);
        }
    }
}

其实之前做蓝桥杯的题目好像做过类似的题目,也是用到的深度搜索
具体见蓝桥杯2016年javaB组

方格填数

如下的10个格子
±-±-±-+
| | | |
±-±-±-±-+
| | | | |
±-±-±-±-+
| | | |
±-±-±-+

(如果显示有问题,也可以参看【图1.jpg】)
在这里插入图片描述

填入0~9的数字。要求:连续的两个数字不能相邻。 (左右、上下、对角都算相邻)

一共有多少种可能的填数方案?

请填写表示方案数目的整数。 注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

这里的深度搜索是有条件的深度搜索

public class T6 {
	//用于记录我们填入的数字
    static int[][] datas = new int[3+2][4+2];
    //判断当前的空位是否已经填入
    static int[] visit = new int[10];
    //记录最后的种数
    static int result = 0;
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        for(int i=0;i<datas.length;i++){
            Arrays.fill(datas[i], -9);
        }
        dfs(1,2);
        System.out.print(result);
    }
    public static void dfs(int dep,int pos){
        if(dep==3&&pos==4){
            result ++;
            return;
        }else{
            if(pos<=4){
                for(int i=0;i<10;i++){
                    if(visit[i]==0&&!hasOther(dep,pos,i)){
                        datas[dep][pos]=i;
                        visit[i]=1;
                        dfs(dep,pos+1);
                        datas[dep][pos]=-9;
                        visit[i]=0;
                    }
                }
            }else{
                dfs(dep+1,1);
            }
        }
    }

    public static boolean hasOther(int dep,int pos,int num){
        boolean result = false;
        if(Math.abs(datas[dep+1][pos]-num)==1||
                Math.abs(datas[dep][pos+1]-num)==1||
                Math.abs(datas[dep+1][pos+1]-num)==1||
                Math.abs(datas[dep-1][pos]-num)==1||
                Math.abs(datas[dep][pos-1]-num)==1||
                Math.abs(datas[dep-1][pos-1]-num)==1||
                Math.abs(datas[dep+1][pos-1]-num)==1||
                Math.abs(datas[dep-1][pos+1]-num)==1
        ){
            result = true;
        }
        return result;
    }

}

还有39阶的问题,这里应该用的是递归,应该也属于回溯法的一种

小明刚刚看完电影《第39级台阶》。离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!
站在台阶前,他突然又想着一个问题:
如果我每一步只能迈上1个或2个台阶。先迈左脚,然后左右交替,最后一步是迈右脚,也就是说一共要走偶数步。
那么,上完39级台阶,有多少种不同的上法呢?
请你利用计算机的优势,帮助小明寻找答案。

public class ThreeNineJie {
    static int count=0;
    /**
     *
     * @param num 剩下的步数
     * @param step 一共走了多少步
     * @return
     */
    static void ways(int num,int step){
        //如果剩下的台阶小于1的话,那么就只能向前走一步
        //如果剩下的台阶为2的话,那么我们有两种走法
        //     1.向前走两步
        //      2.向前走一步,走两次


        //如果剩下的台阶小于零,那么此次的走法不符合要求,退回
        if(num<0) return;
        //如果剩下的台阶等于零,说明递归结束,判断当前的步数是否为偶数
        //如果为偶数,那么此次的走法为正确的走法,种数加一
        if(num==0 && step%2==0){
            count++;
        }
        //走一步的情况
        ways(num-1,step+1);
        //走两步的情况
        ways(num-2,step+1);
    }

    public static void main(String[] args) {
        ways(9,0);
        System.out.println(count);
    }
}

总结:
根据,上面的三道题,我们可以大概的得出一个递归(深度搜索、回溯法)的代码模板

方法体(参数){
 if(跳出循环的条件){
 	如果达到了跳出循环的条件,我们怎么操作,一般都是进行记录并进行返回
 }
 下面就是写,我们没有达到跳出循环的条件,我们怎么操作
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值