N皇后-回溯法(代码全注释)

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

public class NQueens {
    class  Solution {
        public List<List<String>> solveNQueens(int n) {
            List<List<String>> results = new ArrayList<>();

            solveNQueens(0, n, new ArrayList<>(), results);

            return results;
        }

        private void solveNQueens(int row, int n, List<Integer> colPlacements, List<List<String>> results) {
            if (row == n) {
      /*
        All n queens have been placed in the n rows. We have
        reached the bottom of our recursion. We can now add
        the colPlacements to the results.
      */
                results.add(generateBoardFromPlacements(colPlacements, n));
                return;
            }

    /*
      Try all columns in the current row that we are making
      a choice on.
      The colPlacements list will hold the column we place a
      queen for the i'th row.
      So if I have [ 1, 3, 0, 2 ] that means:
      It is a 4 x 4 board.
      row index 0 has a queen placed in column index 1
      row index 1 has a queen placed in column index 3
      row index 2 has a queen placed in column index 0
      row index 3 has a queen placed in column index 2
    */
            for (int col = 0; col < n; col++) {

      /*
        Record a column placement for this row
      */
                colPlacements.add(col);

      /*
        If it is a valid placement we recurse to work on
        the next row (row + 1) in a recursive call
      */
                if (isValid(colPlacements)) {
                    solveNQueens(row + 1, n, colPlacements, results);
                }

      /*
        We are done exploring with that placement and now we
        will remove it from our colPlacements. We will loop
        back around and try more column placements for this
        row (if there are any left)
      */
                colPlacements.remove(colPlacements.size() - 1);
            }
        }

        /*
          Check if a column placement that we just put in the colPlacements
          list is actually valid to recurse on
        */
        private boolean isValid(List<Integer> colPlacements) {

    /*
      rowWeAreValidatingOn is the row that we just placed a queen on
      and we need to validate the placement
    */
            int rowWeAreValidatingOn = colPlacements.size() - 1;

    /*
      Loop and check our placements in every row previous against
      the placement that we just made
    */
            for (int ithQueenRow = 0; ithQueenRow < rowWeAreValidatingOn; ithQueenRow++) {

      /*
        Get the absolute difference between:
        1.) The column of the already placed queen we are comparing against -> colPlacements.get(ithQueenRow)
        2.) The column of the queen we just placed -> colPlacements.get(rowWeAreValidatingOn)
      */
                int absoluteColumnDistance = Math.abs(colPlacements.get(ithQueenRow) - colPlacements.get(rowWeAreValidatingOn));

      /*
        1.) absoluteColumnDistance == 0
          If the absolute difference in columns is 0 then we placed in a column being
          attacked by the i'th queen.
        2.) absoluteColumnDistance == rowDistance
          If the absolute difference in columns equals the distance in rows from the
          i'th queen we placed, then the queen we just placed is attacked diagonally.
        For Constraint #2 imagine this:
        [
          ". . Q .",  <--- row 0 (Queen 1)
          "Q . . .",  <--- row 1 (Queen 2)
          ". Q . .",  <--- row 2 (Queen 3)
          ". . . ."
        ]
        1.)
          Absolute Column Distance Between Queen 2 & 3 == 1.
          Queen 2 is in col 0, Queen 3 is in col 1. 1 - 0 = 1.
        2.)
          Absolute Row Distance Between Queen 2 & 3 == 1
          Queen 2 is in row 1, Queen 3 is in row 2. 2 - 1 = 1.
      */
                int rowDistance = rowWeAreValidatingOn - ithQueenRow;
                if (absoluteColumnDistance == 0 || absoluteColumnDistance == rowDistance) {
                    return false;
                }
            }

            return true;
        }

        /*
        [
          ".Q..",
          "...Q",
          "Q...",
          "..Q."
          ]
          Generate a board from the list of column placements for each of the n rows.
        */
        private List<String> generateBoardFromPlacements(List<Integer> colPlacements, int n) {
            List<String> board = new ArrayList<>();
            int totalItemsPlaced = colPlacements.size();

            // Materialize a row for each queen that we placed
            for (int row = 0; row < totalItemsPlaced; row++) {

                StringBuilder sb = new StringBuilder();

      /*
        Go through all columns in the row and populate the string.
        If the column has a queen in it place a 'Q', otherwise place
        a '.'
      */
                for (int col = 0; col < n; col++) {
                    if (col == colPlacements.get(row)) {
                        sb.append('Q');
                    } else {
                        sb.append('.');
                    }
                }

                // Add the row to the board
                board.add(sb.toString());
            }

            return board;
        }
    }

    public static void main(String[] args) {
        NQueens.Solution solution = new NQueens().new Solution();
        int n = 4;
        List<List<String>> lists = solution.solveNQueens(n);
        Iterator<List<String>> iterator = lists.iterator();
        while(iterator.hasNext()){
            Iterator<String> iterator1 = iterator.next().iterator();
            while (iterator1.hasNext()){
                System.out.println(iterator1.next());
            }
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值