From d52c652374a755641bfc2fcd3973813c64ee1e61 Mon Sep 17 00:00:00 2001 From: "huangge1199@hotmail.com" Date: Wed, 21 Apr 2021 08:42:23 +0800 Subject: [PATCH] =?UTF-8?q?37:=E8=A7=A3=E6=95=B0=E7=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/leetcode/editor/cn/SudokuSolver.java | 137 +++ .../java/leetcode/editor/cn/SudokuSolver.md | 41 + .../java/leetcode/editor/cn/ValidSudoku.java | 18 +- .../hui-su-fa-jie-shu-du-by-i_use_python.md | 82 ++ .../cn/doc/jie-shu-du-by-leetcode-solution.md | 914 ++++++++++++++++++ .../java/leetcode/editor/cn/doc/p__&_.png | Bin 0 -> 226 bytes .../editor/cn/doc/p__0_leq_x_leq_2_.png | Bin 0 -> 511 bytes .../editor/cn/doc/p__0_leq_y_leq_2_.png | Bin 0 -> 539 bytes .../leetcode/editor/cn/doc/p__9_times_9_.png | Bin 0 -> 325 bytes .../editor/cn/doc/p__O_9^{9_times_9}__.png | Bin 0 -> 660 bytes .../p___111111111__2_=__text{1FF}__{16}_.png | Bin 0 -> 789 bytes ...lfloor_i_3_rfloor,_lfloor_j_3_rfloor__.png | Bin 0 -> 781 bytes .../leetcode/editor/cn/doc/p__b_~&~__-b__.png | Bin 0 -> 556 bytes .../editor/cn/doc/p__lfloor_u_rfloor_.png | Bin 0 -> 262 bytes .../java/leetcode/editor/cn/doc/p__sim_.png | Bin 0 -> 151 bytes .../leetcode/editor/cn/doc/p__sim_b_+_1_.png | Bin 0 -> 367 bytes .../java/leetcode/editor/cn/doc/p__sim_b_.png | Bin 0 -> 259 bytes ...r_i_3_rfloor__lfloor_j_3_rfloor__x-1__.png | Bin 0 -> 1233 bytes .../editor/cn/doc/p__textit{block}_x__y__.png | Bin 0 -> 769 bytes .../editor/cn/doc/p__textit{column}_j__.png | Bin 0 -> 694 bytes .../cn/doc/p__textit{column}_j__x-1__.png | Bin 0 -> 899 bytes .../p__textit{line}_2__3__=_text{True}_.png | Bin 0 -> 925 bytes .../editor/cn/doc/p__textit{line}_i__.png | Bin 0 -> 487 bytes .../cn/doc/p__textit{line}_i__x-1__.png | Bin 0 -> 703 bytes .../editor/cn/doc/p__text{False}_.png | Bin 0 -> 441 bytes .../leetcode/editor/cn/doc/p__text{True}_.png | Bin 0 -> 363 bytes .../java/leetcode/editor/cn/doc/p__wedge_.png | Bin 0 -> 176 bytes 27 files changed, 1177 insertions(+), 15 deletions(-) create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/SudokuSolver.java create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/SudokuSolver.md create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/hui-su-fa-jie-shu-du-by-i_use_python.md create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/jie-shu-du-by-leetcode-solution.md create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__&_.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__0_leq_x_leq_2_.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__0_leq_y_leq_2_.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__9_times_9_.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__O_9^{9_times_9}__.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p___111111111__2_=__text{1FF}__{16}_.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p___lfloor_i_3_rfloor,_lfloor_j_3_rfloor__.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__b_~&~__-b__.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__lfloor_u_rfloor_.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__sim_.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__sim_b_+_1_.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__sim_b_.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{block}_lfloor_i_3_rfloor__lfloor_j_3_rfloor__x-1__.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{block}_x__y__.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{column}_j__.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{column}_j__x-1__.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{line}_2__3__=_text{True}_.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{line}_i__.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{line}_i__x-1__.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__text{False}_.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__text{True}_.png create mode 100644 LeetCode/src/main/java/leetcode/editor/cn/doc/p__wedge_.png diff --git a/LeetCode/src/main/java/leetcode/editor/cn/SudokuSolver.java b/LeetCode/src/main/java/leetcode/editor/cn/SudokuSolver.java new file mode 100644 index 0000000..db091a3 --- /dev/null +++ b/LeetCode/src/main/java/leetcode/editor/cn/SudokuSolver.java @@ -0,0 +1,137 @@ +//编写一个程序,通过填充空格来解决数独问题。 +// +// 数独的解法需 遵循如下规则: +// +// +// 数字 1-9 在每一行只能出现一次。 +// 数字 1-9 在每一列只能出现一次。 +// 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图) +// +// +// 数独部分空格内已填入了数字,空白格用 '.' 表示。 +// +// +// +// +// +// +// 示例: +// +// +//输入:board = [["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5","." +//,".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".","." +//,"3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6" +//],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[" +//.",".",".",".","8",".",".","7","9"]] +//输出:[["5","3","4","6","7","8","9","1","2"],["6","7","2","1","9","5","3","4","8" +//],["1","9","8","3","4","2","5","6","7"],["8","5","9","7","6","1","4","2","3"],[" +//4","2","6","8","5","3","7","9","1"],["7","1","3","9","2","4","8","5","6"],["9"," +//6","1","5","3","7","2","8","4"],["2","8","7","4","1","9","6","3","5"],["3","4"," +//5","2","8","6","1","7","9"]] +//解释:输入的数独如上图所示,唯一有效的解决方案如下所示: +// +// +// +// +// +// +// 提示: +// +// +// board.length == 9 +// board[i].length == 9 +// board[i][j] 是一位数字或者 '.' +// 题目数据 保证 输入数独仅有一个解 +// +// +// +// +// Related Topics 哈希表 回溯算法 +// 👍 819 👎 0 + +package leetcode.editor.cn; + +import java.util.*; + +//37:解数独 +public class SudokuSolver { + public static void main(String[] args) { + //测试代码 + Solution solution = new SudokuSolver().new Solution(); + } + + //力扣代码 + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + public void solveSudoku(char[][] board) { + List[][] boards = new ArrayList[9][9]; + List[] rows = new ArrayList[9]; + List[] columns = new ArrayList[9]; + List[] others = new ArrayList[9]; + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + boards[i][j] = new ArrayList<>(); + } + rows[i] = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); + columns[i] = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); + others[i] = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); + } + List> left = new ArrayList<>(); + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + char ch = board[i][j]; + if (ch == '.') { + left.add(Arrays.asList(i, j)); + continue; + } + rows[i].remove(ch - '0'); + columns[j].remove(ch - '0'); + int otherIndex = (i / 3) * 3 + j / 3; + others[otherIndex].remove(ch - '0'); + } + } + while (left.size() > 0) { + for (int i = 0; i < left.size(); i++) { + List list = left.get(i); + int r = 0, c = 0, o = 0; + int x = list.get(0),y = list.get(1); + List tempR = rows[x]; + List tempC = columns[y]; + int otherIndex = (x / 3) * 3 + y / 3; + List tempO = others[otherIndex]; + while (r < tempR.size() && c < tempC.size() && o < tempO.size()) { + if(tempR.get(r).equals(tempC.get(c)) && tempC.get(c).equals(tempO.get(o))){ + boards[x][y].add(tempC.get(c)); + } + while (tempR.get(r)编写一个程序,通过填充空格来解决数独问题。

+ +

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

