0
点赞
收藏
分享

微信扫一扫

每日一练(day06-秒解皇后问题)

文章目录

警句

自知之明是最难得的知识。——西班牙

题目

中序遍历

这里注意的就是输出,要给到一个列表里面,而不是直接打印即可。

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        inorder(root, res);
        return res;
    }

    public void inorder(TreeNode root, List<Integer> res) {
        //中序遍历,将结果给到 res
        if (root == null) {
            return;
        }
        inorder(root.left, res);
        res.add(root.val);
        inorder(root.right, res);
    }
}

树的深度

这个题目的代码非常简单,但是这里面涉及到递归的思想,而且有点抽象,我估计有很多人但是这个点理解地时候应该是不太顺利的,就像当初的KMP的next数组一样。

关于这个的写法,包括所有的递归都是有模板的。
思路:

代码:

技巧

此外关于什么时候可以使用到递归,其实就是有个特点那就是整体可以拆分局部,可以使用栈的时候也可以使用(递归实际上使用的就是编译器提供的栈)

就拿这个为例子。一个数,输入根节点,如果有左右孩子,左右孩子又有节点,那么这个左右孩子也相当于一个根节点,那么从整体上,我就只需要考虑孩子节点,这样就是总体拆分成了局部,考虑自然就是局部。

回到本题代码,对于一个没有叶子节点的树而言,深度为以,左右孩子为空也就是深度为0。那么现在假设这个树,往上面加入一个节点此时,这个树的根节点就成为了另一棵树的叶子节点(假设为叶子节点),深度为1,执行代码的时候,此时返回结果为1给上一层假设上一层有右孩子,那么同样执行逻辑,假设返回给上一层的结果是2,那么对于这一层的深度不就是 max(left,right)同时加上自己,也就是 H=max(left,right)+1.那么就是三。下面就是假设的那课树
在这里插入图片描述

展开

class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null){
            return 0;
        }
        int left = this.maxDepth(root.left);

        int right = this.maxDepth(root.right);

        return Math.max(left,right)+1;

    }
}
class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null){
            return 0;
        }
        
        return Math.max(this.maxDepth(root.left),this.maxDepth(root.right))+1;

    }
}

较大分组位置

这个没啥好说的。

class Solution {
    public List<List<Integer>> largeGroupPositions(String s) {
        List<List<Integer>> ret = new ArrayList<List<Integer>>();
        int n = s.length();
        int num = 1;
        for (int i = 0; i < n; i++) {
            if (i == n - 1 || s.charAt(i) != s.charAt(i + 1)) {
                if (num >= 3) {
                    ret.add(Arrays.asList(i - num + 1, i));
                }
                num = 1;
            } else {
                num++;
            }
        }
        return ret;
    }
}

反转图像

这个没什么,就是双指针,然后套循环,之后的话,我们在反转,0–>1,1—>0 这里直接进行异或运算就行了。

class Solution {
    public int[][] flipAndInvertImage(int[][] image) {
        int n = image.length;
        for (int i = 0; i < n; i++) {
            int left = 0, right = n - 1;
            while (left < right) {
                if (image[i][left] == image[i][right]) {
                    image[i][left] ^= 1;
                    image[i][right] ^= 1;
                }
                left++;
                right--;
            }
            if (left == right) {
                image[i][left] ^= 1;
            }
        }
        return image;
    }
}

N皇后问题

最后来一个皇后问题吧,这个应该是最经典的问题了。

题目

那么这个 皇后问题其实和我先前做数据结构实训课时候写的迷宫问题的思路其实是类似的,只是我们的规则不一样,先前的迷宫问题使用的DFS的思路,先直接往前走,返现路走不通了,返回,用一个栈来记录走过的路,然后出栈往回走,当然那里用递归也是可以的,不过你也需要用一个栈来存储你走过的路,只是不用循环罢了。
数据结构小设计–(迷宫问题Python版本)

规则

