集合で 数独の 盤に 同じ 数字の 重なりが 無いか確かめる
途中まで
海外で定番の問題リスト 4 本には入っていません
問題
数独のboard でboard[r] は"1" から "9" の"." です。
入っているtrue、false を
-
どの
行にも、 同じ 数字が 2 回入っていない -
どの
列にも、 同じ 数字が 2 回入っていない -
盤を
縦横 3 つずつに 割った 9 個の 3 × 3 の 箱の どれにも、 同じ 数字が 2 回入っていない -
空いた
マスは 数えません。 空いた マスに 数字を 入れて 最後まで 解けるか どうかは 問いません -
boardは必ず 9 本で、 どの 文字列も 9 文字です。 文字は "1"から"9"と"."だけです
入力と出力の例
例 1
入っている
例 2
左上のfalse です。
例 3
例 1 の
面接での聞かれ方
面接では、
- 「この
数独の 盤が、 決まりを 破っていないか 確かめてください」 - 「解けるか
どうかも 見ますか?」と、 範囲を 自分から 確かめるかを 見られます - 書き終えた
あとに 「盤を 1 回だけなめて 確かめられますか?」と 広げられる こともあります
確かめるのは、
ヒント
まだ開いていません
付箋は 4 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3
ヒント 4答えに近い
アルゴリズムのチートシートの「ハッシュマップ」に、
関わる学び
ハッシュは、
まず 考える手順
段 1
決まりを 3 つに
段 2
素直に
段 3
マスを 1 r // 3 * 3 + c // 3 で 0 から 8 に
段 4
印をfalse を
解答
Python
Python
def valid_sudoku(board):
seen = set()
for i in range(81):
r, c = divmod(i, 9)
v = board[r][c]
if v == ".":
continue
b = r // 3 * 3 + c // 3
keys = (("row", r, v),
("col", c, v),
("box", b, v))
for k in keys:
if k in seen:
return False
seen.add(k)
return TrueJavaScript
JavaScript
function validSudoku(
board
) {
const seen = new Set();
for (let i = 0; i < 81; i++) {
const r = Math.floor(i / 9);
const c = i % 9;
const v = board[r][c];
if (v === ".") continue;
const b =
Math.floor(r / 3) * 3 +
Math.floor(c / 3);
const keys = [
`row${r}-${v}`,
`col${c}-${v}`,
`box${b}-${v}`,
];
for (const k of keys) {
if (seen.has(k)) {
return false;
}
seen.add(k);
}
}
return true;
}Go
Go
func validSudoku(
board []string,
) bool {
var rows [9][10]bool
var cols [9][10]bool
var boxes [9][10]bool
for i := 0; i < 81; i++ {
r, c := i/9, i%9
if board[r][c] == '.' {
continue
}
d := board[r][c] - '0'
b := r/3*3 + c/3
if rows[r][d] ||
cols[c][d] ||
boxes[b][d] {
return false
}
rows[r][d] = true
cols[c][d] = true
boxes[b][d] = true
}
return true
}81 マスを 1 本のi から
計算量
- 時間は O(1) です。
盤は いつも 81 マスで、 1 マスに つき印を 3 つ 見るだけです。 盤の 一辺を n とした 広い 数独なら O(n²) です - 使う
記憶も O(1) です。 印は 多くても 81 × 3 個です - 段 2 の
行、 列、 箱を 別々に 確かめる 書き方も 同じ O(1) ですが、 盤を 3 回なめます
よく ある間違い
- 空いた
マスの "."も数字と 同じに数える。 空きは 1 つの 行に 何個でも あるので、 すぐ 重なりと 見なして falseを返します。 数字の マスだけを見ます - 行と
列と 箱の 印を 区別しない。 「行 2 に 5」と 「列 2 に 5」が 同じ印に なり、 例 1 のような 正しい 盤でも falseを返します。 印に row、col、boxのような区別を入れます - 箱の
番号を r // 3 + c // 3と書く。 左上から 1 つ右の箱と 1 つ下の 箱が 同じ 番号 1 に なります。 行の 商に 3 を 掛けてから 列の 商を足します - 最後まで
解けるかまで 確かめようとする。 問いの 範囲を 広げてしまい、 時間内に 書き終わりません。 範囲は 最初に 確かめます
解答を動かした版 Python 3.14.7Node.js 24.22.1Go 1.24.2確認日 2026年11月8日
面接での 話し方の例
書き始める
「確かめるのは
入っている 数字の 重なりだけで、 解けるか どうかは 見ない、で 合っていますか。 マスを 1 回ずつ 見て、 数字が あれば、 行、 列、 箱の 3 つの 印を 作って 集合に 入れます。 同じ 印が 2 回出たら 重なりです。 箱の 番号は、 行と 列を それぞれ 3 で 割った 商から 0 から 8 に 振ります。 盤の 大きさが 決まっているので、 時間も 記憶も 一定です。」
書き終えたら、
「例 2 で
たどります。 いちばん上の 行の 左端の 4 で、 行 0、 列 0、 箱 0 の 印を 入れます。 2 行目の 左から 3 番目の 4 は、 行 1、 列 2 なので 行と 列の 印は 新しいですが、 箱は 0 で、 箱 0 に 4 の 印は もう あります。 ここで falseを返します。」