leetcode n queens 回溯 backtrack 递归 非递归

231 篇文章 0 订阅

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

Given an integer n, return the number of distinct solutions to the n-queens puzzle.

Example:

Input: 4
Output: 2
Explanation: There are two distinct solutions to the 4-queens puzzle as shown below.
[
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]

 

Python 递归 Version:

class Solution:
    def IsValid(self, posDict, col, row):
        if col in posDict:
            return False
        for hc,hr in posDict.items():
            if abs(hc-col) == abs(hr-row):
                return False
        return True

    def BackTrack(self, posDict, curRow, n):
        if (curRow == n):
            return 1
        res = 0
        for i in range(n):
            if (self.IsValid(posDict, i, curRow)):
                posDict1 = dict(posDict)
                posDict1[i] = curRow
                res += self.BackTrack(posDict1, curRow+1, n)
        return res

    def totalNQueens(self, n):
        res = self.BackTrack({}, 0, n)
        return res

Backtracks are usually written as recursive programs, the general solution is :

 

void backtrack(int t) {
  if (t > n)
    output(x);
  else
    for (int i = f(n, t); i <= g(n,t); ++i) {
      x[t] = h(i);
      if (constraint(t) && bound(t))
        backtrack(t + 1);
    }
}


t stands for the recursive depth, f(n, t) is the starting number of next layer, g(n, t) is the ending number of next layer. Bound is a function for pruning. 

 

But sometimes, non-recursive programs are essential:

 

void iterativeBacktrack() {
  int t = 0;
  while (t > -1) {
    if (t == n && solution(t)) 
      output(x);
    if (f(n, t) + 1 <= g(n, t)){
      f(n, t) = f(n, t) + 1;
      if (constraint(t) && bound(t)) 
        ++t;
      }
    }
    else
      --t;
  }
}

 

Python非递归Version:

class Solution:
    def IsValid(self, posDict, col, row):
        for hr, hc in posDict.items():
            if abs(hc - col) == abs(hr - row) or col == hc:
                return False
        return True

    def BackTrack2(self, posDict, curRow, n):
        res = 0
        rowStatus = [0 for i in range(n)]
        while (curRow > -1):
            if (curRow == n):
                res += 1
                curRow -= 1
            if (rowStatus[curRow] >= -1 and rowStatus[curRow] < n):
                rowStatus[curRow] += 1
                if (self.IsValid(posDict, rowStatus[curRow], curRow)):
                    posDict[curRow] = rowStatus[curRow]
                    curRow +=1
            elif (rowStatus[curRow] == n):
                if curRow in posDict:
                    posDict.pop(curRow)
                rowStatus[curRow] = 0
                curRow -= 1
        return res

    def totalNQueens(self, n):
        res = self.BackTrack2({}, 0, n)
        return res
s = Solution()
print(s.totalNQueens(4))

 

C++ 位运算递归 Version:

class Solution {
 public:
  unsigned int upperlimit;
  int res = 0;
  void dfs(unsigned int row, unsigned int ld, unsigned int rd) {
    if (row == upperlimit) {
      ++res;
      return;
    }
    unsigned int pos = (row | ld | rd) & upperlimit, p = (~pos) & upperlimit, digit;
    while (p) {
      digit = p - (p & (p - 1));
      dfs(row + digit, (ld + digit) << 1, (rd + digit) >> 1);
      p -= digit;
    }
  };
  int totalNQueens(int n) {
    upperlimit = 0;
    for (int i = 0; i < n; ++i)
      upperlimit |= (1 << i);
    res = 0;
    dfs(0, 0, 0);
    return res;  
  }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值