首页 > 其他分享 >【力扣】数学之美:对角线与N皇后问题的完美结合

【力扣】数学之美:对角线与N皇后问题的完美结合

时间:2024-12-12 19:27:19浏览次数:6  
标签:之美 dig2 dig1 力扣 对角线 皇后 col row

对角线性质分析

在这里插入图片描述

在二维数组中:
主对角线(黑色)满足条件:y - x = n,其中 n 是一个固定值,对于同一条主对角线,n 值相同,不同的主对角线 n 值不同。
副对角线(红色)满足条件:y + x = n,其中 n 也是一个固定值,对于同一条副对角线,n 值相同,不同的副对角线 n 值不同。
利用这个特性,可以高效处理某些涉及二维数组对角线的算法问题,而不需要暴力枚举每个元素。

样例分析

力扣-N皇后
对于N皇后问题,我们就可以通过对角线问题巧妙解决。

N 皇后

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位

在这里插入图片描述

解法

首先n×n的棋盘,需要摆放n个皇后,因为皇后可以左右,所以一定是每行一个,可以上下攻击,肯定也是每列一个。因此这2个情况很容易分析,我们只需要每行进行遍历放一个皇后,即可解决左右攻击问题,用个数组来记录哪列放了皇后,即可解决上下攻击问题。关键问题就是斜线,如果暴力解决,花费的时间成本就比较高,我们通过二维数组的横纵坐标的关系,进行解决。
总结一下流程
解法思路
行列攻击限制:
每行只能放置一个皇后,因此可以逐行遍历,每次在当前行放置一个皇后。
用一个数组 col 记录哪些列已经放置过皇后,避免重复。
主副对角线攻击限制:
主对角线:满足 y - x = n,需要额外对负值偏移进行调整,映射到非负下标。
副对角线:满足 y + x = n,直接映射即可。
使用两个数组 dig1 和 dig2 记录主、副对角线是否被占用。
递归搜索:
从第 0 行开始,逐行尝试每个列的位置,验证是否满足列、主对角线、副对角线的限制。
如果满足,将当前皇后放置,递归进入下一行。
如果某次尝试失败(所有列均不满足),回溯上一行进行其他尝试。

参考代码

class Solution {
public:
    vector<bool> col,dig1,dig2;//记录列,主对角线,副对角线。
    vector<vector<string>> ans;//记录结果
    vector<string> path;//记录棋盘
    int _n = 0;
    vector<vector<string>> solveNQueens(int n) {
        _n = n;
        path.resize(n,string(n,'.'));
        col.resize(n,false);
        dig1.resize(n*2,false);//这里就是需要稍微调整的地方,由于数组下标没有负数,所以我们对y-x=b都加上一个n,这样就保证必然是大于0,能够进行映射。
        dig2.resize(n*2,false);//因为x+y可能是n-1+n-1,所以我们开的是2倍n
        dfs(0);
        return ans;
    }

    void dfs(int row)//这个参数表示我们现在处理的是多少行。
    {
        if(row == _n)//这里表示进行到了最后,相当于放成功了
        {
            ans.push_back(path);
            return ;
        }
        for(int i=0;i<_n;i++)//这里就是找可以放皇后的列
        {
            if(!col[i]&&!dig1[row-i+_n]&&!dig2[row+i]) //行可以放,主对角线可以放(意思就是上几行放的皇后的主对角线没有经过这里),副对角线可以放。
            {
                path[row][i] = 'Q';//这里尝试放皇后
                col[i] = dig1[row-i+_n]=dig2[row+i] = true;
                dfs(row+1);//进行下一行的尝试
                path[row][i] = '.';
                col[i] = dig1[row-i+_n]=dig2[row+i] = false;
            }
        }

    }
};

总结

对角线解题的优势
1、减少搜索空间
通过主、副对角线的特性,可以快速判断某位置是否被斜线占用,无需逐一遍历棋盘,极大提高了算法效率。
2、简单的映射关系
使用简单的数学公式(y - x 和 y + x)将二维棋盘的斜线问题转化为一维数组的访问问题,代码实现直观简洁。

