N queens-Kotlin solution

LeetCode 51. N Queens :
Brief explanation: Give you an N×N board, let you place N queens so that they cannot attack each other.
PS: Queens can attack any unit in the same row, column, top left, bottom right, top right, bottom four directions.

The Kotlin solution is as follows, first upload the code:

class Solution {
    /**
     * 无重叠子问题,只能用回溯法,暴力穷举
     * 指数级时间复杂度
     */
    private var result: MutableList<MutableList<String>> = mutableListOf()
    fun solveNQueens(n: Int): MutableList<MutableList<String>> {
        var board: MutableList<MutableList<String>> = MutableList(n) { MutableList(n) { "." } }
        backtrack(board, 0)
        return result;
    }

    /**
     * 回溯函数
     */
    private fun backtrack(board: MutableList<MutableList<String>>, row: Int) {
        //满足条件,每一行都放置了皇后、记录结果
        if (row == board.size) {
            result.add(helper(board))
            return
        }

        //在当前行的每一列都可以放置皇后
        for (column: Int in 0 until board.size) {
            //排除可以相互攻击的格子
            if (!isValid(board, row, column)) {
                continue
            }
            //做选择
            board[row][column] = "Q"
            //进入下一行放皇后
            backtrack(board, row + 1)
            //撤销选择
            board[row][column] = "."
        }

    }

    /**
     * 判断位置(row , column)是否可以放置皇后
     */
    private fun isValid(board: MutableList<MutableList<String>>, row: Int, column: Int): Boolean {

        //检查左上方
        var i = row - 1
        var j = column - 1

        while (i >= 0 && j >= 0) {
            if (board[i][j] == "Q") {
                return false
            }
            i--
            j--
        }

        //检查正上方
        i = row - 1
        j = column
        while (i >= 0) {
            if (board[i][j] == "Q") {
                return false
            }
            i--
        }

        //检查右上方
        i = row - 1
        j = column + 1
        while (i >= 0 && j < board.size) {
            if (board[i][j] == "Q") {
                return false
            }
            i--
            j++
        }

        return true
    }

    /**
     * 数据结构转换函数,
     * 将MutableList<MutableList<String>>)转换为 MutableList<String>
     */
    private inline fun helper(board: MutableList<MutableList<String>>): MutableList<String> {
        var tempList: MutableList<String> = mutableListOf()
        var strB = StringBuilder()
        for (i: Int in 0 until board.size) {

            for (j: Int in 0 until board[i].size) {
                strB.append(board[i][j])
            }
            tempList.add(strB.toString())
            strB.clear()
        }
        return tempList
    }

Take n=2, that is, a 2*2 chessboard as an example.

 

Each level of the decision tree represents each row on the board; the choice each node can make is to place a queen in any column of that row.

Understand the possible questions that may arise from the algorithm:

Question 1: According to the description of the N queens problem, why not check the lower left corner, lower right corner and the lower grid, but only check the upper left corner, upper right corner and upper grid?

Because the queen is placed line by line from top to bottom, there is no need to check the bottom left, bottom right, and right bottom (the queen has not been placed yet); because only one queen is placed in a line, there is no need to check each line. That is, in the end, only the top, upper left, and upper right directions are checked.

The backtracking algorithm is a multi-fork tree traversal problem, the N queens problem, there are no overlapping sub-problems, and the backtracking algorithm can only be exhaustive.
The violent solution phase of dynamic programming is the backtracking algorithm. It’s just that some problems have the nature of overlapping sub-problems, which can be optimized with dp table or memo, and the recursive tree can be greatly pruned, which becomes dynamic programming.

The time complexity of the N Queens problem is very high and exponential, and the worst time complexity is O(N^(N+1)).

Question 2: What should I do if the time complexity is too high?

The complexity of finding all solutions is too high, such as the algorithm for solving Sudoku, as long as one solution is found.

    /**
     * 回溯函数
     */
    private fun backtrack(board: MutableList<MutableList<String>>, row: Int): Boolean {
        //满足条件,每一行都放置了皇后、记录结果
        if (row == board.size) {
            result.add(helper(board))
           //只要找到一个答案,就返回
            return true
        }

        //在当前行的每一列都可以放置皇后
        for (column: Int in 0 until board.size) {
            //排除可以相互攻击的格子
            if (!isValid(board, row, column)) {
                continue
            }
            //做选择
            board[row][column] = "Q"
            //进入下一行放皇后
            backtrack(board, row + 1)
            //撤销选择
            board[row][column] = "."
        }
        return false
    }

As long as an answer is found, the subsequent recursive exhaustion of the for loop will be blocked.

Guess you like

Origin blog.csdn.net/lrxb_123/article/details/123904308