Leetcode.52. N Queen Problem

51.n-queens

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

Insert picture description here
Given an integer n, return all distinct solutions to the n-queens puzzle.

Each solution contains a distinct board configuration of the n-queens’ placement, where ‘Q’ and ‘.’ both indicate a queen and an empty space respectively.

Example:

Input: 4
Output: [
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above.

Code

Set-based backtracking

package n_queens;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击
 * 注意,1.每一行要都放一个皇后,棋盘是方形的
 *
 */
public class Solution1 {
    
    
	
    public List<List<String>> solveNQueens(int n) {
    
    
        List<List<String>> solutions = new ArrayList<List<String>>();
        int[] queens = new int[n];//index表示第几行,index对应的数字表示第几列
        Arrays.fill(queens, -1);//填充为-1
        Set<Integer> columns = new HashSet<Integer>();//列集合
        Set<Integer> diagonals1 = new HashSet<Integer>();//斜线为从左上到右下方向
        Set<Integer> diagonals2 = new HashSet<Integer>();//斜线为从右上到左下方向
        backtrack(solutions, queens, n, 0, columns, diagonals1, diagonals2);
        return solutions;
    }

    /**
     * 基于集合的回溯,通过三个集合来判断是否包含
     * @param solutions 结果集
     * @param queens 填充数组,数组长度为n,下标表示行,元素值表示当前行的位置.有点一维数组当二维数组用的意思
     * @param n		n个皇后
     * @param row	行
     * @param columns 列集合
     * @param diagonals1 斜线为从左上到右下方向
     * @param diagonals2 斜线为从右上到左下方向
     */
    public void backtrack(List<List<String>> solutions, int[] queens, int n, int row, 
        Set<Integer> columns, Set<Integer> diagonals1, Set<Integer> diagonals2) {
    
    
        if (row == n) {
    
    
            List<String> board = generateBoard(queens, n);//返回字符串
            solutions.add(board);
        } else {
    
    
            for (int i = 0; i < n; i++) {
    
    //遍历当行行
                if (columns.contains(i)) {
    
    
                    continue;
                }
                //重点
                int diagonal1 = row - i;//方向一的斜线为从左上到右下方向,同一条斜线上的每个位置满足行下标与列下标之差相等
                if (diagonals1.contains(diagonal1)) {
    
    
                    continue;
                }
                //重点
                int diagonal2 = row + i;//方向二的斜线为从右上到左下方向,同一条斜线上的每个位置满足行下标与列下标之和相等
                if (diagonals2.contains(diagonal2)) {
    
    
                    continue;
                }
                queens[row] = i;
                columns.add(i);//将当前列占用
                diagonals1.add(diagonal1);//将当前斜线占用
                diagonals2.add(diagonal2);//将当前斜线占用
                //进入下一行
                backtrack(solutions, queens, n, row + 1, columns, diagonals1, diagonals2);
                //回溯
                queens[row] = -1;
                columns.remove(i);
                diagonals1.remove(diagonal1);
                diagonals2.remove(diagonal2);
            }
        }
    }

    /**数组转字符串*/
    public List<String> generateBoard(int[] queens, int n) {
    
    
        List<String> board = new ArrayList<String>();
        for (int i = 0; i < n; i++) {
    
    
            char[] row = new char[n];
            Arrays.fill(row, '.');
            row[queens[i]] = 'Q';
            board.add(new String(row));
        }
        return board;
    }
    
    public static void main(String[] args) {
    
    
    	//测试4*4的棋盘
		List<List<String>> list = new Solution1().solveNQueens(4);
		list.forEach(list2->{
    
    
			list2.forEach(System.out::println);
			System.out.println("=====");
		});
	}
}

Method 2: Backtracking based on bit operations (not recommended)

Insert picture description here
We can use arrays instead of collections.
After finishing line 0, line 1, how to put line 2 there.
We use 0 to represent the position where the queen can be placed, and 1 to represent the position where the queen cannot be placed.
Obviously, the situation is as follows.

列          , 从左上到右下方向  ,从右上到左下方向
0001 01000011 00000000 1001

Picture from Leetcode official

class Solution {
    
    
    public List<List<String>> solveNQueens(int n) {
    
    
        int[] queens = new int[n];
        Arrays.fill(queens, -1);
        List<List<String>> solutions = new ArrayList<List<String>>();
        solve(solutions, queens, n, 0, 0, 0, 0);
        return solutions;
    }

    public void solve(List<List<String>> solutions, int[] queens, int n, int row, int columns, int diagonals1, int diagonals2) {
    
    
        if (row == n) {
    
    
            List<String> board = generateBoard(queens, n);
            solutions.add(board);
        } else {
    
    
            int availablePositions = ((1 << n) - 1) & (~(columns | diagonals1 | diagonals2));
            while (availablePositions != 0) {
    
    
                int position = availablePositions & (-availablePositions);
                availablePositions = availablePositions & (availablePositions - 1);
                int column = Integer.bitCount(position - 1);
                queens[row] = column;
                solve(solutions, queens, n, row + 1, columns | position, (diagonals1 | position) << 1, (diagonals2 | position) >> 1);
                queens[row] = -1;
            }
        }
    }

    public List<String> generateBoard(int[] queens, int n) {
    
    
        List<String> board = new ArrayList<String>();
        for (int i = 0; i < n; i++) {
    
    
            char[] row = new char[n];
            Arrays.fill(row, '.');
            row[queens[i]] = 'Q';
            board.add(new String(row));
        }
        return board;
    }
}

52.n-queens-ii

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

Insert picture description here

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.."]
]

