|
| 1 | +package pp.arithmetic.leetcode; |
| 2 | + |
| 3 | +import java.util.HashMap; |
| 4 | + |
| 5 | +/** |
| 6 | + * Created by wangpeng on 2019-05-14. |
| 7 | + * 36. 有效的数独 |
| 8 | + * |
| 9 | + * 判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。 |
| 10 | + * |
| 11 | + * 数字 1-9 在每一行只能出现一次。 |
| 12 | + * 数字 1-9 在每一列只能出现一次。 |
| 13 | + * 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 |
| 14 | + * |
| 15 | + * <image src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Sudoku-by-L2G-20050714.svg/250px-Sudoku-by-L2G-20050714.svg.png" /> |
| 16 | + * 上图是一个部分填充的有效的数独。 |
| 17 | + * |
| 18 | + * 数独部分空格内已填入了数字,空白格用 '.' 表示。 |
| 19 | + * |
| 20 | + * 示例 1: |
| 21 | + * |
| 22 | + * 输入: |
| 23 | + * [ |
| 24 | + * ["5","3",".",".","7",".",".",".","."], |
| 25 | + * ["6",".",".","1","9","5",".",".","."], |
| 26 | + * [".","9","8",".",".",".",".","6","."], |
| 27 | + * ["8",".",".",".","6",".",".",".","3"], |
| 28 | + * ["4",".",".","8",".","3",".",".","1"], |
| 29 | + * ["7",".",".",".","2",".",".",".","6"], |
| 30 | + * [".","6",".",".",".",".","2","8","."], |
| 31 | + * [".",".",".","4","1","9",".",".","5"], |
| 32 | + * [".",".",".",".","8",".",".","7","9"] |
| 33 | + * ] |
| 34 | + * 输出: true |
| 35 | + * 示例 2: |
| 36 | + * |
| 37 | + * 输入: |
| 38 | + * [ |
| 39 | + * ["8","3",".",".","7",".",".",".","."], |
| 40 | + * ["6",".",".","1","9","5",".",".","."], |
| 41 | + * [".","9","8",".",".",".",".","6","."], |
| 42 | + * ["8",".",".",".","6",".",".",".","3"], |
| 43 | + * ["4",".",".","8",".","3",".",".","1"], |
| 44 | + * ["7",".",".",".","2",".",".",".","6"], |
| 45 | + * [".","6",".",".",".",".","2","8","."], |
| 46 | + * [".",".",".","4","1","9",".",".","5"], |
| 47 | + * [".",".",".",".","8",".",".","7","9"] |
| 48 | + * ] |
| 49 | + * 输出: false |
| 50 | + * 解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 |
| 51 | + * 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。 |
| 52 | + * 说明: |
| 53 | + * |
| 54 | + * 一个有效的数独(部分已被填充)不一定是可解的。 |
| 55 | + * 只需要根据以上规则,验证已经填入的数字是否有效即可。 |
| 56 | + * 给定数独序列只包含数字 1-9 和字符 '.' 。 |
| 57 | + * 给定数独永远是 9x9 形式的。 |
| 58 | + */ |
| 59 | +public class _36_isValidSudoku { |
| 60 | + |
| 61 | + public static void main(String[] args) { |
| 62 | + char[][] board = new char[][]{ |
| 63 | + {'5', '3', '.', '.', '7', '.', '.', '.', '.'}, |
| 64 | + {'6', '.', '.', '1', '9', '5', '.', '.', '.'}, |
| 65 | + {'.', '9', '8', '.', '.', '.', '.', '6', '.'}, |
| 66 | + {'8', '.', '.', '.', '6', '.', '.', '.', '3'}, |
| 67 | + {'4', '.', '.', '8', '.', '3', '.', '.', '1'}, |
| 68 | + {'7', '.', '.', '.', '2', '.', '.', '.', '6'}, |
| 69 | + {'.', '6', '.', '.', '.', '.', '2', '8', '.'}, |
| 70 | + {'.', '.', '.', '4', '1', '9', '.', '.', '5'}, |
| 71 | + {'.', '.', '.', '.', '8', '.', '.', '7', '9'} |
| 72 | + }; |
| 73 | + _36_isValidSudoku isValidSudoku = new _36_isValidSudoku(); |
| 74 | + System.out.println(isValidSudoku.isValidSudoku(board)); |
| 75 | + } |
| 76 | + |
| 77 | + /** |
| 78 | + * 解题思路: |
| 79 | + * 首先必须理解有效数独的定义 |
| 80 | + * 要知道是否满足数独的要求,肯定所有的点都得遍历到,所以得双重遍历 |
| 81 | + * 在双重遍历中得匹配之前的遍历结果,看是否有重复的数字,考虑用hashmap报错遍历结果 |
| 82 | + * hashmap中存储的key是有三种:行的index+数字、列的index+数字、3*3宫格的index+数字 |
| 83 | + * |
| 84 | + * 提交结果: |
| 85 | + * 执行用时 : 16 ms, 在Valid Sudoku的Java提交中击败了62.19% 的用户 |
| 86 | + * 内存消耗 : 42.4 MB, 在Valid Sudoku的Java提交中击败了81.42% 的用户 |
| 87 | + * 结果并不是很出色,看了其他优秀解法,发现他们存储是固定大小三个数组, |
| 88 | + * 仔细想想也是,HashMap虽然查找是O(1),但是扩容的时候是有时间消耗的,对于这种固定大小的可以考虑用数组进行优化 |
| 89 | + * 官方解题,是分了三个HashMap,估计也是为了减少扩容的时间消耗吧 |
| 90 | + * |
| 91 | + * @param board |
| 92 | + * @return |
| 93 | + */ |
| 94 | + public boolean isValidSudoku(char[][] board) { |
| 95 | + HashMap<String, Boolean> map = new HashMap<>(); |
| 96 | + for (int i = 0; i < board.length; i++) { |
| 97 | + for (int j = 0; j < board[i].length; j++) { |
| 98 | + char num = board[i][j]; |
| 99 | + if (num == '.') continue; |
| 100 | + String rowKey = i + "row" + num; |
| 101 | + String colKey = j + "col" + num; |
| 102 | + int groupIndex = i / 3 + j / 3 * 3; |
| 103 | + String groupKey = groupIndex + "group" + num; |
| 104 | + //寻找是否有重复的数字 |
| 105 | + if (map.getOrDefault(rowKey, false) |
| 106 | + || map.getOrDefault(colKey, false) |
| 107 | + || map.getOrDefault(groupKey, false)) { |
| 108 | + return false; |
| 109 | + } |
| 110 | + //更新遍历记录 |
| 111 | + map.put(rowKey, true); |
| 112 | + map.put(colKey, true); |
| 113 | + map.put(groupKey, true); |
| 114 | + } |
| 115 | + } |
| 116 | + return true; |
| 117 | + } |
| 118 | +} |
0 commit comments