N皇后问题——暴力递归+位运算优化版本——java

N皇后问题

返回摆放的方式有几种

public int num(int n){
    if(n<1){
        return 0;
    }
    int[] record=new int[n];//record[i]->i行的皇后放在了第几列
    return process(0,record,n);
}

public int process(int i,int[] record,int n){
    if(i==n){
        return 1;//base case 之前的做法是对的 返回一
    }
    int res=0;
    for(int j=0;j<n;j++){
        //当前i行的皇后,放在j列,会不会和之前(0...i-1)的皇后共行或共斜线
        if(isValid(record,i,j)){
            record[i]=j;
            res+=process(i+1,record,n);
        }
    }
    return res;
}

public boolean isValid(int[] record,int i,int j){
    for(int k=0;k<i;k++){
        if(j==record[k]||Math.abs(record[k]-j)==Math.abs(k-i)){
            return false;
        }
    }
    return true;
}

N皇后问题有更好的思路和算法,但都是很难的

面试掌握程度只需要到这种程度即可

但是可以在这种思路上做一些优化

优化版本:位运算(在时间上优化程度很高)

每一行做的选择都变成了限制信息

斜线:在列的限制加上之后整体移动

image-20220618185659980

image-20220618193108966

//不要超过32皇后问题
public int num(int n){
    if(n<1||n>32){
        return 0;
    }
    int limit=n==32?-1:(1<<n)-1;//例如8皇后问题 它就是左边八个0+右边8个1  -1是32位都是1的状态
    return process(limit,0,0,0);//后几位都是0即第一位皇后没有限制
}

//colLim列的限制,1的位置不能放皇后,0的位置可以
//leftDiaLim左斜线的限制,rightDiaLim右斜线的限制
public int process(int limit,int colLim,int leftDiaLin,int rightDiaLim){
    if(colLim==limit){//base case 列限制信息跟limit一样的时候就是n个皇后都放置完成之后
        return 1;
    }
    int pos=0;
    int mostRightOne=0;
    pos=limit&(~(colLim|leftDiaLim|rightDiaLim));//pos值为1的数就是现在可以放的位置,(colLim|leftDiaLim|rightDiaLim)是现在所有不能放的位置
    int res=0;
    while(pos!=0){
        mostRightOne=pos&(~pos+1);//取到最右边为1的数
        pos=pos-mostRightOne;
        res+=process(limit,colLim|mostRightOne,(leftDiaLim|mostRightOne)<<1,(rightDiaLim|mostRightOne)>>>1);//选取最右边为1的数放置皇后之后,加上下一列的限制条件进行递归
    }
    return res;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值