LintCode 题解丨大厂面试题:N皇后问题

简介: LintCode 题解丨大厂面试题:N皇后问题

n皇后问题是将n个皇后放置在n*n的棋盘上,皇后彼此之间不能相互攻击(任意两个皇后不能位于同一行,同一列,同一斜线)。

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

每个解决方案包含一个明确的n皇后放置布局,其中“Q”和“.”分别表示一个女王和一个空位置。

在线评测地址:

LintCode 领扣

样例1:

输入:1
输出:
[["Q"]]
样例2:

输入:4
输出:
[
// Solution 1
[".Q..",
"...Q",
"Q...",
"..Q."
],
// Solution 2
["..Q.",
"Q...",
"...Q",
".Q.."
]
]
算法:dfs(回溯法)

题目分析

这个问题要求把n个皇后放在一个nXn的棋盘上,使得任何两个皇后都不能相互攻击,即它们不能同行,不能同列,也不能位于同一条对角线上。对于n=1,问题的解很简单,而且很容易看出对于n=2和n=3来说,这个问题是无解的。所以我们考虑4皇后问题,并用回溯法对它求解。

算法思路

因为每个皇后都必须分别占据一行,我们需要做的不过是棋盘上的每个皇后分配一列。
下面我们用4皇后的求解过程来讲解算法思路:
从空棋盘开始,然后把皇后1 放到它所在行的第-一个可能位置上,也就是第一-行第一列。对于皇后2,在经过第-列和第二列的失败尝试之后,我们把它放在第一个可能的位置,就是格子(2, 3),位于第二行第三列的格子。这被证明是一个死胡同,因为皇后3将没有位置可放。所以,该算法进行回溯,把皇后2放在下一个可能位置(2,4)上。这样皇后3就可以放在(3, 2),这被证明是另一个死胡同。该算法然后就回溯到底,把皇后1移到(1,2)。 接着皇后2到(2,4), 皇后3到(3,1), 而皇后4到(4, 3), 这就是该问题的一个解。
整个过程实际上就是一个状态树的遍历过程
下图为状态树
算法:dfs(回溯法)

题目分析

这个问题要求把n个皇后放在一个nXn的棋盘上,使得任何两个皇后都不能相互攻击,即它们不能同行,不能同列,也不能位于同一条对角线上。对于n=1,问题的解很简单,而且很容易看出对于n=2和n=3来说,这个问题是无解的。所以我们考虑4皇后问题,并用回溯法对它求解。

算法思路

因为每个皇后都必须分别占据一行,我们需要做的不过是棋盘上的每个皇后分配一列。
下面我们用4皇后的求解过程来讲解算法思路:
从空棋盘开始,然后把皇后1 放到它所在行的第-一个可能位置上,也就是第一-行第一列。对于皇后2,在经过第-列和第二列的失败尝试之后,我们把它放在第一个可能的位置,就是格子(2, 3),位于第二行第三列的格子。这被证明是一个死胡同,因为皇后3将没有位置可放。所以,该算法进行回溯,把皇后2放在下一个可能位置(2,4)上。这样皇后3就可以放在(3, 2),这被证明是另一个死胡同。该算法然后就回溯到底,把皇后1移到(1,2)。 接着皇后2到(2,4), 皇后3到(3,1), 而皇后4到(4, 3), 这就是该问题的一个解。
整个过程实际上就是一个状态树的遍历过程
下图为状态树

代码思路

按行摆放,在确定一个皇后应该摆的列时,需要检查当前列是否合法,如果合法,则将皇后放置在当前位置,并进行递归,回溯。每行都摆满皇后时,则产生了一种解法,将所有解法收集并返回。
合法性判断方法:当前将要摆放皇后的位置和其他已摆放皇后的位置不能在同一列,且不能在同一条斜线上。这里判断是否在同一条斜线上可以通过两个皇后的位置横坐标之差和纵坐标之差的绝对值是否相等来判断。
复杂度分析

空间复杂度:O(N!)
时间复杂度:O(N!)
放置第一个皇后有 N 种可能,放置两个皇后不超过N(N-2)种可能,放置三个皇后不超过N(N - 2)(N - 4)种可能 ,以此类推。
class Solution {

/**
 * Get all distinct N-Queen solutions
 * @param n: The number of queens
 * @return: All distinct solutions
 * For example, A string '...Q' shows a queen on forth position
 */
List<List<String>> solveNQueens(int n) {
    // result用于存储答案
    List<List<String>> results = new ArrayList<>();
    if (n <= 0) {
        return results;
    }
    
    search(results, new ArrayList<Integer>(), n);
    return results;
}

// search函数为搜索函数,n表示已经放置了n个皇后,cols 表示每个皇后所在的列
private void search(List<List<String>> results, List<Integer> cols, int n) {
    // 若已经放置了n个皇后表示出现了一种解法,绘制后加入答案result
    if (cols.size() == n) {
        results.add(Draw(cols));
        return;
    }
    // 枚举当前皇后放置的列,若不合法则跳过
    for (int colIndex = 0; colIndex < n; colIndex++) {
        if (!isValid(cols, colIndex)) {
            continue;
        }
        // 若合法则递归枚举下一行的皇后
        cols.add(colIndex);
        search(results, cols, n);
        cols.remove(cols.size() - 1);
    }
}

// isValid函数为合法性判断函数
private boolean isValid(List<Integer> cols, int col) {
    int row = cols.size();
    for (int rowIndex = 0; rowIndex < cols.size(); rowIndex++) {
        //若有其他皇后在同一列或同一斜线上则不合法
        if (cols.get(rowIndex) == col) {
            return false;
        }
        if (row + col == rowIndex + cols.get(rowIndex)) {
            return false;
        }
        if (row - col == rowIndex - cols.get(rowIndex)) {
            return false;
        }
    }
    return true;
}
// Draw函数为将 cols 数组转换为答案的绘制函数
private List<String> Draw(List<Integer> cols) {
    List<String> result = new ArrayList<>();
    for (int i = 0; i < cols.size(); i++) {
        StringBuilder sb = new StringBuilder();
        for (int j = 0; j < cols.size(); j++) {
            sb.append(j == cols.get(i) ? 'Q' : '.');
        }
        result.add(sb.toString());
    }
    return result;
}

}
更多题解参考:

