バックトラックで互いに取り合わない n 個のクイーンの置き方を全部集める

n 行 n 列の盤に、縦・横・斜めのどれでも取り合わないように n 個のクイーンを置く方法を全部集めます。1 行に 1 個ずつ置き、使った列と 2 本の斜めを集合で覚えて、置けない所を O(1) で飛ばす練習です。

海外で定番の問題リスト 4 本には入っていません

問題

チェスのクイーンは、縦、横、斜めのどの向きにも、何マスでも進めます。整数 n を受け取ります。n 行 n 列の盤に n 個のクイーンを、どの 2 個も同じ行、同じ列、同じ斜めの線に並ばないように置く方法を全部集めて、並びにして返す関数を書いてください。

  • 1 つの置き方は、盤の各行を文字列にした n 個の並びで表します。クイーンのあるマスは "Q"、無いマスは "." です
  • 置き方どうしの順は、1 行目のクイーンの列が左にある方を先にします。1 行目が同じなら 2 行目の列が左にある方を先に、と下へ続けて比べます
  • 置き方が無ければ、空の並び [] を返します
  • n は 1 以上 9 以下です

入力と出力の例

例 1

4 行 4 列では、置き方は 2 つです。1 行目の列が 2 列目の物が先、3 列目の物が後です。

n = 4
[[".Q..", "...Q", "Q...", "..Q."], ["..Q.", "Q...", "...Q", ".Q.."]]

例 2

6 行 6 列では、置き方は 4 つです。1 行目のクイーンが左にある物から順に並びます。

n = 6
[[".Q....", "...Q..", ".....Q", "Q.....", "..Q...", "....Q."], ["..Q...", ".....Q", ".Q....", "....Q.", "Q.....", "...Q.."], ["...Q..", "Q.....", "....Q.", ".Q....", ".....Q", "..Q..."], ["....Q.", "..Q...", "Q.....", ".....Q", "...Q..", ".Q...."]]

例 3

3 行 3 列では、どう置いても 2 個が取り合います。置き方はありません。

n = 3
[]

面接での聞かれ方

面接では、短く次のように渡されることが多いです。

  • 「n クイーン問題を解いて、全部の置き方を返してください」
  • 書き終えると「置けるかどうかの確かめは、何でしていますか? 毎回盤を全部見ていませんか?」と聞かれます
  • 「置き方の数だけを返すなら、どこを変えますか?」と、続けて聞かれることがあります

盤の表し方と返す順を最初に確かめておくと、答えを 1 つに決められます。

ヒント

まだ開いていません

付箋は 4 枚。下の段ほど答えに近づきます

  1. ヒント 2

  2. ヒント 3

  3. ヒント 4答えに近い

アルゴリズムのチートシートの「再帰と木」に、この型の要点を表とコードでまとめています。

再帰は、同じ形の小さい問題に分けて自分を呼ぶ書き方です。木の深さや、全部の組み合わせを数える問題で使います。

main.py
def n_queens(n: int) -> list[list[str]]:
    """
    Goal: 何を返すか

    idea1: まず思いつく案
    -> runtime: O(?)  space: O(?)

    idea2: もっと速い案
    -> runtime: O(?)  space: O(?)

    edge case: 空、1 つだけ、など
    """
    # ここに書きます
    pass


# 「実行」を押すと、この行の結果が出ます
print(n_queens(4))

できているか「例で確かめる」を押すと、問題の例を全部この関数に渡して、通ったかをここに出します