Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "a96e51ed",
"metadata": {},
"source": [
"# TypeScript Debounce関数 実装\n",
"\n",
"## 1. 問題の分析\n",
"\n",
"### 競技プログラミング視点での分析\n",
"- **実行速度**: debounce自体は遅延が目的なので、呼び出しのオーバーヘッドを最小化\n",
"- **メモリ使用量**: タイマーID1つと最新の引数のみ保持(O(1)空間)\n",
"- **アルゴリズム**: シンプルなタイマー管理で十分\n",
"\n",
"### 業務開発視点での分析\n",
"- **型安全性**: 引数の型を正確に保持し、実行時エラーを防止\n",
"- **保守性**: クロージャによる状態管理で明確な責務分離\n",
"- **メモリリーク防止**: タイマーの適切なクリアが必須\n",
"- **エラーハンドリング**: 不正な`t`値の検証\n",
"\n",
"### TypeScript特有の考慮点\n",
"- **型推論**: `ReturnType<typeof setTimeout>`でタイマーIDの型を自動推論\n",
"- **クロージャの型安全性**: 外部変数の型を厳密に管理\n",
"- **ジェネリクス**: より汎用的な実装も可能だが、LeetCode形式に従う\n",
"\n",
"## 2. アルゴリズムアプローチ比較\n",
"\n",
"|アプローチ|時間計算量|空間計算量|TS実装コスト|型安全性|可読性|備考|\n",
"|---------|---------|---------|-----------|-------|------|-----|\n",
"|タイマー管理|O(1)|O(1)|低|高|高|標準的なdebounce実装|\n",
"|キュー方式|O(n)|O(n)|高|中|低|過剰設計、不要|\n",
"\n",
"## 3. 選択したアルゴリズムと理由\n",
"\n",
"**選択したアプローチ**: タイマー管理方式\n",
"\n",
"**理由**:\n",
"- **計算量的な優位性**: 各呼び出しO(1)、メモリもO(1)で最適\n",
"- **TypeScript環境での型安全性**: クロージャで型情報を完全に保持\n",
"- **保守性・可読性**: 実装が直感的で、debounceの動作が明確\n",
"\n",
"**TypeScript特有の最適化ポイント**:\n",
"- `ReturnType<typeof setTimeout>`による型推論活用\n",
"- strict nullチェックによる安全なタイマー管理\n",
"- クロージャによる状態カプセル化"
]
},
{
"cell_type": "markdown",
"id": "code-header",
"metadata": {},
"source": [
"## 4. 実装コード\n",
"\n",
"### LeetCode Performance\n",
"- Runtime: 48 ms (Beats 71.15%)\n",
"- Memory: 54.18 MB (Beats 95.14%)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "type-definition",
"metadata": {},
"outputs": [],
"source": [
"// Type definition for function signature\n",
"type F = (...args: number[]) => void"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "debounce-implementation",
"metadata": {},
"outputs": [],
"source": [
"/**\n",
" * 関数の実行をデバウンスする(遅延実行&キャンセル機能付き)\n",
" * @param fn - デバウンス対象の関数\n",
" * @param t - 遅延時間(ミリ秒)\n",
" * @returns デバウンスされた関数\n",
" * @complexity Time: O(1) per call, Space: O(1)\n",
" */\n",
"function debounce(fn: F, t: number): F {\n",
" // タイマーIDを保持するクロージャ変数(型安全)\n",
" let timeoutId: ReturnType<typeof setTimeout> | null = null;\n",
" \n",
" return function(...args: number[]): void {\n",
" // 既存のタイマーをキャンセル(clearTimeoutはnull安全)\n",
" clearTimeout(timeoutId);\n",
" \n",
" // 新しいタイマーをセット(t ミリ秒後に fn を実行)\n",
" timeoutId = setTimeout(() => {\n",
" fn(...args);\n",
" }, t);\n",
" };\n",
"}"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "usage-example",
"metadata": {},
"outputs": [],
"source": [
"// Usage example\n",
"const log = debounce(console.log, 100);\n",
"log('Hello'); // cancelled\n",
"log('Hello'); // cancelled\n",
"log('Hello'); // Logged at t=100ms"
]
},
{
"cell_type": "markdown",
"id": "explanation",
"metadata": {},
"source": [
"## 5. 実装の詳細説明\n",
"\n",
"### コア機能\n",
"\n",
"1. **タイマー管理**\n",
" - `timeoutId`変数で現在のタイマーを追跡\n",
" - `clearTimeout`はnull/undefinedを安全に受け付ける\n",
"\n",
"2. **キャンセルメカニズム**\n",
" - 新しい呼び出し時に既存タイマーを`clearTimeout`でクリア\n",
" - これにより前の実行がキャンセルされる\n",
"\n",
"3. **遅延実行**\n",
" - `setTimeout`で`t`ミリ秒後に元の関数を実行\n",
" - 引数は最新の呼び出し時のものを使用\n",
"\n",
"### TypeScript型安全性のポイント\n",
"\n",
"```typescript\n",
"// ✅ 型安全な実装\n",
"let timeoutId: ReturnType<typeof setTimeout> | null = null;\n",
"// - ReturnType: setTimeoutの戻り値型を自動推論\n",
"// - | null: 初期状態を表現\n",
"// - clearTimeout(null)は仕様上安全(no-op)\n",
"\n",
"// ✅ 引数の型保持\n",
"return function(...args: number[]): void {\n",
" // argsの型が明示的にnumber[]として保持される\n",
"}\n",
"```\n",
"\n",
"### 動作例の詳細\n",
"\n",
"**Example 1**: `t = 50ms`\n",
"```\n",
"50ms: dlog(1) → タイマーセット(100msに実行予定)\n",
"75ms: dlog(2) → 前のタイマークリア、新タイマーセット(125msに実行)\n",
"125ms: fn(2)実行\n",
"```\n",
"\n",
"**Example 2**: `t = 20ms`\n",
"```\n",
"50ms: dlog(1) → タイマーセット(70msに実行予定)\n",
"70ms: fn(1)実行\n",
"100ms: dlog(2) → タイマーセット(120msに実行)\n",
"120ms: fn(2)実行\n",
"```\n",
"\n",
"## TypeScript固有の最適化観点\n",
"\n",
"### 型安全性の活用\n",
"\n",
"1. **コンパイル時エラー防止**\n",
" - `timeoutId`の型で未初期化状態を安全に管理\n",
" - strict modeでのnull安全性確保\n",
"\n",
"2. **型推論による開発効率**\n",
" - `ReturnType<typeof setTimeout>`で環境依存の型を自動取得\n",
" - Node.js/ブラウザ両方で動作\n",
"\n",
"3. **クロージャの型安全性**\n",
" - 外部変数の型が明確で、スコープ管理が安全\n",
"\n",
"### パフォーマンス特性\n",
"\n",
"- **時間計算量**: O(1) - 各呼び出しは定数時間\n",
"- **空間計算量**: O(1) - タイマーID1つのみ保持\n",
"- **メモリリーク**: なし - タイマーは適切にクリアされる\n",
"\n",
"### エッジケース対応\n",
"\n",
"- `t = 0`: `setTimeout(fn, 0)`は次のイベントループティックで実行される(同期的ではない)。連続呼び出しでは最後の呼び出しのみが実行されるdebounce動作は維持される\n",
"- 連続呼び出し: 最後の呼び出しのみが実行される\n",
"- 引数なし: 正常に動作(`...args`が空配列)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "TypeScript",
"language": "typescript",
"name": "typescript"
},
"language_info": {
"file_extension": ".ts",
"mimetype": "text/typescript",
"name": "typescript",
"version": "5.3.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Loading