标签:之美,dig2,dig1,力扣,对角线,皇后,col,row
From: https://blog.csdn.net/2201_75443644/article/details/144433449

相关文章

  • 数据结构与算法之美:再谈单链表(进阶)
            Hello大家好!很高兴我们又见面啦!给生活添点passion,开始今天的编程之路!我的博客:<但凡.我的专栏:《数据结构与算法之美》、《编程之路》、《题海拾贝》欢迎点赞,关注! 目录 1、使用C++实现单链表1.1节点的声明1.2节点的初始化1.3头插和尾插1.3.1头插......
  • 1321. 餐馆营业额变化增长 - 力扣(LeetCode)
    1321.餐馆营业额变化增长-力扣(LeetCode)目标输入输入:营业额customer_idnamevisited_onamount1Jhon2019/1/11002Daniel2019/1/21103Jade2019/1/31204Khaled2019/1/41305Winston2019/1/51106Elvis2019/1/61407Anna2019/1/71508Maria2019/1/8809Jaze2019/1/91101Jhon2019......
  • 1341. 电影评分 - 力扣(LeetCode)
    1341.电影评分-力扣(LeetCode)目标输入输入:评分表movie_iduser_idratingcreated_at1132020/1/121242020/2/111322020/2/121412020/1/12152020/2/172222020/2/12322020/3/13132020/2/223242020/2/25输入:用户表user_idname1Daniel2Monica3Maria4James输入:电影表movie......
  • 626. 换座位 - 力扣(LeetCode)
    626.换座位-力扣(LeetCode)目标输入输入:座位表idstudent1Abbot2Doris3Emerson4Green5Jeames输出输出:新座位表idstudent1Doris2Abbot3Green4Emerson5Jeames分析编写解决方案来交换每两个连续的学生的座位号。如果学生的数量是奇数,则最后一个学生的id不交换。按id......
  • 每日力扣打卡93.复原IP地址
    题目:有效IP地址正好由四个整数(每个整数位于0到255之间组成,且不能含有前导0),整数之间用'.'分隔。例如:"0.1.2.201"和"192.168.1.1"是有效IP地址,但是"0.011.255.245"、"192.168.1.312"和"192.168@1.1"是无效IP地址。给定一个只包含数字的字符串s,用以表......
  • 力扣-图论-8【算法学习day.58】
    前言###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程(例如想要掌握基础用法,该刷哪些题?)我的解析也不会做的非常详细,只会提供思路和一些关键点,力扣上的大佬们的题解质量是非常非常高滴!!!习题1.引爆最多的炸弹题目链接:2101.引爆最多的炸弹-力扣(Le......
  • 力扣周赛427
    力扣周赛427......
  • 单词拼写纠正-04-161.力扣 相隔为 1 的编辑距离
    拼写纠正系列NLP中文拼写检测实现思路NLP中文拼写检测纠正算法整理NLP英文拼写算法,如果提升100W倍的性能?NLP中文拼写检测纠正Paperjava实现中英文拼写检查和错误纠正?可我只会写CRUD啊!一个提升英文单词拼写检测性能1000倍的算法?单词拼写纠正-03-leetcodeedit-d......
  • 力扣746 使用最小花费爬楼梯
    问题描述:给你一个整数数组cost,其中cost[i]是从楼梯第i个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。你可以选择从下标为0或下标为1的台阶开始爬楼梯。请你计算并返回达到楼梯顶部的最低花费。示例一:输入:cost=[10,15,20]输出:15......
  • 力扣392.判断子序列
    首先本题有两种解题思路:1.利用双指针遍历s与t,挨个判断s中的元素是否在t中存在,具体方法:i,j 两个指针从0开始,如果s[j]==t[i],则i++,j++;如果不等于则只是i++;继续比较s[j]==t[i];直到i=t.size(),跳出循环,最后判断j是否等于s.size()即可。双指针classSolution{......