Unix Path Simplifier

Technical Analysis & Algorithm Visualization

Problem Overview

The Unix Path Simplifier transforms absolute Unix-style paths into their canonical form by processing path components and applying Unix filesystem navigation rules.

1

Input Validation

Validate absolute path format and constraints

2

Component Split

Split path by '/' separator into components

3

Stack Processing

Process each component using stack operations

4

Path Reconstruction

Build canonical path from stack contents

Algorithm Analysis

Core Implementation (JavaScript)

JavaScript
/**
 * @param {string} path
 * @return {string}
 */
var simplifyPath = function (path) {
  // 1. 入力検証(LeetCode環境では制約保証済み)
  if (!path || path[0] !== "/") return "/";

  // 2. パス構成要素分割(連続スラッシュも自動処理)
  const components = path.split("/");

  // 3. スタック初期化(事前サイズ確保でV8最適化)
  const stack = [];
  stack.length = 0; // V8: 配列長明示でメモリ最適化

  // 4. 各構成要素処理(効率的ループ)
  for (let i = 0; i < components.length; i++) {
    const component = components[i];

    // 空文字列・現在ディレクトリ指定をスキップ
    if (component === "" || component === ".") {
      continue;
    }

    // 親ディレクトリ指定処理
    if (component === "..") {
      // ルート以外で親に移動
      if (stack.length > 0) {
        stack.pop(); // V8最適化: length更新自動
      }
    } else {
      // 有効なディレクトリ/ファイル名追加
      stack.push(component);
    }
  }

  // 5. 正規化パス構築
  // ルートディレクトリ特別処理
  if (stack.length === 0) {
    return "/";
  }

  // パス結合(効率的文字列生成)
  return "/" + stack.join("/");
};

/**
 * 入力検証ヘルパー(開発環境用)
 * @param {string} path - Unix絶対パス
 * @throws {TypeError} - 不正な型
 * @throws {RangeError} - 制約違反
 */
function validateInput(path) {
  if (typeof path !== "string") {
    throw new TypeError("Path must be a string");
  }
  if (path.length === 0 || path.length > 3000) {
    throw new RangeError("Path length must be 1-3000 characters");
  }
  if (path[0] !== "/") {
    throw new Error("Path must be absolute (start with /)");
  }
}

Processing Rules

Rule 1: Empty Components & Current Directory ('.')

Skip empty strings from consecutive slashes and current directory markers

Rule 2: Parent Directory ('..')

Pop from stack if not at root, otherwise ignore

Rule 3: Valid Names

Push valid directory/file names (including '...', '....', etc.) to stack

Multi-Language Implementation

TypeScript (Type-Safe Version)

TypeScript
// 型定義セクション
type UnixPath = string & { readonly __brand: unique symbol };
type PathComponent = string;
type PathStack = PathComponent[];

// パス構成要素の型定義(Union Types活用)
type SpecialComponent = "." | ".." | "";
type ValidComponent = Exclude;

// アルゴリズムオプション
interface PathSimplifyOptions {
  readonly strictValidation?: boolean;
  readonly preserveTrailingSlash?: boolean;
}

// メイン関数(LeetCode形式)
function simplifyPath(path: string): string {
  // 1. 入力型検証(型ガード)
  if (!isValidUnixPath(path)) {
    return "/";
  }

  // 2. パス構成要素分割(型安全な操作)
  const components: PathComponent[] = path.split("/");

  // 3. 型安全なスタック初期化
  const stack: PathStack = [];

  // 4. 構成要素処理(型ガード活用)
  for (const component of components) {
    processPathComponent(component, stack);
  }

  // 5. 正規化パス構築(型安全)
  return buildCanonicalPath(stack);
}

/**
 * Unix絶対パス判定(型ガード)
 */
function isValidUnixPath(path: string): path is UnixPath {
  return (
    typeof path === "string" &&
    path.length > 0 &&
    path.length <= 3000 &&
    path[0] === "/"
  );
}

/**
 * パス構成要素処理(型安全 + インライン最適化)
 */
function processPathComponent(
  component: PathComponent,
  stack: PathStack
): void {
  // 型ガードによる効率的分岐
  if (isEmptyOrCurrent(component)) {
    return; // 早期リターンでV8最適化
  }

  if (isParentDirectory(component)) {
    handleParentDirectory(stack);
    return;
  }

  // 有効なディレクトリ/ファイル名
  if (isValidComponent(component)) {
    stack.push(component);
  }
}

/**
 * 空文字列・現在ディレクトリ判定(型ガード + インライン化)
 */
function isEmptyOrCurrent(component: PathComponent): component is "" | "." {
  return component === "" || component === ".";
}

/**
 * 親ディレクトリ判定(型ガード)
 */
function isParentDirectory(component: PathComponent): component is ".." {
  return component === "..";
}

/**
 * 有効な構成要素判定(型ガード)
 */
function isValidComponent(
  component: PathComponent
): component is ValidComponent {
  return component !== "" && component !== "." && component !== "..";
}

/**
 * 親ディレクトリ処理(型安全なスタック操作)
 */
function handleParentDirectory(stack: PathStack): void {
  if (stack.length > 0) {
    stack.pop(); // V8最適化: 型情報でlength更新最適化
  }
}

/**
 * 正規化パス構築(型安全な文字列操作)
 */
function buildCanonicalPath(stack: ReadonlyArray): string {
  // ルートディレクトリ特別処理(const assertion活用)
  if (stack.length === 0) {
    return "/" as const;
  }

  // 効率的パス結合(Template Literal活用可能性)
  return `/${stack.join("/")}`;
}

/**
 * 型安全な入力検証(開発環境用)
 */
