Set Matrix Zeroes

O(1) Space Complexity Algorithm - Python Implementation

アルゴリズム概要

問題定義

m×n の整数行列が与えられたとき、要素が0の場合、その行と列の全要素を0に設定する。 この操作を in-place(元の配列を直接変更)で行う必要がある。

制約条件

  • 行列サイズ: 1 ≤ m, n ≤ 200
  • 要素範囲: -2³¹ ≤ matrix[i][j] ≤ 2³¹ - 1
  • Follow-up: O(1) 空間計算量で解決できるか?

解法のキーアイデア

第一行と第一列をフラグとして活用し、追加メモリを使わずにO(1)空間計算量を実現する。 元の第一行・第一列に0があるかどうかを事前に記録し、最後に適切に処理する。

ステップバイステップ解説

1
境界状態の保存

第一行と第一列に元々0が含まれているかチェックし、この情報を変数に保存する。

first_row_zero = any(matrix[0][j] == 0 for j in range(n))
first_col_zero = any(matrix[i][0] == 0 for i in range(m))
2
0要素の検出とフラグ設定

内部要素(第一行・列を除く)を走査し、0を見つけた場合、対応する第一行・列の位置に0を設定(フラグ)する。

for i in range(1, m):
    for j in range(1, n):
        if matrix[i][j] == 0:
            matrix[i][0] = 0  # 行フラグ
            matrix[0][j] = 0  # 列フラグ
3
フラグに基づく0設定

設定されたフラグを確認し、対応する行・列の内部要素を0に設定する。

for i in range(1, m):
    for j in range(1, n):
        if matrix[i][0] == 0 or matrix[0][j] == 0:
            matrix[i][j] = 0
4
境界要素の処理

保存しておいた境界状態に基づいて、第一行・第一列を適切に0に設定する。

if first_row_zero:
    for j in range(n):
        matrix[0][j] = 0

if first_col_zero:
    for i in range(m):
        matrix[i][0] = 0

Python実装

競技プログラミング向け実装
class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Set Matrix Zeroes - O(1) Space Solution

        Time Complexity: O(mn)
        Space Complexity: O(1)
        """
        if not matrix or not matrix[0]:
            return

        m, n = len(matrix), len(matrix[0])

        # 第一行・第一列の元の状態チェック
        first_row_zero = any(matrix[0][j] == 0 for j in range(n))
        first_col_zero = any(matrix[i][0] == 0 for i in range(m))

        # 内部要素の0を検出してフラグ設定
        for i in range(1, m):
            for j in range(1, n):
                if matrix[i][j] == 0:
                    matrix[i][0] = 0  # 行フラグ
                    matrix[0][j] = 0  # 列フラグ

        # フラグに基づいて内部要素を0に設定
        for i in range(1, m):
            for j in range(1, n):
                if matrix[i][0] == 0 or matrix[0][j] == 0:
                    matrix[i][j] = 0

        # 第一行の処理
        if first_row_zero:
            for j in range(n):
                matrix[0][j] = 0

        # 第一列の処理
        if first_col_zero:
            for i in range(m):
                matrix[i][0] = 0
業務開発向け実装(型安全・エラーハンドリング)
from typing import List, Any

class Solution:
    def set_zeroes_production(self, matrix: List[List[int]]) -> None:
        """
        業務開発向け実装(型安全・エラーハンドリング重視)

        Args:
            matrix: 2D integer matrix to modify in-place

        Raises:
            TypeError: 入力型が不正な場合
            ValueError: 入力値が制約を満たさない場合

        Time Complexity: O(mn)
        Space Complexity: O(1)
        """
        # 入力検証
        self._validate_matrix_input(matrix)

        # エッジケース処理
        if self._is_empty_matrix(matrix):
            return

        m, n = len(matrix), len(matrix[0])

        try:
            # 境界状態の分析
            first_row_zero = any(matrix[0][j] == 0 for j in range(n))
            first_col_zero = any(matrix[i][0] == 0 for i in range(m))

            # フラグマーキング
            for i in range(1, m):
                for j in range(1, n):
                    if matrix[i][j] == 0:
                        matrix[i][0] = 0
                        matrix[0][j] = 0

            # フラグ適用
            for i in range(1, m):
                for j in range(1, n):
                    if matrix[i][0] == 0 or matrix[0][j] == 0:
                        matrix[i][j] = 0

            # 境界処理
            if first_row_zero:
                for j in range(n):
                    matrix[0][j] = 0

            if first_col_zero:
                for i in range(m):
                    matrix[i][0] = 0

        except Exception as e:
            raise RuntimeError(f"Algorithm execution failed: {e}") from e

    def _validate_matrix_input(self, matrix: Any) -> None:
        """型安全な入力検証"""
        if not isinstance(matrix, list):
            raise TypeError("Matrix must be a list")

        if not matrix:
            return  # 空行列は有効

        if not isinstance(matrix[0], list):
            raise TypeError("Matrix must be a 2D list")

        # 矩形チェック・型チェック・制約チェック
        expected_cols = len(matrix[0])
        for i, row in enumerate(matrix):
            if not isinstance(row, list) or len(row) != expected_cols:
                raise ValueError(f"Matrix must be rectangular")

            for j, element in enumerate(row):
                if not isinstance(element, int):
                    raise TypeError(f"Element at [{i}][{j}] must be integer")

                if element < -2**31 or element >= 2**31:
                    raise ValueError(f"Element out of 32-bit range")

    def _is_empty_matrix(self, matrix: List[List[int]]) -> bool:
        """空行列判定"""
        return not matrix or not matrix[0]

ビジュアルデモ

初期状態
ステップ1: 境界状態の確認

現在のステップ

デモを開始するには「デモ実行」ボタンをクリックしてください。

計算量解析

時間計算量
最良・平均・最悪ケース O(mn)
境界チェック O(m + n)
フラグマーキング O(mn)
ゼロ設定 O(mn)
空間計算量
追加メモリ使用量 O(1)
境界フラグ 2変数
ループ変数 定数個
総評 最適

最適化のポイント

CPython最適化

組み込み関数 any()range() を活用してC実装の恩恵を受ける。

メモリ局所性

行優先のアクセスパターンでキャッシュ効率を最大化し、実際の実行速度を向上させる。

In-place操作

追加メモリを一切使わず、元の配列のみを使用してO(1)空間計算量を実現。

アルゴリズムの評価

A+
時間効率
A+
空間効率
A
実装難易度
A+
実用性