递归回溯

递归与回溯

方法自己调用自己

1)执行方法时创建新栈空间

2)方法的局部变量独立

3)方法使用引用类型变量时,共享此数据

4)递归边界

5)方法全部执行完返回

1.n皇后问题

/**
 * 8皇后问题
 */
public class Queens {
    int max = 8;
    int sum = 0;
    //保存第 i 个皇后的列号
    int[] array = new int[max];

    public static void main(String[] args) {
        Queens queens = new Queens();
        queens.check(0);
        queens.print();
    }

    //放置皇后
    private void check(int n) {
        if (n == max) {
            sum++;
            return;
        }
        //依次放置
        for (int i = 0; i < max; i++) {
            array[n] = i;
            if (judge(n)) {
                check(n + 1);
            }
        }
    }

    //检测是否冲突
    private boolean judge(int n) {
        for (int i = 0; i < n; i++) {
            //位于同一列/同斜线
            if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) {
                return false;
            }
        }
        return true;
    }

    //输出
    private void print() {
//        for (int i = 0; i < array.length; i++) {
//            System.out.println(array[i] + " ");
//        }
        System.out.println(sum);
    }
}

2.回溯

2.1 生成括号

/**
* 给出n对括号,请编写一个函数来生成所有的由n对括号组成的合法组合
*/
public class Solution {
    /**
     * 
     * @param n int整型 
     * @return string字符串ArrayList
     */
    ArrayList<String> ans = new ArrayList<String>();
    public ArrayList<String> generateParenthesis (int n) {        
        gen("",0,0,n);
        return ans;
    }
    //确定分支和边界条件
    private void gen(String s,int i,int j,int n){
        if(j == n){
            ans.add(s);
        }
        if(i < n){
            gen(s+"(",i+1,j,n);
        }
        if(j < i){
            gen(s+")",i,j+1,n);
        }
    }
}

2.2 字符串转化成IP地址

/**
* 现在有一个只包含数字的字符串,将该字符串转化成IP地址的形式,返回所有可能的情况。
*/
public class Solution {
    /**
     * 
     * @param s string字符串 
     * @return string字符串ArrayList
     */
    ArrayList<String> ans = new ArrayList<String>();
    public ArrayList<String> restoreIpAddresses (String s) {        
        gen("",0,0,0,s);
        return ans;
    }
    private void gen(String ip,int left,int right,int n,String s){
        //分析边界条件
        if(n > 4) return;
        String t = "";
        if(n > 0){
            t = s.substring(left,right);
            int num = Integer.parseInt(t);
            if(num < 0 || num > 255 || t.length() > Integer.toString(num).length()) return;
            ip = ip+"."+t;
        }
        //成功返回
        if(n == 4 && right == s.length()){           
            ans.add(ip.substring(1));
            return;
        }
        //分支递归
        if(right+1 <= s.length()) gen(ip,right,right+1,n+1,s);
        if(right+2 <= s.length()) gen(ip,right,right+2,n+1,s);
        if(right+3 <= s.length()) gen(ip,right,right+3,n+1,s);
    }
}

2.3 n中取k个组合(剪枝优化)

/**
* 给出两个整数n和k,返回从1到n中取k个数字的所有可能的组合
*/
public class Solution {
    ArrayList<ArrayList<Integer>> ans;   
    public void check(int n,int k,int start,ArrayList<Integer> com){
        //返回
        if(k == com.size()){
            ans.add(new ArrayList<Integer>(com));
            return;
        }
        //减少不符合的情况
        if(start > n) return;
        //com当中最终应该有k个元素,当前元素为com.size() + 1,那么我们要为下次回溯留下足够多的数
        int len = k - 1 - com.size();
        for(int i = start;i <= n - len;i++){
            com.add(i);
            check(n,k,i+1,com);
            com.remove(com.size()-1);
        }
    }
       
    public ArrayList<ArrayList<Integer>> combine (int n, int k) {
        //基本构造如套路      
        ans = new ArrayList<ArrayList<Integer>>();
        if( n <= 0 || k <= 0 || n < k) return ans;
        
        check(n,k,1,new ArrayList<Integer>());
        return ans;
    }
}
posted @ 2021-04-04 14:42  FremontUltimate  阅读(111)  评论(0)    收藏  举报