力扣热题100 - 经典困难回溯题 - 回溯:N 皇后

题目描述:

题号:51

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

图片

解题思路:

思路一:回溯 + 动态规划

回溯法求解N皇后问题的基本步骤包括:

  1. 定义解空间:将棋盘看作一个N×N的矩阵,每个位置可以放置一个皇后或者为空。

  2. 搜索解空间:以深度优先的方式搜索解空间树。在每一行,尝试在当前行的每一列放置皇后,并检查是否满足条件(即不在同一列、同一斜线上有其他皇后)。

  3. 剪枝:如果在当前位置放置皇后后,无法满足后续行的放置条件,则回溯到上一行,尝试其他列。

  4. 记录解:当成功放置了N个皇后后,记录当前棋盘布局作为一个解。

时间复杂度:O(N!) 

空间复杂度:O(N)

C++


// C++
class Solution {
public:
    vector<vector<string>> solveNQueens(int n) {
        vector<vector<string>> res;
        vector<vector<char>> map(n, vector<char>(n, '.'));
        backTrack(map, 0, n, res);
        return res;
    }

    void backTrack(vector<vector<char>>& map, int row, int n, vector<vector<string>>& res) {
        if (row == n) {
            res.push_back(help(map, n));
            return;
        }

        for (int col = 0; col < n; col++) {
            if (isValid(map, row, col, n)) {
                map[row][col] = 'Q';
                backTrack(map, row + 1, n, res);
                map[row][col] = '.';
            }
        }
    }

    bool isValid(vector<vector<char>>& map, int row, int col, int n) {
        // 判断列
        for (int i = 0; i < row; i++) {
            if (map[i][col] == 'Q') {
                return false;
            }
        }
        // 判断右斜
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (map[i][j] == 'Q') {
                return false;
            }
        }
        // 判断左斜
        for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
            if (map[i][j] == 'Q') {
                return false;
            }
        }
        return true;
    }

    vector<string> help(vector<vector<char>>& map, int n) {
        vector<string> temp;
        for (int i = 0; i < n; i++) {
            string build;
            for (int j = 0; j < n; j++) {
                build += map[i][j];
            }
            temp.push_back(build);
        }
        return temp;
    }
};

go


// go
func solveNQueens(n int) [][]string {
    res := [][]string{}
    m := make([][]byte, n)
    for i := 0; i < n; i++ {
        m[i] = make([]byte, n)
        for j := 0; j < n; j++ {
            m[i][j] = '.'
        }
    }
    backTrack(m, 0, n, &res)
    return res
}

func backTrack(m [][]byte, row, n int, res *[][]string) {
    if row == n {
        *res = append(*res, help(m, n))
        return
    }

    for col := 0; col < n; col++ {
        // 判断能否存放皇后
        if isValid(m, row, col, n) {
            m[row][col] = 'Q'
            backTrack(m, row+1, n, res)
            m[row][col] = '.'
        }
    }
}

func isValid(m [][]byte, row, col, n int) bool {
    // 判断列
    for i := 0; i < row; i++ {
        if m[i][col] == 'Q' {
            return false
        }
    }
    // 判断右斜
    for i, j := row-1, col-1; i >= 0 && j >= 0; i, j = i-1, j-1 {
        if m[i][j] == 'Q' {
            return false
        }
    }
    // 判断左斜
    for i, j := row-1, col+1; i >= 0 && j < n; i, j = i-1, j+1 {
        if m[i][j] == 'Q' {
            return false
        }
    }
    return true
}

func help(m [][]byte, n int) []string {
    temp := []string{}
    for i := 0; i < n; i++ {
        temp = append(temp, string(m[i]))
    }
    return temp
}

目描述: 给你两个版本号 version1 和 version2 ,请你比较它们。 版本号由一个或多个修订号组成,各修订号由一个 '.' 连接。每个修订号由多位数字组成,可能包含前导零。每个版本号至少包含一个字符。修订号从左到右编号,下标从0开始,最左边的修订号下标为0 ,下一个修订号下标为1,以此类推。例如,2.5.33 和 0.1 都是有效的版本号。 比较版本号时,请按从左到右的顺序依次比较它们的修订号。比较修订号时,只需比较忽略任何前导零后的整数值。也就是说,修订号1和修订号001相等。如果版本号没有指定某个下标处的修订号,则该修订号视为0。例如,版本1.0 小于版本1.1,因为它们下标为0的修订号相同,而下标为1的修订号分别为0和1,0 < 1。 返回规则如下: 如果 version1 > version2 返回 1, 如果 version1 < version2 返回 -1, 否则返回 0。 示例 1: 输入:version1 = "1.01", version2 = "1.001" 输出:0 解释:忽略前导零,"01" 和 "001" 都表示相同的整数 "1" 示例 2: 输入:version1 = "1.0", version2 = "1.0.0" 输出:0 解释:version1 没有指定下标为 2 的修订号,即视为 "0" 示例 3: 输入:version1 = "0.1", version2 = "1.1" 输出:-1 解释:version1 中下标为 0 的修订号是 0,version2 中下标为 0 的修订号是 1 。0 < 1,所以 version1 < version2 示例 4: 输入:version1 = "1.0.1", version2 = "1" 输出:1 示例 5: 输入:version1 = "7.5.2.4", version2 = "7.5.3" 输出:-1 提示: 1 <= version1.length, version2.length <= 500 version1 和 version2 仅包含数字和 '.' version1 和 version2 都是 有效版本号
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值