4 つの 境目を 狭めながら、 行列を 渦巻きの順に読む
m×n の
海外で定番の問題リスト 4 本には入っていません
問題
倉庫のmatrix で
- どの
区画も ちょうど 1 回ずつ 通ります。 答えの 長さは m × n です - m と n は
どちらも 1 以上 10 以下、 値は どれも -100 以上 100 以下です
入力と出力の例
例 1
外側の
例 2
1 列だけなら、
例 3
縦に
面接での聞かれ方
面接では、
- 「行列を
渦巻きの 順で 返してください」 - 正方形の
例で 説明された あと、 「行と 列の 数が 違う ときも 動きますか?」と 確かめられます - 書き終えた
あとに 「1 行だけ、 1 列だけの ときを たどってください」と 言われる ことがあります
考え方は
ヒント
まだ開いていません
付箋は 4 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3
ヒント 4答えに近い
アルゴリズムのチートシートの「配列と文字列」に、
関わる学び
配列と
まず 考える手順
段 1
通った
段 2
まだtop、bottom、left、right の 4 つだけを
段 3
1 周を 4 つのtop を 1 つ下げ、right を 1 つ左へ、bottom を 1 つ上げ、left を 1 つ右へ
段 4
下のleft > right に
解答
Python
Python
def spiral_order(matrix):
top = 0
bottom = len(matrix) - 1
left = 0
right = len(matrix[0]) - 1
out = []
while top <= bottom and left <= right:
for j in range(left, right + 1):
out.append(matrix[top][j])
top += 1
for i in range(top, bottom + 1):
out.append(matrix[i][right])
right -= 1
if top <= bottom:
for j in range(
right, left - 1, -1
):
out.append(matrix[bottom][j])
bottom -= 1
if left <= right:
for i in range(
bottom, top - 1, -1
):
out.append(matrix[i][left])
left += 1
return outJavaScript
JavaScript
function spiralOrder(matrix) {
let top = 0;
let bottom = matrix.length - 1;
let left = 0;
let right = matrix[0].length - 1;
const out = [];
while (
top <= bottom &&
left <= right
) {
for (let j = left; j <= right; j++) {
out.push(matrix[top][j]);
}
top++;
for (let i = top; i <= bottom; i++) {
out.push(matrix[i][right]);
}
right--;
if (top <= bottom) {
for (let j = right; j >= left; j--) {
out.push(matrix[bottom][j]);
}
bottom--;
}
if (left <= right) {
for (let i = bottom; i >= top; i--) {
out.push(matrix[i][left]);
}
left++;
}
}
return out;
}Go
Go
func spiralOrder(
matrix [][]int,
) []int {
top, bottom := 0, len(matrix)-1
left := 0
right := len(matrix[0]) - 1
out := []int{}
for top <= bottom && left <= right {
for j := left; j <= right; j++ {
out = append(out, matrix[top][j])
}
top++
for i := top; i <= bottom; i++ {
out = append(out, matrix[i][right])
}
right--
if top <= bottom {
for j := right; j >= left; j-- {
v := matrix[bottom][j]
out = append(out, v)
}
bottom--
}
if left <= right {
for i := bottom; i >= top; i-- {
out = append(out, matrix[i][left])
}
left++
}
}
return out
}上の
計算量
- 時間は O(m × n) です。
どの 区画も 1 回ずつ読みます - 追加の
記憶は、 答えの 並びを 除けば O(1) です。 4 つの 境目だけを持ちます - 印を
付ける 書き方は、 時間は 同じですが、 印の 分の O(m × n) の 記憶が要ります
よく ある間違い
- 下の
行と 左の 列の 前に 確かめない。 例 2 では、 右の 列を 読み終えた あと left > rightなので、確かめずに 左の 列を 下から 上へ 読むと、 5 を もう 一度足してしまいます。 1 行だけ 残った 場合も、 下の 行で 同じことが起きます - 境目を
狭める 順を 間違える。 上の 行を 読んだ あとに topを下げずに 右の 列を 読むと、 右上の 角を 2 回読みます。 1 辺読んだら すぐ狭めます - 正方形だけで
確かめる。 正方形では 偶然 うまく いく 書き方 でも、 例 1 や 例 3 のような 長方形で 外れる ことがあります。 縦長、 横長、 1 行、 1 列で 手を 動かして 確かめます
解答を動かした版 Python 3.14.7Node.js 24.22.1Go 1.24.2確認日 2026年11月8日
面接での 話し方の例
書き始める
「まだ
読んでいない 所は いつも 長方形なので、 上、 下、 左、 右の 4 つの 境目を 持ちます。 上の 行、 右の 列、 下の 行、 左の 列の 順に 読み、 1 辺読むたびに その 境目を 1 つ内側へ 狭めます。 下の 行と 左の 列は、 読む前に まだ 残っているかを 確かめます。 時間は O(m × n)、 追加の 記憶は O(1) です。」
書き終えたら、
「例 3 を
たどります。 上の 行の 1、 2 を 読んで topが 1、右の 列の 4、 6、 8 を 読んで rightが 0 です。下の 行は 7 を 読んで bottomが 2、左の 列は 下から 5、 3 を 読みます。 leftが 1 になって rightを超えたので 終わり、 [1, 2, 4, 6, 8, 7, 5, 3]です。」