第26天|LeetCode332.重新安排行程、LeetCode51.N皇后、LeetCode37. 解数独

1.题目链接:332. 重新安排行程

跳过

2.题目链接:51. N 皇后

题目描述:

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

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

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

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

解法:

                1.首先N皇后问题,想到回溯。那最原始的思考过程应该是这样的,如果n = 3,那么要三层循环,n=4,就4层循环。那么无法控制循环层数,考虑到用回溯。那么树型图中,节点位置其实就是for循环(处理同一行的每一列),而递归就是一层递归处理一行,其实相当于处理的是二维集合。

                2.首先我们创建一个全局变量用来收集所有的符合条件的棋盘,再建立棋盘二维数组,大小为n*n,并将其全部初始化为'.'。

                3.三步曲:

                        ①参数 --- chessBoard , n,row。---即传入初始化的棋盘,长度n和行初始位置

                        ②返回值 --- void 因为最后的结果存到了全局变量里。

                        ③终止条件 --- 即叶子节点位置,当row到了棋盘的最后一行的下一行的时候,说明整个棋盘已经添加完毕了,此时我们要收集结果(即最后的结果集中存储的是多个不同的棋盘即多个二维数组---链表)。

                                                那这样不就把非法的结果也收集了吗?我们会在单层逻辑的时候,如果非法我们就跳过,所以最后到叶子节点收集的时候都是合法的结果。

                        ④单层逻辑 --- for(一行中的每一列){

                                1)处理元素 --- if(row,j,chessBoard){即row,j这个位置是合法的话,我们就将元素赋值

                                                         chessBoard【row】【j】= ‘Q’;

                                2)递归 --- backtracking(chessBoard,n,row+1);

                                3)回溯 --- chessBoard【row】【j】= ‘.’;

                                                }else{

                                                        continue;

                                                        }

                        ⑤写一个函数判断位置是否合法 --- 判断行是否重复,判断列是否重复,判断对角是否重复。

                                1)但这里判断的时候不用判断行是否重复,因为我们在一行中添加元素的时候,一次只添加一个元素,所以不用判断行是否重复。

                                2)判断列的时候,因为我们要向当前行的该位置添加元素,所以呢只需判断当前行之前的列的位置上是否有重复的元素。这个同理在判断对角。

                                3)判断对角的时候,一个是45°一个是135°,即一个是行列都减1,一个是行减1列加1。

                        ⑥而在此题中leetCode给的返回值是链表型的,所以我们要将chessBoard这个二维数组变成链表,其中存的元素类型是字符串(即将二维数组变成一个链表,链表中存储的元素类型为字符串型即可),我们就要再写一个函数用来将二维数组转成链表

                        ⑦最后在主函数中调用递归函数,然后返回结果集。

下面为代码(java):

 

 

3.题目链接:37. 解数独 

题目描述:

                编写一个程序,通过填充空格来解决数独问题。

                数独的解法需 遵循如下规则:

                数字 1-9 在每一行只能出现一次。
                数字 1-9 在每一列只能出现一次。
                数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
                数独部分空格内已填入了数字,空白格用 '.' 表示。

解法:

                1.本题呢相当于一个二维递归的过程,我们要横向纵向遍历棋盘中的每一个元素,然后在棋盘中没有元素的位置,遍历1~9个数字,看其是否是我们要求解的数独。故是个二维递归---即三维的处理过程。

                2.三步曲:

                        ①参数 --- board

                        ②返回值 --- boolean 因为我们求的是一个解,而且题目中说了只有一个合法解,所以呢当我们求到了一个合法的解要立即返回(即当一个树枝是合法解,我们就不去遍历其他树枝了就直接返回了)

                        ③终止条件 --- 此题不用写终止条件,为什么呢?因为当有合法解的时候,整个棋盘会遍历完,直接就跳出循环过程了,下面会有个return。而当出现不合法解的时候,我们会在单层逻辑中直接return,所以不用写终止条件。

                        ④单层逻辑 --- for(行){

                                                for(列){

                               if(board【i】【j】!= ‘.’){continue;} ---即如果遇到非空的直接跳过

                               1)处理元素(处理的是为空的位置) --- for(char k = '1'~9){

                                                           if(isValid(i,j,k,board)) --- 即如果当前位置插入k是合法的话                                                               {

                                                                board【i】【j】= k;

                                2)递归 --- backtracking(board);

                                             boolean result = backtracking(board)

                                             if(result == true){return true;}---即返回值是boolean型的,要承接,如果下一层是true说明找到了对应的数独,直接返回不用进行回溯,就将合法的元素放到了该位置。如果下一层返回是false,那么说明下一层找不到合法的元素了,那么就回到本层向后遍历,即取其它的树枝继续寻找,就用到了回溯

                                3)回溯 --- board【i】【j】= ‘.’

                                                                                }

                                4)return false(即如果某个位置1~9都不符合的话,那就返回false,说明没有合适的数添加)

              }

}

                        ⑤return true;--- 最后整个棋盘都遍历完没有返回false,那就说明棋盘中所有空的位置都添加完成且到了棋盘末尾,到了叶子节点的位置,return true;

                                                这里返回true后会一层层返回到上面那个return true的地方---说明为空的位置都添加完毕了,再一层层向上返回,最后该函数的返回值为true,说明已经得到了一个合法的数独。

                        ⑥isValid 函数要判断行、列重复和九宫格重复,对于九宫格重复,因为其下标为0~8,所以每3个元素的开始位置要统一---可以用(row/3) * 3,和(comlumn/3) *3来表示起始位置,长度都是到+3。这样就划分好了九宫格的范围。然后进行比较是否重复即可。

                        ⑦最后在主函数中调用递归函数即可,因为leetCode中会给输入的board,那么调用递归函数后相当于就将board给填上值了,到时候可能leetCode中会重新输出新的board。

下面为代码(java):

 

 

4.总结:

                ①安排行程问题:二刷再来。

                ②N皇后问题:

                        1)是处理二维数组的过程,我们在节点位置的for处理的是同一行的不同列,而递归则是进行不同行的处理

                        2)要注意终止条件是当row == n的时候才收集棋盘,因为如果 row == n-1的时候就收集的话,那么相当于最后一行还没处理。

                        3)而在写判断某个位置放Q是否合法的函数时候,我们要注意的就是,对角线处理(45°和135°都要处理)。

                        4)在本题中最后的返回结果是链表型的,那么我们收集的二维数组(棋盘)就要转成链表型的,故还要写的转换函数。

                ③解数独问题:

                        1)是处理三维数组的过程,也是二维递归的过程。即我们要分别横向和纵向遍历board,同时在棋盘中位置为'.'的位置我们要判断加入1~9中的哪一个,所以是二维递归的过程。

                        2)那么判断是否合法的函数,就是行列九宫格是否重复。注意的是遇到true就返回,因为本题中我们只求一种合法的数独就可以,同时本题也声明了只有一种合法的结果,所以当递归函数为true的时候,我们就要返回true。

                        3)下面为什么要有回溯过程呢?因为如果递归函数返回了false,那么说明我们要回到当前层从新向后去寻找合法的数字,所以有了回溯过程。

                        4)在for(1~9)外部,如果都找不到,就return false。

                        5)在最开始的两层for循环的外部,return true,因为此时就相当于遍历到了整个树的叶子节点,说明结束了没有false返回,那就返回true,然后再一层一层的跳到上面的return true的地方,再一层层的继续向上返回true,最后整个函数返回true,说明找到合法的数独。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值