java code

class Solution {
    
    
    public int totalNQueens(int n) {
    
    
        Set<Integer> columns = new HashSet<Integer>();
        Set<Integer> diagonals1 = new HashSet<Integer>();
        Set<Integer> diagonals2 = new HashSet<Integer>();
        return backtrack(n, 0, columns, diagonals1, diagonals2);
    }

    public int backtrack(int n, int row, Set<Integer> columns, Set<Integer> diagonals1, Set<Integer> diagonals2) {
    
    
        if (row == n) {
    
    
            return 1;
        } else {
    
    
            int count = 0;
            for (int i = 0; i < n; i++) {
    
    
                if (columns.contains(i)) {
    
    
                    continue;
                }
                int diagonal1 = row - i;
                if (diagonals1.contains(diagonal1)) {
    
    
                    continue;
                }
                int diagonal2 = row + i;
                if (diagonals2.contains(diagonal2)) {
    
    
                    continue;
                }
                columns.add(i);
                diagonals1.add(diagonal1);
                diagonals2.add(diagonal2);
                count += backtrack(n, row + 1, columns, diagonals1, diagonals2);
                columns.remove(i);
                diagonals1.remove(diagonal1);
                diagonals2.remove(diagonal2);
            }
            return count;
        }
    }
}

or

class Solution {
    
    
    public int totalNQueens(int n) {
    
    
        return solve(n, 0, 0, 0, 0);
    }

    public int solve(int n, int row, int columns, int diagonals1, int diagonals2) {
    
    
        if (row == n) {
    
    
            return 1;
        } else {
    
    
            int count = 0;
            int availablePositions = ((1 << n) - 1) & (~(columns | diagonals1 | diagonals2));
            while (availablePositions != 0) {
    
    
                int position = availablePositions & (-availablePositions);
                availablePositions = availablePositions & (availablePositions - 1);
                count += solve(n, row + 1, 
                columns | position, 
                (diagonals1 | position) << 1, 
                (diagonals2 | position) >> 1);
            }
            return count;
        }
    }
}

or

class Solution {
    
    
    public int totalNQueens(int n) {
    
    
                int[] rs = new int[]{
    
    0,1,0,0,2,10,4,40,92,352,724,2680};
        return rs[n];
    }
}

Guess you like

Origin blog.csdn.net/e891377/article/details/109129107