アルゴリズム概要

O(log n)
時間計算量
O(1)
空間計算量
≤ 31回
最大反復数
整数演算
浮動小数誤差ゼロ

問題文

非負整数 x を受け取り、 floor(√x)(小数点以下切り捨て)を返す。
math.sqrt**pow(x, 0.5) などの組み込み指数演算は使用禁止

制約

  • 0 ≤ x ≤ 2³¹ - 1(非負整数)
  • 🚫 math.sqrt 禁止
  • 🚫 ** 演算子 禁止
  • 🚫 pow(x, 0.5) 禁止

入出力例

EXAMPLE 1
Input: x = 4
Output: 2
√4 = 2.0 → 2(完全平方数)
EXAMPLE 2
Input: x = 8
Output: 2
√8 ≈ 2.828 → 切り捨て 2

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

コード実装

class Solution:
    def mySqrt(self, x: int) -> int:
        # エッジケース: x=0, x=1 は即リターン
        if x < 2:
            return x

        # 探索範囲: [1, x // 2]
        # 根拠: x >= 2 のとき floor(√x) <= x // 2 が常に成立
        low: int = 1
        high: int = x >> 1  # ビットシフトで x // 2(CPython 最速)

        # Loop Invariant:
        #   (low - 1)^2 <= x  かつ  (high + 1)^2 > x
        # → ループ終了時: high = floor(√x)
        while low <= high:
            mid: int = (low + high) >> 1  # 中点計算
            sq:  int = mid * mid          # Python int は任意精度 → オーバーフローなし

            if sq == x:
                return mid       # 完全平方数: 即リターン
            elif sq < x:
                low = mid + 1    # mid が小さすぎる → 下限を引き上げ
            else:
                high = mid - 1   # mid が大きすぎる → 上限を引き下げ

        # ループ終了後: high = floor(√x)
        return high

処理フローチャート

graph TD
    Start["開始: mySqrt(x)"]
    CheckEdge{"x < 2?"}
    ReturnX["return x"]
    Init["初期化: low=1, high=x/2"]
    LoopCheck{"low <= high?"}
    ReturnHigh["return high"]
    CalcMid["中点計算
mid=(low+high)/2"] Compare{"sq vs x"} ReturnMid["return mid"] UpdateLow["low=mid+1"] UpdateHigh["high=mid-1"] End["終了"] Start --> CheckEdge CheckEdge -->|Yes| ReturnX CheckEdge -->|No| Init Init --> LoopCheck LoopCheck -->|No| ReturnHigh LoopCheck -->|Yes| CalcMid CalcMid --> Compare Compare -->|Equal| ReturnMid Compare -->|Less| UpdateLow Compare -->|Greater| UpdateHigh UpdateLow --> LoopCheck UpdateHigh --> LoopCheck ReturnX --> End ReturnMid --> End ReturnHigh --> End style Start fill:#d1fae5,stroke:#10b981,stroke-width:3px style End fill:#d1fae5,stroke:#10b981,stroke-width:3px style CheckEdge fill:#fef3c7,stroke:#f59e0b,stroke-width:2px style LoopCheck fill:#fef3c7,stroke:#f59e0b,stroke-width:2px style Compare fill:#fef3c7,stroke:#f59e0b,stroke-width:2px style ReturnX fill:#d1fae5,stroke:#059669,stroke-width:2px style ReturnMid fill:#d1fae5,stroke:#059669,stroke-width:2px style ReturnHigh fill:#d1fae5,stroke:#059669,stroke-width:2px style Init fill:#e0f2fe,stroke:#0284c7,stroke-width:2px style CalcMid fill:#e0f2fe,stroke:#0284c7,stroke-width:2px style UpdateLow fill:#e0f2fe,stroke:#0284c7,stroke-width:2px style UpdateHigh fill:#fee2e2,stroke:#dc2626,stroke-width:2px

フローの説明:
1. エッジケース判定: x < 2 の場合は x をそのまま返す(0→0, 1→1)
2. 探索範囲初期化: low=1, high=x>>1(x/2)で探索上限を半分に削減
3. 二分探索ループ: low>high になるまで mid=(low+high)>>1 を計算
4. 三方比較: sq==x(即リターン)/ sq<x(low引き上げ)/ sq>x(high引き下げ)
5. ループ終了: high = floor(√x) が確定 → return high
── 紫の破線: ループバック(探索範囲を狭めて次のイテレーションへ)

計算量分析

O(log n)
時間計算量
x ≤ 2³¹ で最大 31 回のイテレーション
探索範囲が毎ステップ半減する
O(1)
空間計算量
low / high / mid / sq の
スカラー変数のみ。ヒープ確保ゼロ
アプローチ 時間 空間 誤差 保守性 選択
線形探索 O(√n) O(1) なし ★★★ ✗ 遅い
二分探索 ✅ O(log n) O(1) なし ★★★ ✅ 最適
ニュートン法 O(log log n) O(1) float誤差 ★★☆ △ 誤差リスク
math.isqrt() O(log n) O(1) なし ★★★ 🚫 禁止

Loop Invariant(ループ不変条件)

// ループの各反復前に成立:
(low - 1)² ≤ x ← low より小さい値の二乗は x 以下
(high + 1)² > x ← high より大きい値の二乗は x より大きい
// → ループ終了時: high = floor(√x) が数学的に保証される