function validateInput(path: unknown): asserts path is string {
  if (typeof path !== "string") {
    throw new TypeError(`Expected string, got ${typeof path}`);
  }
  if (path.length === 0 || path.length > 3000) {
    throw new RangeError(`Path length must be 1-3000, got ${path.length}`);
  }
  if (!path.startsWith("/")) {
    throw new Error("Path must be absolute (start with /)");
  }
}

/**
 * 高機能版実装(業務開発用、LeetCode提出時は削除)
 */
function simplifyPathAdvanced(
  path: string,
  options: PathSimplifyOptions = {}
): string {
  const { strictValidation = false } = options;

  if (strictValidation) {
    validateInput(path);
  }

  return simplifyPath(path);
}

Python (Production Version)

Python
from collections import deque
from typing import Any, List, Optional

# import sys


class Solution:
    """
    Unix Path Simplifier

    競技プログラミング向けと業務開発向けの2パターンを提供
    """

    def simplifyPath(self, path: str) -> str:
        """
        LeetCode提出用メソッド(競技プログラミング最適化)

        Args:
            path: Unix絶対パス文字列

        Returns:
            正規化された絶対パス

        Time Complexity: O(n)
        Space Complexity: O(n)
        """
        # CPython最適化:dequeによる高速スタック操作
        stack: deque[str] = deque()

        # 組み込み関数split()活用(C実装で高速)
        components = path.split("/")

        # リスト走査(CPythonで最適化済み)
        for component in components:
            # 早期継続でブランチ予測最適化
            if component in ("", "."):
                continue
            elif component == "..":
                # deque.pop()はO(1)(listより高速)
                if stack:
                    stack.pop()
            else:
                # 有効なディレクトリ/ファイル名
                stack.append(component)

        # 効率的文字列結合(join()のC実装活用)
        return "/" + "/".join(stack) if stack else "/"

    def simplify_path_production(
        self, path: str, *, strict_validation: bool = True
    ) -> str:
        """
        業務開発向け実装(型安全・エラーハンドリング重視)

        Args:
            path: Unix絶対パス文字列
            strict_validation: 厳密な入力検証を行うかどうか

        Returns:
            正規化された絶対パス

        Raises:
            ValueError: パス形式が不正な場合
            TypeError: 引数型が不正な場合

        Time Complexity: O(n)
        Space Complexity: O(n)
        """
        # 1. 型・制約検証
        if strict_validation:
            self._validate_input(path)

        # 2. エッジケース処理
        if self._is_root_only(path):
            return "/"

        # 3. メインアルゴリズム(型安全)
        return self._normalize_path(path)

    def _validate_input(self, path: Any) -> None:
        """
        型安全な入力検証

        Args:
            path: 検証対象のパス

        Raises:
            TypeError: 型が不正な場合
            ValueError: 制約違反の場合
        """
        if not isinstance(path, str):
            raise TypeError(f"Path must be a string, got {type(path).__name__}")

        if not path:
            raise ValueError("Path cannot be empty")

        if len(path) > 3000:
            raise ValueError(f"Path length exceeds limit: {len(path)} > 3000")

        if not path.startswith("/"):
            raise ValueError("Path must be absolute (start with '/')")

        # 不正文字チェック
        invalid_chars = set(path) - set(
            "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./_"
        )
        if invalid_chars:
            raise ValueError(f"Invalid characters in path: {invalid_chars}")

    def _is_root_only(self, path: str) -> bool:
        """
        ルートディレクトリのみかどうか判定

        Args:
            path: 判定対象パス

        Returns:
            ルートのみの場合True
        """
        # 効率的な文字列チェック
        return path.strip("/") == ""

    def _normalize_path(self, path: str) -> str:
        """
        パス正規化のコアロジック

        Args:
            path: 正規化対象パス

        Returns:
            正規化されたパス
        """
        # 型ヒント付きスタック初期化
        stack: deque[str] = deque()

        # パス構成要素分割(組み込み関数活用)
        components: List[str] = [c for c in path.split("/") if c]

        # 構成要素処理(型安全なイテレーション)
        for component in components:
            if component == ".":
                continue  # 現在ディレクトリは無視
            elif component == "..":
                # 親ディレクトリ処理(境界チェック)
                if stack:
                    stack.pop()
            else:
                # 有効なディレクトリ/ファイル名追加
                stack.append(component)

        # 結果構築(型安全な文字列操作)
        if not stack:
            return "/"

        return "/" + "/".join(stack)


# 型安全なヘルパー関数(業務開発用)
def validate_unix_path(path: str) -> bool:
    """
    Unix絶対パスの妥当性検証

    Args:
        path: 検証対象パス

    Returns:
        妥当な場合True
    """
    try:
        Solution()._validate_input(path)
        return True
    except (TypeError, ValueError):
        return False


def normalize_path_safe(path: str) -> Optional[str]:
    """
    例外安全なパス正規化

    Args:
        path: 正規化対象パス

    Returns:
        正規化されたパス、失敗時はNone
    """
    try:
        solution = Solution()
        return solution.simplify_path_production(path)
    except (TypeError, ValueError):
        return None

Interactive Algorithm Demo

Stack Visualization

Stack will appear here during demonstration
Click "Analyze Path" to see step-by-step processing

Complexity Analysis

Time Complexity
O(n)
Linear time where n is the length of the input path. Each character is processed exactly once.
Space Complexity
O(n)
Linear space for storing path components in the stack and the result string.
Stack Operations
O(k)
Where k is the number of path components. Each component requires at most one stack operation.
Performance
Optimal
Single pass algorithm with minimal memory overhead and optimal time complexity.

Performance Characteristics

Best Case: O(n)

Path with no special components (., ..) - direct processing

Average Case: O(n)

Mixed path with some navigation components

Worst Case: O(n)

Path with maximum parent directory references - still linear