+ +
    +
  1. 数字 1-9 在每一行只能出现一次。
  2. +
  3. 数字 1-9 在每一列只能出现一次。
  4. +
  5. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
  6. +
+ +

数独部分空格内已填入了数字,空白格用 '.' 表示。

+ +

 

+ +
+
+
+

示例:

+ +
+输入:board = [["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]]
+输出:[["5","3","4","6","7","8","9","1","2"],["6","7","2","1","9","5","3","4","8"],["1","9","8","3","4","2","5","6","7"],["8","5","9","7","6","1","4","2","3"],["4","2","6","8","5","3","7","9","1"],["7","1","3","9","2","4","8","5","6"],["9","6","1","5","3","7","2","8","4"],["2","8","7","4","1","9","6","3","5"],["3","4","5","2","8","6","1","7","9"]]
+解释:输入的数独如上图所示,唯一有效的解决方案如下所示:
+
+
+
+ +

 

+ +

提示:

+ +
    +
  • board.length == 9
  • +
  • board[i].length == 9
  • +
  • board[i][j] 是一位数字或者 '.'
  • +
  • 题目数据 保证 输入数独仅有一个解
  • +
+
+
+
+
Related Topics
  • 哈希表
  • 回溯算法
  • \n
  • 👍 819
  • 👎 0
  • \ No newline at end of file diff --git a/LeetCode/src/main/java/leetcode/editor/cn/ValidSudoku.java b/LeetCode/src/main/java/leetcode/editor/cn/ValidSudoku.java index 8940015..b2a0acd 100644 --- a/LeetCode/src/main/java/leetcode/editor/cn/ValidSudoku.java +++ b/LeetCode/src/main/java/leetcode/editor/cn/ValidSudoku.java @@ -105,21 +105,9 @@ public class ValidSudoku { } int num = ch - '0'; int otherIndex = (i / 3) * 3 + j / 3; - if (row[i].containsKey(num)) { - row[i].put(num, row[i].get(num) + 1); - } else { - row[i].put(num, 1); - } - if (column[j].containsKey(num)) { - column[j].put(num, column[j].get(num) + 1); - } else { - column[j].put(num, 1); - } - if (other[otherIndex].containsKey(num)) { - other[otherIndex].put(num, other[otherIndex].get(num) + 1); - } else { - other[otherIndex].put(num, 1); - } + row[i].put(num,row[i].getOrDefault(num,0) + 1); + column[j].put(num,column[j].getOrDefault(num,0) + 1); + other[otherIndex].put(num,other[otherIndex].getOrDefault(num,0) + 1); if (row[i].get(num) > 1 || column[j].get(num) > 1 || other[otherIndex].get(num) > 1) { return false; } diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/hui-su-fa-jie-shu-du-by-i_use_python.md b/LeetCode/src/main/java/leetcode/editor/cn/doc/hui-su-fa-jie-shu-du-by-i_use_python.md new file mode 100644 index 0000000..34f42a6 --- /dev/null +++ b/LeetCode/src/main/java/leetcode/editor/cn/doc/hui-su-fa-jie-shu-du-by-i_use_python.md @@ -0,0 +1,82 @@ +### 解数独思路: +类似人的思考方式去尝试,`行`,`列`,还有 `3*3` 的方格内数字是 1~9 不能重复。 + +我们尝试填充,如果发现重复了,那么擦除重新进行新一轮的尝试,直到把整个数组填充完成。 + + +### 算法步骤: +- 数独首先`行`,`列`,还有 `3*3` 的方格内数字是 1~9 不能重复。 + +- 声明布尔数组,表明行列中某个数字是否被使用了, 被用过视为 `true`,没用过为 `false`。 + +- 初始化布尔数组,表明哪些数字已经被使用过了。 + +- 尝试去填充数组,只要`行`,`列`, 还有 `3*3` 的方格内 出现已经被使用过的数字,我们就不填充,否则尝试填充。 + +- 如果填充失败,那么我们需要回溯。将原来尝试填充的地方改回来。 + +- 递归直到数独被填充完成。 + +### 代码: + +代码看着多, 其实逻辑非常清楚,很容易理解。 + +```java [-Java] +class Solution { + public void solveSudoku(char[][] board) { + // 三个布尔数组 表明 行, 列, 还有 3*3 的方格的数字是否被使用过 + boolean[][] rowUsed = new boolean[9][10]; + boolean[][] colUsed = new boolean[9][10]; + boolean[][][] boxUsed = new boolean[3][3][10]; + // 初始化 + for(int row = 0; row < board.length; row++){ + for(int col = 0; col < board[0].length; col++) { + int num = board[row][col] - '0'; + if(1 <= num && num <= 9){ + rowUsed[row][num] = true; + colUsed[col][num] = true; + boxUsed[row/3][col/3][num] = true; + } + } + } + // 递归尝试填充数组 + recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, 0, 0); + } + + private boolean recusiveSolveSudoku(char[][]board, boolean[][]rowUsed, boolean[][]colUsed, boolean[][][]boxUsed, int row, int col){ + // 边界校验, 如果已经填充完成, 返回true, 表示一切结束 + if(col == board[0].length){ + col = 0; + row++; + if(row == board.length){ + return true; + } + } + // 是空则尝试填充, 否则跳过继续尝试填充下一个位置 + if(board[row][col] == '.') { + // 尝试填充1~9 + for(int num = 1; num <= 9; num++){ + boolean canUsed = !(rowUsed[row][num] || colUsed[col][num] || boxUsed[row/3][col/3][num]); + if(canUsed){ + rowUsed[row][num] = true; + colUsed[col][num] = true; + boxUsed[row/3][col/3][num] = true; + + board[row][col] = (char)('0' + num); + if(recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, row, col + 1)){ + return true; + } + board[row][col] = '.'; + + rowUsed[row][num] = false; + colUsed[col][num] = false; + boxUsed[row/3][col/3][num] = false; + } + } + } else { + return recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, row, col + 1); + } + return false; + } +} +``` \ No newline at end of file diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/jie-shu-du-by-leetcode-solution.md b/LeetCode/src/main/java/leetcode/editor/cn/doc/jie-shu-du-by-leetcode-solution.md new file mode 100644 index 0000000..67e1f46 --- /dev/null +++ b/LeetCode/src/main/java/leetcode/editor/cn/doc/jie-shu-du-by-leetcode-solution.md @@ -0,0 +1,914 @@ +#### 前言 + +我们可以考虑按照「行优先」的顺序依次枚举每一个空白格中填的数字,通过递归 + 回溯的方法枚举所有可能的填法。当递归到最后一个空白格后,如果仍然没有冲突,说明我们找到了答案;在递归的过程中,如果当前的空白格不能填下任何一个数字,那么就进行回溯。 + +由于每个数字在同一行、同一列、同一个九宫格中只会出现一次,因此我们可以使用 ![\textit{line}\[i\] ](./p__textit{line}_i__.png) ,![\textit{column}\[j\] ](./p__textit{column}_j__.png) ,![\textit{block}\[x\]\[y\] ](./p__textit{block}_x__y__.png) 分别表示第 *i* 行,第 *j* 列,第 *(x, y)* 个九宫格中填写数字的情况。在下面给出的三种方法中,我们将会介绍两种不同的表示填写数字情况的方法。 + +> 九宫格的范围为 ![0\leqx\leq2 ](./p__0_leq_x_leq_2_.png) 以及 ![0\leqy\leq2 ](./p__0_leq_y_leq_2_.png) 。 +> 具体地,第 *i* 行第 *j* 列的格子位于第 ![(\lfloori/3\rfloor,\lfloorj/3\rfloor) ](./p___lfloor_i_3_rfloor,_lfloor_j_3_rfloor__.png) 个九宫格中,其中 ![\lflooru\rfloor ](./p__lfloor_u_rfloor_.png) 表示对 *u* 向下取整。 + +由于这些方法均以递归 + 回溯为基础,算法运行的时间(以及时间复杂度)很大程度取决于给定的输入数据,而我们很难找到一个非常精确的渐进紧界。因此这里只给出一个较为宽松的渐进复杂度上界 ![O(9^{9\times9}) ](./p__O_9^{9_times_9}__.png) ,即最多有 ![9\times9 ](./p__9_times_9_.png) 个空白格,每个格子可以填 *[1, 9]* 中的任意整数。 + +#### 方法一:递归 + +**思路** + +最容易想到的方法是用一个数组记录每个数字是否出现。由于我们可以填写的数字范围为 *[1, 9]*,而数组的下标从 *0* 开始,因此在存储时,我们使用一个长度为 *9* 的布尔类型的数组,其中 *i* 个元素的值为 ![\text{True} ](./p__text{True}_.png) ,当且仅当数字 *i+1* 出现过。例如我们用 ![\textit{line}\[2\]\[3\]=\text{True} ](./p__textit{line}_2__3__=_text{True}_.png) 表示数字 *4* 在第 *2* 行已经出现过,那么当我们在遍历到第 *2* 行的空白格时,就不能填入数字 *4*。 + +**算法** + +我们首先对整个数独数组进行遍历,当我们遍历到第 *i* 行第 *j* 列的位置: + +- 如果该位置是一个空白格,那么我们将其加入一个用来存储空白格位置的列表中,方便后续的递归操作; + +- 如果该位置是一个数字 *x*,那么我们需要将 ![\textit{line}\[i\]\[x-1\] ](./p__textit{line}_i__x-1__.png) ,![\textit{column}\[j\]\[x-1\] ](./p__textit{column}_j__x-1__.png) 以及 ![\textit{block}\[\lfloori/3\rfloor\]\[\lfloorj/3\rfloor\]\[x-1\] ](./p__textit{block}_lfloor_i_3_rfloor__lfloor_j_3_rfloor__x-1__.png) 均置为 ![\text{True} ](./p__text{True}_.png) 。 + +当我们结束了遍历过程之后,就可以开始递归枚举。当递归到第 *i* 行第 *j* 列的位置时,我们枚举填入的数字 *x*。根据题目的要求,数字 *x* 不能和当前行、列、九宫格中已经填入的数字相同,因此 ![\textit{line}\[i\]\[x-1\] ](./p__textit{line}_i__x-1__.png) ,![\textit{column}\[j\]\[x-1\] ](./p__textit{column}_j__x-1__.png) 以及 ![\textit{block}\[\lfloori/3\rfloor\]\[\lfloorj/3\rfloor\]\[x-1\] ](./p__textit{block}_lfloor_i_3_rfloor__lfloor_j_3_rfloor__x-1__.png) 必须均为 ![\text{False} ](./p__text{False}_.png) 。 + +当我们填入了数字 *x* 之后,我们要将上述的三个值都置为 ![\text{True} ](./p__text{True}_.png) ,并且继续对下一个空白格位置进行递归。在回溯到当前递归层时,我们还要将上述的三个值重新置为 ![\text{False} ](./p__text{False}_.png) 。 + +**代码** + +```C++ [sol1-C++] +class Solution { +private: + bool line[9][9]; + bool column[9][9]; + bool block[3][3][9]; + bool valid; + vector> spaces; + +public: + void dfs(vector>& board, int pos) { + if (pos == spaces.size()) { + valid = true; + return; + } + + auto [i, j] = spaces[pos]; + for (int digit = 0; digit < 9 && !valid; ++digit) { + if (!line[i][digit] && !column[j][digit] && !block[i / 3][j / 3][digit]) { + line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true; + board[i][j] = digit + '0' + 1; + dfs(board, pos + 1); + line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = false; + } + } + } + + void solveSudoku(vector>& board) { + memset(line, false, sizeof(line)); + memset(column, false, sizeof(column)); + memset(block, false, sizeof(block)); + valid = false; + + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] == '.') { + spaces.emplace_back(i, j); + } + else { + int digit = board[i][j] - '0' - 1; + line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true; + } + } + } + + dfs(board, 0); + } +}; +``` + +```Java [sol1-Java] +class Solution { + private boolean[][] line = new boolean[9][9]; + private boolean[][] column = new boolean[9][9]; + private boolean[][][] block = new boolean[3][3][9]; + private boolean valid = false; + private List spaces = new ArrayList(); + + public void solveSudoku(char[][] board) { + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] == '.') { + spaces.add(new int[]{i, j}); + } else { + int digit = board[i][j] - '0' - 1; + line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true; + } + } + } + + dfs(board, 0); + } + + public void dfs(char[][] board, int pos) { + if (pos == spaces.size()) { + valid = true; + return; + } + + int[] space = spaces.get(pos); + int i = space[0], j = space[1]; + for (int digit = 0; digit < 9 && !valid; ++digit) { + if (!line[i][digit] && !column[j][digit] && !block[i / 3][j / 3][digit]) { + line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true; + board[i][j] = (char) (digit + '0' + 1); + dfs(board, pos + 1); + line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = false; + } + } + } +} +``` + +```Python [sol1-Python3] +class Solution: + def solveSudoku(self, board: List[List[str]]) -> None: + def dfs(pos: int): + nonlocal valid + if pos == len(spaces): + valid = True + return + + i, j = spaces[pos] + for digit in range(9): + if line[i][digit] == column[j][digit] == block[i // 3][j // 3][digit] == False: + line[i][digit] = column[j][digit] = block[i // 3][j // 3][digit] = True + board[i][j] = str(digit + 1) + dfs(pos + 1) + line[i][digit] = column[j][digit] = block[i // 3][j // 3][digit] = False + if valid: + return + + line = [[False] * 9 for _ in range(9)] + column = [[False] * 9 for _ in range(9)] + block = [[[False] * 9 for _a in range(3)] for _b in range(3)] + valid = False + spaces = list() + + for i in range(9): + for j in range(9): + if board[i][j] == ".": + spaces.append((i, j)) + else: + digit = int(board[i][j]) - 1 + line[i][digit] = column[j][digit] = block[i // 3][j // 3][digit] = True + + dfs(0) +``` + +```Golang [sol1-Golang] +func solveSudoku(board [][]byte) { + var line, column [9][9]bool + var block [3][3][9]bool + var spaces [][2]int + + for i, row := range board { + for j, b := range row { + if b == '.' { + spaces = append(spaces, [2]int{i, j}) + } else { + digit := b - '1' + line[i][digit] = true + column[j][digit] = true + block[i/3][j/3][digit] = true + } + } + } + + var dfs func(int) bool + dfs = func(pos int) bool { + if pos == len(spaces) { + return true + } + i, j := spaces[pos][0], spaces[pos][1] + for digit := byte(0); digit < 9; digit++ { + if !line[i][digit] && !column[j][digit] && !block[i/3][j/3][digit] { + line[i][digit] = true + column[j][digit] = true + block[i/3][j/3][digit] = true + board[i][j] = digit + '1' + if dfs(pos + 1) { + return true + } + line[i][digit] = false + column[j][digit] = false + block[i/3][j/3][digit] = false + } + } + return false + } + dfs(0) +} +``` + +```C [sol1-C] +bool line[9][9]; +bool column[9][9]; +bool block[3][3][9]; +bool valid; +int* spaces[81]; +int spacesSize; + +void dfs(char** board, int pos) { + if (pos == spacesSize) { + valid = true; + return; + } + + int i = spaces[pos][0], j = spaces[pos][1]; + for (int digit = 0; digit < 9 && !valid; ++digit) { + if (!line[i][digit] && !column[j][digit] && !block[i / 3][j / 3][digit]) { + line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true; + board[i][j] = digit + '0' + 1; + dfs(board, pos + 1); + line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = false; + } + } +} + +void solveSudoku(char** board, int boardSize, int* boardColSize) { + memset(line, false, sizeof(line)); + memset(column, false, sizeof(column)); + memset(block, false, sizeof(block)); + valid = false; + spacesSize = 0; + + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] == '.') { + spaces[spacesSize] = malloc(sizeof(int) * 2); + spaces[spacesSize][0] = i; + spaces[spacesSize++][1] = j; + } else { + int digit = board[i][j] - '0' - 1; + line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true; + } + } + } + + dfs(board, 0); +} +``` + +#### 方法二:位运算优化 + +**思路与算法** + +在方法一中,我们使用了长度为 *9* 的数组表示每个数字是否出现过。我们同样也可以借助位运算,仅使用一个整数表示每个数字是否出现过。 + +具体地,数 *b* 的二进制表示的第 *i* 位(从低到高,最低位为第 *0* 位)为 *1*,当且仅当数字 *i+1* 已经出现过。例如当 *b* 的二进制表示为 *(011000100)_2* 时,就表示数字 *3*,*7*,*8* 已经出现过。 + +位运算有一些基础的使用技巧。下面列举了所有在代码中使用到的技巧: + +- 对于第 *i* 行第 *j* 列的位置,![\textit{line}\[i\]~|~\textit{column}\[j\]~|~\textit{block}\[\lfloori/3\rfloor\]\[\lfloorj/3\rfloor\] ](./p__textit{line}_i__~|~_textit{column}_j__~|~_textit{block}_lfloor_i_3_rfloor__lfloor_j_3_rfloor__.png) 中第 *k* 位为 *1*,表示该位置不能填入数字 *k+1*(因为已经出现过),其中 *|* 表示按位或运算。如果我们对这个值进行 ![\sim ](./p__sim_.png) 按位取反运算,那么第 *k* 位为 *1* 就表示该位置可以填入数字 *k+1*,我们就可以通过寻找 *1* 来进行枚举。由于在进行按位取反运算后,这个数的高位也全部变成了 *1*,而这是我们不应当枚举到的,因此我们需要将这个数和 ![(111111111)_2=(\text{1FF})_{16} ](./p___111111111__2_=__text{1FF}__{16}_.png) 进行按位与运算 ![\& ](./p__&_.png) ,将所有无关的位置为 *0*; + +- 我们可以使用按位异或运算 ![\wedge ](./p__wedge_.png) ,将第 *i* 位从 *0* 变为 *1*,或从 *1* 变为 *0*。具体地,与数 *1 << i* 进行按位异或运算即可,其中 *<<* 表示左移运算; + +- 我们可以用 ![b~\&~(-b) ](./p__b_~&~__-b__.png) 得到 *b* 二进制表示中最低位的 *1*,这是因为 *(-b)* 在计算机中以补码的形式存储,它等于 ![\simb+1 ](./p__sim_b_+_1_.png) 。*b* 如果和 ![\simb ](./p__sim_b_.png) 进行按位与运算,那么会得到 *0*,但是当 ![\simb ](./p__sim_b_.png) 增加 *1* 之后,最低位的连续的 *1* 都变为 *0*,而最低位的 *0* 变为 *1*,对应到 *b* 中即为最低位的 *1*,因此当 *b* 和 ![\simb+1 ](./p__sim_b_+_1_.png) 进行按位与运算时,只有最低位的 *1* 会被保留; + +- 当我们得到这个最低位的 *1* 时,我们可以通过一些语言自带的函数得到这个最低位的 *1* 究竟是第几位(即 *i* 值),具体可以参考下面的代码; + +- 我们可以用 *b* 和最低位的 *1* 进行按位异或运算,就可以将其从 *b* 中去除,这样就可以枚举下一个 *1*。同样地,我们也可以用 *b* 和 *b-1* 进行按位与运算达到相同的效果,读者可以自行尝试推导。 + +实际上,方法二中整体的递归 + 回溯的框架与方法一是一致的。不同的仅仅是我们将一个数组「压缩」成了一个数而已。 + +**代码** + +```C++ [sol2-C++] +class Solution { +private: + int line[9]; + int column[9]; + int block[3][3]; + bool valid; + vector> spaces; + +public: + void flip(int i, int j, int digit) { + line[i] ^= (1 << digit); + column[j] ^= (1 << digit); + block[i / 3][j / 3] ^= (1 << digit); + } + + void dfs(vector>& board, int pos) { + if (pos == spaces.size()) { + valid = true; + return; + } + + auto [i, j] = spaces[pos]; + int mask = ~(line[i] | column[j] | block[i / 3][j / 3]) & 0x1ff; + for (; mask && !valid; mask &= (mask - 1)) { + int digitMask = mask & (-mask); + int digit = __builtin_ctz(digitMask); + flip(i, j, digit); + board[i][j] = digit + '0' + 1; + dfs(board, pos + 1); + flip(i, j, digit); + } + } + + void solveSudoku(vector>& board) { + memset(line, 0, sizeof(line)); + memset(column, 0, sizeof(column)); + memset(block, 0, sizeof(block)); + valid = false; + + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] == '.') { + spaces.emplace_back(i, j); + } + else { + int digit = board[i][j] - '0' - 1; + flip(i, j, digit); + } + } + } + + dfs(board, 0); + } +}; +``` + +```Java [sol2-Java] +class Solution { + private int[] line = new int[9]; + private int[] column = new int[9]; + private int[][] block = new int[3][3]; + private boolean valid = false; + private List spaces = new ArrayList(); + + public void solveSudoku(char[][] board) { + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] == '.') { + spaces.add(new int[]{i, j}); + } else { + int digit = board[i][j] - '0' - 1; + flip(i, j, digit); + } + } + } + + dfs(board, 0); + } + + public void dfs(char[][] board, int pos) { + if (pos == spaces.size()) { + valid = true; + return; + } + + int[] space = spaces.get(pos); + int i = space[0], j = space[1]; + int mask = ~(line[i] | column[j] | block[i / 3][j / 3]) & 0x1ff; + for (; mask != 0 && !valid; mask &= (mask - 1)) { + int digitMask = mask & (-mask); + int digit = Integer.bitCount(digitMask - 1); + flip(i, j, digit); + board[i][j] = (char) (digit + '0' + 1); + dfs(board, pos + 1); + flip(i, j, digit); + } + } + + public void flip(int i, int j, int digit) { + line[i] ^= (1 << digit); + column[j] ^= (1 << digit); + block[i / 3][j / 3] ^= (1 << digit); + } +} +``` + +```Python [sol2-Python3] +class Solution: + def solveSudoku(self, board: List[List[str]]) -> None: + def flip(i: int, j: int, digit: int): + line[i] ^= (1 << digit) + column[j] ^= (1 << digit) + block[i // 3][j // 3] ^= (1 << digit) + + def dfs(pos: int): + nonlocal valid + if pos == len(spaces): + valid = True + return + + i, j = spaces[pos] + mask = ~(line[i] | column[j] | block[i // 3][j // 3]) & 0x1ff + while mask: + digitMask = mask & (-mask) + digit = bin(digitMask).count("0") - 1 + flip(i, j, digit) + board[i][j] = str(digit + 1) + dfs(pos + 1) + flip(i, j, digit) + mask &= (mask - 1) + if valid: + return + + line = [0] * 9 + column = [0] * 9 + block = [[0] * 3 for _ in range(3)] + valid = False + spaces = list() + + for i in range(9): + for j in range(9): + if board[i][j] == ".": + spaces.append((i, j)) + else: + digit = int(board[i][j]) - 1 + flip(i, j, digit) + + dfs(0) +``` + +```Golang [sol2-Golang] +func solveSudoku(board [][]byte) { + var line, column [9]int + var block [3][3]int + var spaces [][2]int + + flip := func(i, j int, digit byte) { + line[i] ^= 1 << digit + column[j] ^= 1 << digit + block[i/3][j/3] ^= 1 << digit + } + + for i, row := range board { + for j, b := range row { + if b == '.' { + spaces = append(spaces, [2]int{i, j}) + } else { + digit := b - '1' + flip(i, j, digit) + } + } + } + + var dfs func(int) bool + dfs = func(pos int) bool { + if pos == len(spaces) { + return true + } + i, j := spaces[pos][0], spaces[pos][1] + mask := 0x1ff &^ uint(line[i]|column[j]|block[i/3][j/3]) // 0x1ff 即二进制的 9 个 1 + for ; mask > 0; mask &= mask - 1 { // 最右侧的 1 置为 0 + digit := byte(bits.TrailingZeros(mask)) + flip(i, j, digit) + board[i][j] = digit + '1' + if dfs(pos + 1) { + return true + } + flip(i, j, digit) + } + return false + } + dfs(0) +} +``` + +```C [sol2-C] +int line[9]; +int column[9]; +int block[3][3]; +bool valid; +int* spaces[81]; +int spacesSize; + +void flip(int i, int j, int digit) { + line[i] ^= (1 << digit); + column[j] ^= (1 << digit); + block[i / 3][j / 3] ^= (1 << digit); +} + +void dfs(char** board, int pos) { + if (pos == spacesSize) { + valid = true; + return; + } + + int i = spaces[pos][0], j = spaces[pos][1]; + int mask = ~(line[i] | column[j] | block[i / 3][j / 3]) & 0x1ff; + for (; mask && !valid; mask &= (mask - 1)) { + int digitMask = mask & (-mask); + int digit = __builtin_ctz(digitMask); + flip(i, j, digit); + board[i][j] = digit + '0' + 1; + dfs(board, pos + 1); + flip(i, j, digit); + } +} + +void solveSudoku(char** board, int boardSize, int* boardColSize) { + memset(line, 0, sizeof(line)); + memset(column, 0, sizeof(column)); + memset(block, 0, sizeof(block)); + valid = false; + spacesSize = 0; + + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] == '.') { + spaces[spacesSize] = malloc(sizeof(int) * 2); + spaces[spacesSize][0] = i; + spaces[spacesSize++][1] = j; + } else { + int digit = board[i][j] - '0' - 1; + flip(i, j, digit); + } + } + } + + dfs(board, 0); +} +``` + +#### 方法三:枚举优化 + +**思路与算法** + +我们可以顺着方法二的思路继续优化下去: + +- 如果一个空白格只有唯一的数可以填入,也就是其对应的 *b* 值和 *b-1* 进行按位与运算后得到 *0*(即 *b* 中只有一个二进制位为 *1*)。此时,我们就可以确定这个空白格填入的数,而不用等到递归时再去处理它。 + +这样一来,我们可以不断地对整个数独进行遍历,将可以唯一确定的空白格全部填入对应的数。随后我们再使用与方法二相同的方法对剩余无法唯一确定的空白格进行递归 + 回溯。 + +**代码** + +```C++ [sol3-C++] +class Solution { +private: + int line[9]; + int column[9]; + int block[3][3]; + bool valid; + vector> spaces; + +public: + void flip(int i, int j, int digit) { + line[i] ^= (1 << digit); + column[j] ^= (1 << digit); + block[i / 3][j / 3] ^= (1 << digit); + } + + void dfs(vector>& board, int pos) { + if (pos == spaces.size()) { + valid = true; + return; + } + + auto [i, j] = spaces[pos]; + int mask = ~(line[i] | column[j] | block[i / 3][j / 3]) & 0x1ff; + for (; mask && !valid; mask &= (mask - 1)) { + int digitMask = mask & (-mask); + int digit = __builtin_ctz(digitMask); + flip(i, j, digit); + board[i][j] = digit + '0' + 1; + dfs(board, pos + 1); + flip(i, j, digit); + } + } + + void solveSudoku(vector>& board) { + memset(line, 0, sizeof(line)); + memset(column, 0, sizeof(column)); + memset(block, 0, sizeof(block)); + valid = false; + + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] != '.') { + int digit = board[i][j] - '0' - 1; + flip(i, j, digit); + } + } + } + + while (true) { + int modified = false; + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] == '.') { + int mask = ~(line[i] | column[j] | block[i / 3][j / 3]) & 0x1ff; + if (!(mask & (mask - 1))) { + int digit = __builtin_ctz(mask); + flip(i, j, digit); + board[i][j] = digit + '0' + 1; + modified = true; + } + } + } + } + if (!modified) { + break; + } + } + + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] == '.') { + spaces.emplace_back(i, j); + } + } + } + + dfs(board, 0); + } +}; +``` + +```Java [sol3-Java] +class Solution { + private int[] line = new int[9]; + private int[] column = new int[9]; + private int[][] block = new int[3][3]; + private boolean valid = false; + private List spaces = new ArrayList(); + + public void solveSudoku(char[][] board) { + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] != '.') { + int digit = board[i][j] - '0' - 1; + flip(i, j, digit); + } + } + } + + while (true) { + boolean modified = false; + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] == '.') { + int mask = ~(line[i] | column[j] | block[i / 3][j / 3]) & 0x1ff; + if ((mask & (mask - 1)) == 0) { + int digit = Integer.bitCount(mask - 1); + flip(i, j, digit); + board[i][j] = (char) (digit + '0' + 1); + modified = true; + } + } + } + } + if (!modified) { + break; + } + } + + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] == '.') { + spaces.add(new int[]{i, j}); + } + } + } + + dfs(board, 0); + } + + public void dfs(char[][] board, int pos) { + if (pos == spaces.size()) { + valid = true; + return; + } + + int[] space = spaces.get(pos); + int i = space[0], j = space[1]; + int mask = ~(line[i] | column[j] | block[i / 3][j / 3]) & 0x1ff; + for (; mask != 0 && !valid; mask &= (mask - 1)) { + int digitMask = mask & (-mask); + int digit = Integer.bitCount(digitMask - 1); + flip(i, j, digit); + board[i][j] = (char) (digit + '0' + 1); + dfs(board, pos + 1); + flip(i, j, digit); + } + } + + public void flip(int i, int j, int digit) { + line[i] ^= (1 << digit); + column[j] ^= (1 << digit); + block[i / 3][j / 3] ^= (1 << digit); + } +} +``` + +```Python [sol3-Python3] +class Solution: + def solveSudoku(self, board: List[List[str]]) -> None: + def flip(i: int, j: int, digit: int): + line[i] ^= (1 << digit) + column[j] ^= (1 << digit) + block[i // 3][j // 3] ^= (1 << digit) + + def dfs(pos: int): + nonlocal valid + if pos == len(spaces): + valid = True + return + + i, j = spaces[pos] + mask = ~(line[i] | column[j] | block[i // 3][j // 3]) & 0x1ff + while mask: + digitMask = mask & (-mask) + digit = bin(digitMask).count("0") - 1 + flip(i, j, digit) + board[i][j] = str(digit + 1) + dfs(pos + 1) + flip(i, j, digit) + mask &= (mask - 1) + if valid: + return + + line = [0] * 9 + column = [0] * 9 + block = [[0] * 3 for _ in range(3)] + valid = False + spaces = list() + + for i in range(9): + for j in range(9): + if board[i][j] != ".": + digit = int(board[i][j]) - 1 + flip(i, j, digit) + + while True: + modified = False + for i in range(9): + for j in range(9): + if board[i][j] == ".": + mask = ~(line[i] | column[j] | block[i // 3][j // 3]) & 0x1ff + if not (mask & (mask - 1)): + digit = bin(mask).count("0") - 1 + flip(i, j, digit) + board[i][j] = str(digit + 1) + modified = True + if not modified: + break + + for i in range(9): + for j in range(9): + if board[i][j] == ".": + spaces.append((i, j)) + + dfs(0) +``` + +```Golang [sol3-Golang] +func solveSudoku(board [][]byte) { + var line, column [9]int + var block [3][3]int + var spaces [][2]int + + flip := func(i, j int, digit byte) { + line[i] ^= 1 << digit + column[j] ^= 1 << digit + block[i/3][j/3] ^= 1 << digit + } + + for i, row := range board { + for j, b := range row { + if b != '.' { + digit := b - '1' + flip(i, j, digit) + } + } + } + + for { + modified := false + for i, row := range board { + for j, b := range row { + if b != '.' { + continue + } + mask := 0x1ff &^ uint(line[i]|column[j]|block[i/3][j/3]) + if mask&(mask-1) == 0 { // mask 的二进制表示仅有一个 1 + digit := byte(bits.TrailingZeros(mask)) + flip(i, j, digit) + board[i][j] = digit + '1' + modified = true + } + } + } + if !modified { + break + } + } + + for i, row := range board { + for j, b := range row { + if b == '.' { + spaces = append(spaces, [2]int{i, j}) + } + } + } + + var dfs func(int) bool + dfs = func(pos int) bool { + if pos == len(spaces) { + return true + } + i, j := spaces[pos][0], spaces[pos][1] + mask := 0x1ff &^ uint(line[i]|column[j]|block[i/3][j/3]) // 0x1ff 即二进制的 9 个 1 + for ; mask > 0; mask &= mask - 1 { // 最右侧的 1 置为 0 + digit := byte(bits.TrailingZeros(mask)) + flip(i, j, digit) + board[i][j] = digit + '1' + if dfs(pos + 1) { + return true + } + flip(i, j, digit) + } + return false + } + dfs(0) +} +``` + +```C [sol3-C] +int line[9]; +int column[9]; +int block[3][3]; +bool valid; +int* spaces[81]; +int spacesSize; + +void flip(int i, int j, int digit) { + line[i] ^= (1 << digit); + column[j] ^= (1 << digit); + block[i / 3][j / 3] ^= (1 << digit); +} + +void dfs(char** board, int pos) { + if (pos == spacesSize) { + valid = true; + return; + } + + int i = spaces[pos][0], j = spaces[pos][1]; + int mask = ~(line[i] | column[j] | block[i / 3][j / 3]) & 0x1ff; + for (; mask && !valid; mask &= (mask - 1)) { + int digitMask = mask & (-mask); + int digit = __builtin_ctz(digitMask); + flip(i, j, digit); + board[i][j] = digit + '0' + 1; + dfs(board, pos + 1); + flip(i, j, digit); + } +} + +void solveSudoku(char** board, int boardSize, int* boardColSize) { + memset(line, 0, sizeof(line)); + memset(column, 0, sizeof(column)); + memset(block, 0, sizeof(block)); + valid = false; + spacesSize = 0; + + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] != '.') { + int digit = board[i][j] - '0' - 1; + flip(i, j, digit); + } + } + } + + while (true) { + int modified = false; + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] == '.') { + int mask = ~(line[i] | column[j] | block[i / 3][j / 3]) & 0x1ff; + if (!(mask & (mask - 1))) { + int digit = __builtin_ctz(mask); + flip(i, j, digit); + board[i][j] = digit + '0' + 1; + modified = true; + } + } + } + } + if (!modified) { + break; + } + } + + for (int i = 0; i < 9; ++i) { + for (int j = 0; j < 9; ++j) { + if (board[i][j] == '.') { + spaces[spacesSize] = malloc(sizeof(int) * 2); + spaces[spacesSize][0] = i; + spaces[spacesSize++][1] = j; + } + } + } + + dfs(board, 0); +} +``` \ No newline at end of file diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p__&_.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__&_.png new file mode 100644 index 0000000000000000000000000000000000000000..627d33deb20bd895f23859995476c3156e480d39 GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^f_?V4{9*I$%Q$eH!B9n{LwI3Q4@c&sgH;M(9 zfWUT!k5(oh6HM&<9&j8Hb2!6#q`cvVsMb4%BSHaYaSUAD{tjmtpGGr%tYzy6?r09F>t%0evs8#c0# zl$GLpIy0QPy?O7xXWm=Qr#?03+&k~QxpU84qL7euQf4MnNZ_@K;Q<_k18~+m9G46@ z3?s15I}|uJwU*!-+=CY+&u7IM>{anLoK&$NnI!WfaERnjrV86y)38y+{4AF$_Js?) z!9tbmgtsa-$$|6moc!NPP$XK5cfg&B+u*y3eW`%oMy?4y8#xzl8!pyi4p`6($KXC3 zhokTcw&+QUWNMYeS`|;g2NnCmH+>no2KZ^@T-r%mX&L4kW3k91Sp=pFJ~`Li$5qa? zNwT$Evf(4iu82!1$&S!H$8YXM#nEVmr*H!n7-P}Ma%4717QmK7Yq=c3ZZqizFTg7- zQMn#?ui{wL!xOkm_Fv~4l3l^@PO&ACTD)j=&Na8c6^A58lFJUs5tInkB)`Kw84Z5$ z8CV2ANIrth>hBDD;?-J!H6-nn59hqY{_qX_@ckqou`TjHo|0vXB;cws8_ zqyShaX?5+jXGTb{EW+a$j{HsiH|eYu5)u;P;RhasN=e`89Fzb6002ovPDHLkV1jR* B=+^)M literal 0 HcmV?d00001 diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p__0_leq_y_leq_2_.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__0_leq_y_leq_2_.png new file mode 100644 index 0000000000000000000000000000000000000000..fcf6d912b72f4d467e8f24136779b97628a0fd71 GIT binary patch literal 539 zcmV+$0_6RPP)+0005vNklwOGF7fS&IB93k#m5vSMfT7UGXkQfy=) z8!N^4bZ0no&6{~|yyr*Fr#?03-22{ncjlgVhsek0C&@`{m6I_O`Q=~D`H;DiHL3C z0#7horoI6NTdC-Pmq)Zr%|5^*DZ7O^db@J-9r!Fw%d!mYxEn)Lw}QeXh? z!fGQ|MB#6?*E$8TT*O20QpC3K2VS*Y4SdmZCQYQ;XBwtyV@?dh40r@PjT~=rj_vST zN0JP$NbLqk@<{Cj*=P0eLBw`6z&*GCv$Qcg(qSgNBeg3S-sS;wLKvd0BiV$ldeRPF z{3Fa2xi)wqVkfHL4qPGkf8kzITioOpmWbGiXzDP0(<+Q>Zh2QWNF6;U%cPE(XecH1 zJ=}xgn1l1ibtSwJW04X`oe5Y*s*Sh>$E?Hl@MK;%_bT`9A~_#JUMYs#q;B{zsdk7p ze3QAorDv8Ie~433FK7RfNx0=;|L0T-+|$>_HNVV+VB*K* z7zM)^hyZaj5XS;>5)c=lN>dETHvbS18zS-ZfH(w+PbnbFd}$#52gJ-sVrD?R3yF^m zI)GRZO-vn#8_>jHfK>D0fDefO0x<`Ym;(?$M&cs_2_Rkq!~#&h5)dzBK-G^7NHre? zv;lD#62AtBzasI`ffNug17aN@UJS%ssL~jKRP#}Q2N3%MaX14c{_mkmV*o1#h~c29 zA_kCZJ{Slypr(N=AfAH6M+czjTnfZ`43KCg6k?>B4+p1#*ayny1mb-Rkm$k&Kv^H; zC?P0cg#nVr*x@QL0V(FA08a))8B-6$3MjIuU?LEUp^0e$aTA&tG9bnLQ7{Td!Jq*E Xmy9d;7XY>000000NkvXXu0mjf_wa6H literal 0 HcmV?d00001 diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p__O_9^{9_times_9}__.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__O_9^{9_times_9}__.png new file mode 100644 index 0000000000000000000000000000000000000000..22df104b99d7282262149021aeeafaf64eed8aff GIT binary patch literal 660 zcmV;F0&D$=P)dFN@Q4StDh2Ho9hSWI*nTEGiNa@`OxvqT)z*WWw_DgXW`s% zomAfjXPP`Wn&A+f?k61ma0y%v-yf(f7 literal 0 HcmV?d00001 diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p___111111111__2_=__text{1FF}__{16}_.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p___111111111__2_=__text{1FF}__{16}_.png new file mode 100644 index 0000000000000000000000000000000000000000..db07a7e45eeaf654c805e82f3fca294ab348c48c GIT binary patch literal 789 zcmV+w1M2*VP)Ae3m+R2 z8+%qZ7R3MGxux&389+L$!}Um!KcY^EADWJcMRjvtn!wNLifA zCG3-7XtAV?A(iF(1lnP|vY?vYcM3XT&58-tfW+do{&Z+ZketwG8fW+do{$|rADPxGumoTQw#ycc# z>{jCk;hD~Jc&hPjP@1Oq^*~=$dw+4|!|pTXcZygINGwkJKcU0oo}oU=-{Vro5SuR- z2|x2edE23l&^+j-@}n#jmy}&ev4lv|`&L2URQoM7qqu*i{7w<80g1(FeeNQ5T*??? z^Yy$@_Ya^+#l63l!r95Bx{Pmw(lotqJ@j6+{cp1bx}|*0{~U#}8jx6=)}IM&P;HVj zhS+>PdSdaY+yWgC_x>x1cj9KP#s;NndLMth`_>fq4{f0}J4C1kBo=4P*QAUgv3&K! z`Up)Hw=nJ~zm#LpfNJlBu8CVkL(rxc^^x1qF5_`k^I4=SYz;^(&R*zB;q%{|jg_Q~ z@r3dvdSX3R_b=6bDV&KTsy$Ig-^TLFc3b**EWMULpCjgrdvGNzSQXeBkXW32vFVRg z8^0%I3<>4y(G%-DG)3I^-c$ZR>4$b&vxS_4))?;*^r_HY)7MGHq6VRSr-|Dwzd(D$ zz5iMO4T{@YmyHfhgJ05Z%@)xo?p@DVQfCeNB%ZI|?RfROW+s!#WHOmdrbd1PUiWdP)xumluNED6NN-kCX|VZfeZ{3 zLlcsLk%<}a+uqw*XPvdb|KHB148Et{&cENi&R*;M-~QI#9g&8HhK9dp0yHIlKB4>) zrb8Xpte`YcX}o11_05Eas&NsMp=;3KIKHChO1KJ*ux16Nc}n9g1F3H;bP5`zytd$% z`clFUPE`FNGobg@lu*D0HSU7eLYttQ&;m7=sLJEfD*iHb(3+7t>SIig@mj(Jw~c2P z)(nFtSrhDm=El!_SfAD05;IOz>gYn0b9luM$&Z1}W@;rc^STo|q6TVGf zpfSe(7xmqRHdwO?_ST2S^A`5l3(dA>0l7T(+L*}2^Puxi_PXoi1A8ZZ&!Dzg2CY|P zyKs(M)+i*GXNxr=I-WP5OA^k5^Uw}8m#DkGGtgq=wasSf{bvtf87@xQ_L1P-nLDHu z_Pez9eKSXRh5$@OaJR>LqkJD!+*kW8hL;w%6}Ni00000 LNkvXXu0mjfnmCLI literal 0 HcmV?d00001 diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p__b_~&~__-b__.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__b_~&~__-b__.png new file mode 100644 index 0000000000000000000000000000000000000000..9b1b59879d36554da2cc3e35f441cdfa4255c105 GIT binary patch literal 556 zcmV+{0@MA8P)xhvf;?ed?Wnk9J^6W>Z0YYJpz{u z_Bfxj^;!X+wAht4xTeLt$?$9>gJ<~>es*HMvp1xcw(Ti1yvguI^GXSVt=DFFsl~4F z2N#@UUVi5=H(pMFo8_70I~rpc-jTW?44)&m{E~4&iQo5wt=B@h`H! zKU?7r9EX#ne&{<~hZAs=)H&Ulf@3o25nHdD6d#39@d<9ri-b#)lI@O?fXJ9JiajIB2`)VC9V7huV4?InhVhq%9i!cW`Xht*J4W z0`Y4tT1?-x&9u%C7Z=&4JBcgo!@76b7J~m3W`)dF6`k|IFy{ON>9QmH{d`xQoy4{5 z(eu*@to#K_rmNgdTL`sB|B-U~A3w`$m)`8Yzxb*D4~9)Y<;ysxD%}HmjKR~@&t;uc GLK6U21#6Z7 literal 0 HcmV?d00001 diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p__sim_.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__sim_.png new file mode 100644 index 0000000000000000000000000000000000000000..c703c0fbe088981bd037f92ccd32cf722b5a733b GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^fG+Xvj2{gZ zzPV3kW)xR=<|OXI=Hp<)-oe^9L%3sig9WE6E3>nvlsxkarj6{gB9sNh84R@rq!|j; ySDB~@FeK%bI4XEBJ~DRL)5N$aP2>VI1B3KLj>Z*ccO8H>F?hQAxvX`K_L>^ib5$Wm4bRnyra}eL=*}IjZz`esOYzq_!)w4 zG8c2t-b>E1*=D}v%g%Y+2ClX0V`>2|IX>bGVCRscJpe;Y|JQc#3`4E&gv^ zPIZWEs5s;i$CL9E-UPKQOv8z>e;8*~ZVT7MzX!MJgLL_eeyj!YBHjnFV*>XB-QwO< zZVyYJA1F+hDPoUK!ixBOQ={Vr!>9nRX{ zFdev!3%Du%Lcd`dZV8X^9oMD)IkX&i;VYfY!M)kG_@UMvVLUDRk+7`xFCjTMXn)r^JG z0@4dkEMinsn8$pi$>9v=kywX0EsL5O7mD=u^PFSY$T=mK|H$kKPYfEg1gaNwnlcqK zGOO4*=)HBB+QuxXu&?n5Kl7tzj~X5Yh9h@gG&xK-#8CK^i>*T{hvCVIN{>G?9b)>A zEY~VvdnBh3Ez@zH$gTe~ HDWM4f1h`iI literal 0 HcmV?d00001 diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{block}_lfloor_i_3_rfloor__lfloor_j_3_rfloor__x-1__.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{block}_lfloor_i_3_rfloor__lfloor_j_3_rfloor__x-1__.png new file mode 100644 index 0000000000000000000000000000000000000000..a898ae62fcdc7aa03e7bd7ce57356260b92901d5 GIT binary patch literal 1233 zcmV;?1TOoDP)M=000D-NklKab>GwbN+=;-L^ z_@8sP26mAXU9&Yf1H-g4Or4T8JpN}m!S%N5Ly0eOZI#%d?BTl4wbOM>5ufM!#C5-G zVU9gEeR?1scg@n^43zDhZ>j!AMQoJbf;K#ki<-ZG$Ju<0kwB_+6OV8^8*OjizU2nKf zF0L5`+HTMkuR@1>XKA(_=lV9sr(B2RQ{EFg7Z zpv?riI`?nVrPG)8p+179c$J?m4K$c?y_AocfiXw|wp<3=*_H-hz~GAqP|oyMUF%%u zy1vY@MOHVcoeboVy!!8Fz4zr+{Gy@^tQsqdGKuy+GR$)nP?M|j85 zDhI55qo%3drg#-*7!?>4e7;~Cgy*dPRi8I1X7omzUdG{TOIr+E?L#@n0O5YDXslG< zbkZL!{bf)9)2Y$dEXyfEmDX4dj!8Hll^GT=V5w6$=| zhh_3Z@`{>4?PTCP6$AT>A~xH4A6h_%vzp?O2Y^RningO(vum&b83X@2^cXOr>I vXYvsJ$Md9k3ntxT&0j}HM@L6T$7uNnY``urg@v%<00000NkvXXu0mjf!!>Oq literal 0 HcmV?d00001 diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{block}_x__y__.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{block}_x__y__.png new file mode 100644 index 0000000000000000000000000000000000000000..f6d82fe260c4a605a201738ba016c1c34822d44a GIT binary patch literal 769 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 literal 0 HcmV?d00001 diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{line}_i__.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{line}_i__.png new file mode 100644 index 0000000000000000000000000000000000000000..f419ad6dec78e5ff8f3130553bebf5b110f06dd7 GIT binary patch literal 487 zcmVk5hZU%it;Ez2KWOElrmJzOw`RQd1YY4l#v02ks0Qg$s;k4 zfq~z$*U3KXo?Ba;E9rjq)m>|^?)mL=_PJf61PT5=jqpM@L!c0zz&Ti{)|d{s0FPBa zCR@4z4s_#(l*5mJ-leMbOdx4+Q8z;%C_oC#v+AIkKq}z4ZiawM0GF9BhG45z*TDza zEp}7=#&c2X;!2aSj<#btznf)lyf%VK^mqE!>sQ9=rj*7(am{*hBsR zeD1U0HB6Nr;~a9H%q~6nu5t(tn=HM3GGUoL*hJ>;dc4DYt7dcnKKJ}{ln#@mr)Ofa z4kxUd&*CVV$IRryJ2GF)p>JUc+>mwV3O2(`*bA2_I=~q$gCq34c|8*oK1%~u&1deB z%(-NW$^W7p!W&p*_1egUzbCV~Y>E!BLgpoHv3h#u*KrBpG80!^0=Ue?6_)@mGjS#K dKNt!AC7((?S0{__^XmWr002ovPDHLkV1oHz+M)me literal 0 HcmV?d00001 diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{line}_i__x-1__.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__textit{line}_i__x-1__.png new file mode 100644 index 0000000000000000000000000000000000000000..4fc0a6eeeea2fa9687a75d7d28a50b0401a6d382 GIT binary patch literal 703 zcmV;w0zmzVP)Kfx|nuY+IU zHrNZl!3XYG$a?r1{)By!4Zsz66y9`wj}2+-RigPW!vk<1d<0hqW6Hpu*OTf;T!3?f z`aJA`7hQcvH1tcj6E1|`-7ya*nm-6UX*c}p-unQ&_?hq_+~In}h79W&q7z8Airyf? zT+C1=HiswGkGN*)PIy;z6_AziAUx;lHE_Va_i%!FGOpm~aF=8QaNnH`-@~b{M{LNj zp6nz%x4)?=PKaJh$~|L4BWw;&svmJxbd`9xDmh7<%t@~ISadSUAlxX~uhcKNAgGBA zz)A23_B;_?jf5+-Y*Ob<^&{@VGeOP0@QCQwn9PG8L@%6^ItrJ-`|db- z2RFf4a5uaqae!BFDLgD=H^+_%YfjoR(G~ndbTyOH?zK#84o|8d!M$v6P;zjI#s4dZM1S!9 zz_X$c*&ds(a*717V{Baod~)#H3tw4#>d2F!NB}#=)^$^Ro+1J47+cp(?Ri@LGa>H} l{8pc-lDvEk4GsSne*p_umAUDiI|Tp$002ovPDHLkV1i}AQiK2i literal 0 HcmV?d00001 diff --git a/LeetCode/src/main/java/leetcode/editor/cn/doc/p__text{False}_.png b/LeetCode/src/main/java/leetcode/editor/cn/doc/p__text{False}_.png new file mode 100644 index 0000000000000000000000000000000000000000..5a608e5633a3f371031795a9cac521d8975a0705 GIT binary patch literal 441 zcmV;q0Y?6bP)0+Gm}0);S_Mkc^J1 z8shL8tY<|H@D?sQZ9`qS=qXihMhXuug-&N{LE6pV6y|14;lcfZ-vZ+>0*BD%?S;AP zVsRa?36D?-TQCeK(434;AwBpV7RBc3L83Q0fE8zV!@alX7gYs!P~`k3v7)YAoN5Se zot;wQ(+&oHzF7ArU_qjT?dNLT1w6qi%!qYKKcWHXgK4pcOslY{a_Dt-9$dnb^AoZ9 zMb>z}N@uY`Y!2t(2F}HbDswS^R#=p;TCqb*oUa|zPBn`CF8o}zSDmeDg=e@H%S&j| zvwu`O?26r3hjc8u{ne?M*w9YFk-O^aIhOBS{jX_Jap)22^bU-Qy~2H%hgqnXG}70g jv!K!f3cbCY{+&Jn4pd2@s5^oM00000NkvXXu0mjfR;%txlYPQ$rNpbz_Si>E0Uo;ir1A4^j3qj3( znUc84OeDkUi9J+_)o1VnM|{?eV0$`PH`#8KKPln?HpRWsiO;&Yr%nAB=lnH_{+AAM z1NZUO_vo(D1$-m!K6_a4*Yssr+d;tuuH#pjHda?ij002ov JPDHLkV1iAG+J4kk5) zdF^V`*pIMfBv~}t3$QQj{AlQKs6~Te(_G0|0gkGM2#Ht$Sq~$JKmEKJ424{~9vCn% Z+{ombuJ``#R-h9YJYD@<);T3K0RWz4GqV5y literal 0 HcmV?d00001