|
| 1 | +(* |
| 2 | +Determine if a 9 x 9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules: |
| 3 | +
|
| 4 | +Each row must contain the digits 1-9 without repetition. |
| 5 | +Each column must contain the digits 1-9 without repetition. |
| 6 | +Each of the nine 3 x 3 sub-boxes of the grid must contain the digits 1-9 without repetition. |
| 7 | +Note: |
| 8 | +
|
| 9 | +A Sudoku board (partially filled) could be valid but is not necessarily solvable. |
| 10 | +Only the filled cells need to be validated according to the mentioned rules. |
| 11 | +
|
| 12 | +Example 1: |
| 13 | +
|
| 14 | +Input: board = |
| 15 | +[["5","3",".",".","7",".",".",".","."] |
| 16 | +,["6",".",".","1","9","5",".",".","."] |
| 17 | +,[".","9","8",".",".",".",".","6","."] |
| 18 | +,["8",".",".",".","6",".",".",".","3"] |
| 19 | +,["4",".",".","8",".","3",".",".","1"] |
| 20 | +,["7",".",".",".","2",".",".",".","6"] |
| 21 | +,[".","6",".",".",".",".","2","8","."] |
| 22 | +,[".",".",".","4","1","9",".",".","5"] |
| 23 | +,[".",".",".",".","8",".",".","7","9"]] |
| 24 | +Output: true |
| 25 | +Example 2: |
| 26 | +
|
| 27 | +Input: board = |
| 28 | +[["8","3",".",".","7",".",".",".","."] |
| 29 | +,["6",".",".","1","9","5",".",".","."] |
| 30 | +,[".","9","8",".",".",".",".","6","."] |
| 31 | +,["8",".",".",".","6",".",".",".","3"] |
| 32 | +,["4",".",".","8",".","3",".",".","1"] |
| 33 | +,["7",".",".",".","2",".",".",".","6"] |
| 34 | +,[".","6",".",".",".",".","2","8","."] |
| 35 | +,[".",".",".","4","1","9",".",".","5"] |
| 36 | +,[".",".",".",".","8",".",".","7","9"]] |
| 37 | +Output: false |
| 38 | +Explanation: Same as Example 1, except with the 5 in the top left corner being modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid. |
| 39 | + |
| 40 | +Constraints: |
| 41 | +
|
| 42 | +board.length == 9 |
| 43 | +board[i].length == 9 |
| 44 | +board[i][j] is a digit 1-9 or '.'. |
| 45 | +*) |
| 46 | + |
| 47 | +let char_to_int (c : char) : int = |
| 48 | + match c with |
| 49 | + | '1' -> 1 |
| 50 | + | '2' -> 2 |
| 51 | + | '3' -> 3 |
| 52 | + | '4' -> 4 |
| 53 | + | '5' -> 5 |
| 54 | + | '6' -> 6 |
| 55 | + | '7' -> 7 |
| 56 | + | '8' -> 8 |
| 57 | + | '9' -> 9 |
| 58 | + | _ -> assert false |
| 59 | + |
| 60 | +(* |
| 61 | +time O(n) |
| 62 | +space O(1) |
| 63 | +*) |
| 64 | +let is_valid_sudoku (board : char array array) : bool = |
| 65 | + assert (Array.length board = Array.length board.(0)); |
| 66 | + |
| 67 | + let board_size = Array.length board in |
| 68 | + |
| 69 | + let valid = ref true in |
| 70 | + |
| 71 | + let row_or_column = ref 0 in |
| 72 | + |
| 73 | + (* Check for duplicated numbers in 3x3 grid *) |
| 74 | + let grid_size = 3 in |
| 75 | + |
| 76 | + let grid_row_starts_at = ref 0 in |
| 77 | + |
| 78 | + let grid_column_starts_at = ref 0 in |
| 79 | + |
| 80 | + (* time O(n) *) |
| 81 | + while !valid && !grid_row_starts_at <= 6 do |
| 82 | + while !valid && !grid_column_starts_at <= 6 do |
| 83 | + let count = Array.make 9 0 in |
| 84 | + |
| 85 | + for i = 0 to 2 do |
| 86 | + for j = 0 to 2 do |
| 87 | + let value = |
| 88 | + board.(!grid_row_starts_at + i).(!grid_column_starts_at + j) |
| 89 | + in |
| 90 | + if value != '.' then ( |
| 91 | + let index = char_to_int value - 1 in |
| 92 | + count.(index) <- count.(index) + 1; |
| 93 | + |
| 94 | + if count.(index) > 1 then valid := false) |
| 95 | + done |
| 96 | + done; |
| 97 | + |
| 98 | + grid_column_starts_at := !grid_column_starts_at + grid_size |
| 99 | + done; |
| 100 | + |
| 101 | + grid_row_starts_at := !grid_row_starts_at + grid_size; |
| 102 | + grid_column_starts_at := 0 |
| 103 | + done; |
| 104 | + |
| 105 | + (* time O(n) *) |
| 106 | + while !valid && !row_or_column < board_size do |
| 107 | + (* Check for duplicated numbers in the current row *) |
| 108 | + let count = Array.make 9 0 in |
| 109 | + |
| 110 | + for i = 0 to board_size - 1 do |
| 111 | + (* A value from 1 to 9. *) |
| 112 | + let value = board.(!row_or_column).(i) in |
| 113 | + if value != '.' then ( |
| 114 | + let index = char_to_int value - 1 in |
| 115 | + count.(index) <- count.(index) + 1; |
| 116 | + if count.(index) > 1 then valid := false) |
| 117 | + done; |
| 118 | + |
| 119 | + (* Check for duplicated numbers in the current column *) |
| 120 | + let count = Array.make 9 0 in |
| 121 | + |
| 122 | + (* time O(n) *) |
| 123 | + for i = 0 to board_size - 1 do |
| 124 | + (* A value from 1 to 9. *) |
| 125 | + let value = board.(i).(!row_or_column) in |
| 126 | + if value != '.' then ( |
| 127 | + let index = char_to_int value - 1 in |
| 128 | + count.(index) <- count.(index) + 1; |
| 129 | + if count.(index) > 1 then valid := false) |
| 130 | + done; |
| 131 | + |
| 132 | + row_or_column := !row_or_column + 1 |
| 133 | + done; |
| 134 | + |
| 135 | + !valid |
| 136 | + |
| 137 | +let () = |
| 138 | + Printf.printf "example 1: should be true %b\n" |
| 139 | + (is_valid_sudoku |
| 140 | + [| |
| 141 | + [| '5'; '3'; '.'; '.'; '7'; '.'; '.'; '.'; '.' |]; |
| 142 | + [| '6'; '.'; '.'; '1'; '9'; '5'; '.'; '.'; '.' |]; |
| 143 | + [| '.'; '9'; '8'; '.'; '.'; '.'; '.'; '6'; '.' |]; |
| 144 | + [| '8'; '.'; '.'; '.'; '6'; '.'; '.'; '.'; '3' |]; |
| 145 | + [| '4'; '.'; '.'; '8'; '.'; '3'; '.'; '.'; '1' |]; |
| 146 | + [| '7'; '.'; '.'; '.'; '2'; '.'; '.'; '.'; '6' |]; |
| 147 | + [| '.'; '6'; '.'; '.'; '.'; '.'; '2'; '8'; '.' |]; |
| 148 | + [| '.'; '.'; '.'; '4'; '1'; '9'; '.'; '.'; '5' |]; |
| 149 | + [| '.'; '.'; '.'; '.'; '8'; '.'; '.'; '7'; '9' |]; |
| 150 | + |]); |
| 151 | + |
| 152 | + Printf.printf "example 2: should be false %b\n" |
| 153 | + (is_valid_sudoku |
| 154 | + [| |
| 155 | + [| '8'; '3'; '.'; '.'; '7'; '.'; '.'; '.'; '.' |]; |
| 156 | + [| '6'; '.'; '.'; '1'; '9'; '5'; '.'; '.'; '.' |]; |
| 157 | + [| '.'; '9'; '8'; '.'; '.'; '.'; '.'; '6'; '.' |]; |
| 158 | + [| '8'; '.'; '.'; '.'; '6'; '.'; '.'; '.'; '3' |]; |
| 159 | + [| '4'; '.'; '.'; '8'; '.'; '3'; '.'; '.'; '1' |]; |
| 160 | + [| '7'; '.'; '.'; '.'; '2'; '.'; '.'; '.'; '6' |]; |
| 161 | + [| '.'; '6'; '.'; '.'; '.'; '.'; '2'; '8'; '.' |]; |
| 162 | + [| '.'; '.'; '.'; '4'; '1'; '9'; '.'; '.'; '5' |]; |
| 163 | + [| '.'; '.'; '.'; '.'; '8'; '.'; '.'; '7'; '9' |]; |
| 164 | + |]); |
| 165 | + |
| 166 | + Printf.printf "example 3: should be false %b\n" |
| 167 | + (is_valid_sudoku |
| 168 | + [| |
| 169 | + [| '5'; '3'; '.'; '.'; '7'; '.'; '.'; '.'; '.' |]; |
| 170 | + [| '6'; '.'; '.'; '1'; '9'; '5'; '.'; '.'; '.' |]; |
| 171 | + [| '.'; '9'; '8'; '.'; '.'; '.'; '.'; '6'; '.' |]; |
| 172 | + [| '8'; '.'; '.'; '.'; '6'; '2'; '.'; '.'; '3' |]; |
| 173 | + [| '4'; '.'; '.'; '.'; '.'; '3'; '.'; '.'; '1' |]; |
| 174 | + [| '7'; '8'; '.'; '.'; '2'; '.'; '.'; '.'; '6' |]; |
| 175 | + [| '.'; '6'; '.'; '.'; '.'; '.'; '2'; '8'; '.' |]; |
| 176 | + [| '.'; '.'; '.'; '4'; '1'; '9'; '.'; '.'; '5' |]; |
| 177 | + [| '.'; '.'; '.'; '.'; '8'; '.'; '.'; '7'; '9' |]; |
| 178 | + |]) |
0 commit comments