一些暴力递归题 java左程云

1、N皇后问题:
在N*N的棋盘上要摆N个皇后,要求任何两个皇后不同行、不同列,也不在同一条斜线上

(1)

package learn;

public class NQueens {
    public static int num1(int n){//返回n个皇后有多少中摆法
        if(n<1){
            return 0;
        }
        int[] record=new int[n];//eg.record[1]=2 表示1行皇后放在了第2列
        
        return process(0,record,n);
    }

    public static boolean isValid(int i,int j,int[] record) {
        for(int x=0;x<i;x++){
            if(record[x]==j || Math.abs(i-x)!=Math.abs(j-record[x])){//共斜线,斜率绝对值为1
                return false;
            }
        }
        return true;//都不共列或共斜线
    }
    public static int process(int i,int[] record,int n) {
        if(i==n){
            return 1;//0到n-1皇后已经摆放好
        }
        int res=0;
        for(int j=0;j<n;j++){
            if(isValid(i,j,record)){
                record[i]=j;
                res+=process(i+1,record,n);
            }
        }
        return res;
    }
}

(2)
<=32皇后问题,有改进版:

package learn;

public class NQueens {
    public static int num2(int n){//返回n个皇后有多少中摆法
        if(n<1 || n>32){
            return 0;
        }
        int limit=n==32?-1:(1<<n)-1;

        return process(limit,0,0,0);//0行皇后无任何限制
    }

    public static int process(int limit,int lieLim,int leftLim,int rightLim) {
        //lieLim leftLim rightLim 中 0表示可以放的位置 1表示不可以放的位置
        if(limit==lieLim){
            return 1;
        }
        int pos=(~(lieLim|leftLim|rightLim))&limit;//1表示可放位置 0表示不可放位置
        int mostRightOne=0;
        int res=0;
        while (pos!=0){
            mostRightOne=pos&(~pos+1);
            pos-=mostRightOne;//pos^=mostRightOne;
            res+=process(limit,(lieLim|mostRightOne),(leftLim|mostRightOne)<<1,(rightLim|mostRightOne)>>>1);
        }
        return res;
    }
}

2、打印一个字符串所有子序列,包括空字符串
(可能出现重复)
子序列和子串:
子序列:从字符串中删除一些字符后不更改剩余字符串字符顺序而生成的序列
子串:原序列中必须连续的一段

法一:易理解

package learn;

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

public class Demo {
    public static void function(String str) {
        char[] c=str.toCharArray();
        process(c,0,new ArrayList<Character>());
    }

    public static void process(char[] c, int i, List<Character> res) {
        if(i==c.length){
            print(res);
            return;
        }

        List<Character> l1=copyList(res);//可用clone方法,但要改为ArrayList,因为List中没有clone方法
        l1.add(c[i]);
        process(c,i+1,l1);//要当前字符

        List<Character> l2=copyList(res);
        process(c,i+1,l2);//不要当前字符
    }

    public static void print(List<Character> list) {
        for(int i=0;i<list.size();i++){
            System.out.println(list.get(i));
        }
    }

    public static List<Character> copyList(List<Character> res) {
        List<Character> l=new ArrayList<>();
        for(int i=0;i<res.size();i++){
            l.add(res.get(i));
        }
        return l;
    }

    public static void main(String[] args) {
        String x="abc";
        function(x);
//abc
//ab
//ac
//a
//bc
//b
//c
//  (空字符串)
    }
}

法二:省空间

    public static void function(String str) {
        char[] c=str.toCharArray();
        process(c,0);
    }

    public static void process(char[] c, int i) {
        if(i==c.length){
            print(c);
            return;
        }

        process(c,i+1);//要当前字符
        char temp=c[i];
        c[i]=0;
        process(c,i+1);//不要当前字符
        c[i]=temp;//恢复此层递归进来时(最初)字符串状态
    }

    public static void print(char[] c) {
        for(int i=0;i<c.length;i++){
            if(c[i]!=0) {
                System.out.print(c[i]);
            }
        }
        System.out.print(" ");
    }


    public static void main(String[] args) {
        String x="abc";
        function(x);
        //abc ab ac a bc b c (空字符串)
    }

3、打印一个字符串的全部排列

    public static ArrayList<String> function(String str) {
        ArrayList<String> res=new ArrayList<>();
        if(str==null || str.length()==0){
            return res;
        }
        char[] c=str.toCharArray();
        process(c,0,res);
        return res;
    }

    public static void process(char[] c, int i,ArrayList<String> res) {
        if(i==c.length){
            res.add(String.valueOf(c));
            return;
        }

        boolean[] visit=new boolean[26];//用来标记26个英文字母是否在字符串中出现过 避免交换两个不同位置的相同字母造成排列重复
        //boolean 数组默认值为false
        for(int j=i;j<c.length;j++){//位置i 第i个字符和其以后的字符都可以选择占据此位
            if(!visit[c[j]-'a']) {
                visit[c[j]-'a']=true;
                swap(c, i, j);
                process(c, i + 1, res);
                swap(c, i, j);//交换回来
            }
        }
    }

    public static void swap(char[] c,int i,int j) {
        char x;
        x=c[i];
        c[i]=c[j];
        c[j]=x;
    }

    public static void print(ArrayList<String> a) {
        for(int i=0;i<a.size();i++){
            System.out.println(a.get(i));
        }
    }


    public static void main(String[] args) {
        String x="abbc";
        ArrayList<String> a=function(x);
        print(a);
        /*
        abbc
        abcb
        acbb
        babc
        bacb
        bbac
        bbca
        bcba
        bcab
        cbba
        cbab
        cabb
         */
    }