九章算法 - 帮助更多中国人找到好工作,硅谷顶尖IT企业工程师实时在线授课为你传授面试技巧

相关文章
|
机器学习/深度学习 弹性计算 TensorFlow
在阿里云上打造强大的模型训练服务
随着人工智能技术的迅猛发展,模型训练服务变得愈发关键。阿里云提供了一系列强大的产品,使得在云端轻松搭建、优化和管理模型训练变得更加便捷。本文将详细介绍如何使用阿里云的相关产品构建高效的模型训练服务。
1190 0
|
机器学习/深度学习 数据采集 自然语言处理
机器学习模型的部署与上线:从训练到实际应用
在机器学习中,模型训练只是整个过程的一部分。将训练好的模型部署到实际应用中,并使其稳定运行,也是非常重要的。本文将介绍机器学习模型的部署与上线过程,包括数据处理、模型选择、部署环境搭建、模型调优等方面。同时,我们也会介绍一些实际应用场景,并分享一些经验和技巧。
|
Cloud Native 网络协议 数据中心
Overlay网络与Underlay网络:深入探索与全面对比
在当今云原生的世界中🌍☁️,网络是构建和维护任何分布式系统的基石💎。了解Overlay网络和Underlay网络及其之间的区别🔍,对于设计高效、可扩展的云原生应用至关重要🚀。本文旨在全面解析Overlay和Underlay网络,揭示它们的工作原理、优缺点,并说明何种情况下应该使用哪一种网络📚。
Overlay网络与Underlay网络:深入探索与全面对比
|
9月前
|
前端开发 数据库 Python
Flask模板高级技巧
本文详细介绍了Flask模板系统的高级技巧,涵盖控制语句(条件判断、循环语句)、宏定义、模板继承、静态文件管理等内容。通过条件语句和循环语句实现动态内容渲染,利用宏定义复用代码块,借助模板继承构建统一布局。同时,文章还讲解了静态文件的组织与引用方法,包括版本控制和CDN资源的使用。最后总结了Flask模板的核心知识点,为构建结构化、易维护的Web应用界面打下坚实基础。
315 19
|
机器学习/深度学习 算法 安全
随机性、熵与随机数生成器:解析伪随机数生成器(PRNG)和真随机数生成器(TRNG)
随机性在密码学、仿真和机器学习等领域中至关重要,本文探讨了随机性、熵的概念以及伪随机数生成器(PRNG)和真随机数生成器(TRNG)的原理和应用。PRNG通过算法生成看似随机的序列,适用于高效需求;TRNG利用物理过程生成真正随机数,适用于高安全需求。文章还讨论了两者的协同应用及其面临的挑战。
1016 5
随机性、熵与随机数生成器:解析伪随机数生成器(PRNG)和真随机数生成器(TRNG)
|
7月前
|
存储 Kubernetes API
在Kubernetes(k8s)环境中无法删除持久卷(PV)和持久卷声明(PVC)的解决方案
最后,应该记住,直接编辑Kubernetes对象是一个破坏性的操作,应该只在必要时、并在充分了解后果的情况下采取,理想情况下在有经验的操作员指导下进行。
533 10
|
前端开发 JavaScript 虚拟化
React 树形组件 Tree View
本文从零开始构建了一个简单的React树形组件,介绍了环境准备、项目创建、基础组件构建等步骤,并探讨了常见问题及解决方案,包括层次嵌套过深、状态管理复杂、事件处理不当和样式问题,帮助读者在实际项目中更好地应用树形组件。
644 4
|
机器学习/深度学习 边缘计算 运维
运维技术深度解析:构建高效、稳定的IT基础设施
【10月更文挑战第22天】运维技术深度解析:构建高效、稳定的IT基础设施
360 0
|
Linux Windows
Centos7配置DHCP(简单模式)
Centos7配置DHCP(简单模式)
1162 0
Centos7配置DHCP(简单模式)
|
搜索推荐
九大排序算法时间复杂度、空间复杂度、稳定性
九大排序算法的时间复杂度、空间复杂度和稳定性,提供了对各种排序方法效率和特性的比较分析。
1435 1