所以明确了思路,我们来说一下这个皇后问题,其实就是,假设是一个 8 x 8 的棋盘,放置八个皇后,让这八个皇后不能相互攻击有多少种放置方法。
在这里插入图片描述
这个就是基本规则,我们要放置让这些皇后不能相互攻击。
所以对于一个 矩阵,我们这样这样表示。Q 表示皇后所在位置,. 表示皇后可以攻击的位置,新的皇后不能在 . 上面放置。例如八皇后问题就是在8 x 8 的棋盘上放8个皇后,如果出现下一个皇后放不下,我们就把当前的位置回溯,就相当于那个迷宫问题的十字路口问题。这个题目的难度其实和迷宫问题的DFS类似,只是这个规则彼迷宫问题复杂一点。

策略

现在我们已经知道了规则,那么接下来就是我们要大概怎么做。我们这边还是使用最经典的DFS来做一下。首先我们按照行优先嘛,在第一行第一列先试着放一下,然后放第二个,第二个肯定是在第二行,并且不可能在第一列。所以伪代码就出来了。


放置(0,棋盘)//从第0行开始放

放置(j,棋盘){
	for(int i=0;i<;i++){
		1.终止条件
		
		2.判断能不能放,能放就放并且往下再放
			放置(j+1,棋盘)//往下放第二个
			复原 //假设当前一轮放完了,我们就需要进行“洗牌”
	}
}

这样一来我们就可以不断地去扫描了

判断条件

之后是我们的判断条件,整理有两个注意点,一个是判断当前点是否可以放置,这个我们已经知道了规则,那么就好办了。

放置判断

  public boolean isOk(char[][] chess,int row,int col){
        //列扫描,对角线扫描(上对角,下对角)
        for(int i=0;i<row;i++){
            if(chess[i][col]=='Q'){
                return false;
            }
        }

        for(int i=row-1,j=col-1;i>=0&j>=0;i--,j--){
            if(chess[i][j]=='Q'){
                return false;
            }
        }

        for(int i=row-1,j=col+1;i>=0&&j< chess.length;i--,j++){
            if(chess[i][j]=='Q'){
                return false;
            }
        }

        return true;

    }

我们是行放置的,所以只需要判断列和对角线即可。

找到解的判断

那么之后如何判断我们找到了解。
我们假设是 4 x 4的棋盘,如果第四个放得下去,那么按照逻辑,就会往下一行放,此时传递的行数就是4(从0开始)那么就说明前面的4x4都放好了,如果第四行就放不下去了,那么最多到3。之后我们将我们的结果放进去。

    public void solveN(char[][] chess,int row){
        if(row == chess.length){
            res.add(this.addsolved(chess));
        }
        for(int j=0;j<chess[0].length;j++){
            if(isOk(chess,row,j)){
                chess[row][j] = 'Q';
                solveN(chess,row+1);
                chess[row][j] = '.';//当前一轮结束了,复位
            }
        }
    }

解题代码

那么之后就能解题目了

class Solution {
    List<List<String>> res = new ArrayList<>();
    public List<List<String>> solveNQueens(int n) {
        char[][] chess = new char[n][n];
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                chess[i][j] = '.';
            }
        }

        solveN(chess,0);

        return res;
    }
    public void solveN(char[][] chess,int row){
        if(row == chess.length){
            res.add(this.addsolved(chess));
        }
        for(int j=0;j<chess[0].length;j++){
            if(isOk(chess,row,j)){
                chess[row][j] = 'Q';
                solveN(chess,row+1);
                chess[row][j] = '.';//当前一轮结束了,复位
            }
        }
    }

    public List<String> addsolved(char[][] chess){
        List<String> res1=new ArrayList<>();
        for(char[] c:chess){
            res1.add(new String(c));
        }
        return res1;
    }

    public boolean isOk(char[][] chess,int row,int col){
        //列扫描,对角线扫描(上对角,下对角)
        for(int i=0;i<row;i++){
            if(chess[i][col]=='Q'){
                return false;
            }
        }

        for(int i=row-1,j=col-1;i>=0&j>=0;i--,j--){
            if(chess[i][j]=='Q'){
                return false;
            }
        }

        for(int i=row-1,j=col+1;i>=0&&j< chess.length;i--,j++){
            if(chess[i][j]=='Q'){
                return false;
            }
        }

        return true;

    }
}

之后还有一个 N皇后问题2,就是叫你返回解的个数,一样的。

举报

相关推荐

0 条评论