4、给纸牌,A、B依次拿走纸牌,每次只能拿最左/最右纸牌,返回最后获胜者的分数,玩家A、B都绝顶聪明

    public static int win(int[] arr) {
        if(arr==null || arr.length==0){
            return 0;
        }

        return Math.max(f(arr,0,arr.length-1),s(arr,0,arr.length-1));//f:先手 s:后手
    }

    public static int f(int[] arr,int i,int j) {
        if(i==j){
            return arr[i];//若只剩一张牌,必定是被先手拿走
        }

        return Math.max(arr[i]+s(arr,i+1,j),arr[j]+s(arr,i,j-1));//为先手时,才可取牌(+arr[i]/arr[j]) A、B轮流做先手
    }

    public static int s(int[] arr,int i,int j) {
        if(i==j){
            return 0;
        }
        return Math.min(f(arr,i+1,j),f(arr,i,j-1));//后手希望先手取的少
    }

    public static void main(String[] args) {
        int[] num={1,2,100,4};
        System.out.println(win(num));
        //101
    }

5、给定一个栈,逆序该栈,不申请额外数据结构,只能用递归函数

    public static int f(Stack<Integer> stack){//移出栈底元素并返回
        int res=stack.pop();
        if(stack.isEmpty()){
            return res;//栈底元素
        }else {
            int last = f(stack);
            stack.push(res);
            return last;
        }
    }
    public static void reverse(Stack<Integer> stack){
        if(stack.isEmpty()){
            return;
        }
        int i=f(stack);
        reverse(stack);
        stack.push(i);
    }
    /*
    public static int f(Stack<Integer> stack){
        int num;
        if(stack.size()==1){
            num=stack.pop();
            return num;
        }
        int n=stack.pop();
        num=f(stack);
        stack.push(n);
        return num;
    }
    */

6、规定1和A对应,2和B对应…
那么一个数字字符串比如"111",可以转化为"AAA"、“KA”、“AK”
给定一个只有数字字符组成的字符串str,返回有多少种转化结果

    public static void function(String str) {
        char[] c=str.toCharArray();
        process(c,0);
    }
    
    //0-i-1位置如何转化已做好决定
    //现考虑i及其之后有多少种转化结果
    public static int process(char[] str,int i){
        if(i==str.length){
            return 1;
        }
        if (str[i] == '0') {
            return 0;
        }
        
        if(str[i]=='1'){
            int res=process(str,i+1);//自己一组 后续有多少中可能
            if(i+1<str.length){
                res+=process(str,i+2);//自己和后面一个字符一组 后续有多少中可能
            }
            return res;
        }
        
        if(str[i]=='2'){
            int res=process(str,i+1);
            if(i+1<str.length && str[i+1]<'7'){//不超过26
                res+=process(str,i+2);
            }
            return res;
        }
        return process(str,i+1);//其余3-9 只能自己一组 没有别的可能
    }

7、给定两个长度都为N的数组weights和values,给一个整数bag,表示一个载重bag的袋子,所装物品不能超过这个重量,返回你能装下的最多的价值是多少?

左老师第一个方案有问题:
我觉得大概是超重时,返回的0加上当前的value,还是可能成为最大值,而未被覆盖,然后这个错误的值被逐层返回了
如果返回无穷小应该就行,加上无穷小的话就很小,会被覆盖,错误值不会一路返回

而第二种方案返回0,没有加上任何别的值,必能被其余大于0值覆盖,不会是那个max,除非一个都装不进去

package learn;

public class Demo {

    public static int maxValue(int[] weights, int[] values, int bag) {
        return process(weights, values, 0, 0, 0, bag);
    }

    //每个货物两种选择,装入或不装入,取所有情况中结果最大的
    //i...货物自由选择 0-i-1已经定了选不选择
    public static int process(int[] weights, int[] values, int i, int alreadyWeight, int alreadyValue, int bag) {
        if (alreadyWeight > bag) {
            return 0;//该方案废除 是不可能的方案
        }
        if (i == values.length) {//每个货物都已经做了决定 成为一种可行的方案
            return alreadyValue;
        }
        return Math.max(process(weights, values, i + 1, alreadyWeight + weights[i], alreadyValue + values[i], bag),
                process(weights, values, i + 1, alreadyWeight, alreadyValue, bag));
    }

    public static void main(String[] args) {
        int[] w = {3, 2, 4, 7, 3, 1, 7};
        int[] v = {5, 6, 3, 19, 12, 4, 2};
        int bag = 15;
        System.out.println(maxValue(w, v, bag));//42

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值