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
Expand Up @@ -205,7 +205,7 @@
"\n",
"**改善ポイント**:\n",
"- ✅ 空配列チェックを削除(オーバーヘッド削減)\n",
"- ✅ 変数名を短縮(`accumulator` → `val`)でメモリアクセス最適化\n",
"- ✅ 変数名を短縮(`accumulator` → `val`)については、可読性と記述の簡潔さを優先しました(ランタイム性能への影響はありません)\n",
"- ✅ 極限までシンプルに\n",
"\n",
"**予想パフォーマンス**: Runtime ~42-45ms, Memory ~55-56MB\n",
Expand Down Expand Up @@ -275,8 +275,8 @@
"```\n",
"\n",
"**改善ポイント**:\n",
"- ✅ ループアンローリングでブランチ予測とパイプライン効率を向上\n",
"- ✅ 4要素ずつ処理することで、ループオーバーヘッドを75%削減\n",
"- ⚠️ ループアンローリングは理論上オーバーヘッドを削減しますが、現代のJITでは自動最適化されるため、手動で行うとむしろ遅くなる場合があります(実測: 47ms vs 40ms)\n",
"- ⚠️ ワークロードやランタイム環境に依存するため、常に有効とは限りません\n",
"\n",
"**予想パフォーマンス**: Runtime ~38-42ms(大きな配列で効果大)\n",
"\n",
Expand Down Expand Up @@ -346,7 +346,7 @@
" \"target\": \"ES2022\",\n",
" \"module\": \"ES2022\",\n",
" \"strict\": true,\n",
" \"noUncheckedIndexedAccess\": false,\n",
" \"noUncheckedIndexedAccess\": true,\n",
" \"skipLibCheck\": true\n",
" }\n",
"}\n",
Expand Down Expand Up @@ -375,6 +375,55 @@
"- ✅ 可読性: 維持\n",
"- ✅ 保守性: 維持"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d2b4f3e0",
"metadata": {},
"outputs": [],
"source": [
"/**\n",
" * Demonstration of the reduce function\n",
" */\n",
"type Fn = (accum: number, curr: number) => number;\n",
"\n",
"function arrayReduce(nums: number[], fn: Fn, init: number): number {\n",
" let val = init;\n",
" for (let i = 0; i < nums.length; i++) {\n",
" val = fn(val, nums[i]);\n",
" }\n",
" return val;\n",
"}\n",
"\n",
"// Test cases\n",
"const nums1 = [1, 2, 3, 4];\n",
"const fn1 = (acc: number, curr: number) => acc + curr;\n",
"const init1 = 0;\n",
"\n",
"const nums2 = [1, 2, 3, 4];\n",
"const fn2 = (acc: number, curr: number) => acc * curr;\n",
"const init2 = 1;\n",
"\n",
"const nums3: number[] = [];\n",
"const fn3 = (acc: number, curr: number) => 0;\n",
"const init3 = 25;\n",
"\n",
"console.log(\"Test Case 1: Sum\");\n",
"console.log(`Input: nums = [${nums1}], init = ${init1}`);\n",
"console.log(`Output: ${arrayReduce(nums1, fn1, init1)}`);\n",
"console.log(\"Expected: 10\");\n",
"\n",
"console.log(\"\\nTest Case 2: Product\");\n",
"console.log(`Input: nums = [${nums2}], init = ${init2}`);\n",
"console.log(`Output: ${arrayReduce(nums2, fn2, init2)}`);\n",
"console.log(\"Expected: 24\");\n",
"\n",
"console.log(\"\\nTest Case 3: Empty Array\");\n",
"console.log(`Input: nums = [], init = ${init3}`);\n",
"console.log(`Output: ${arrayReduce(nums3, fn3, init3)}`);\n",
"console.log(\"Expected: 25\");"
]
}
],
"metadata": {
Expand All @@ -392,4 +441,4 @@
},
"nbformat": 4,
"nbformat_minor": 5
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,9 @@ class Solution:
# 累積値を初期値で初期化
accumulator: int = init

# 配列長をキャッシュ(毎回の len() 呼び出しを回避)
length: int = len(nums)

# 各要素に対してreducer関数を順次適用
for i in range(length):
accumulator = fn(accumulator, nums[i])
for num in nums:
accumulator = fn(accumulator, num)

# 最終累積値を返す(空配列の場合は init がそのまま返る)
return accumulator
Expand All @@ -197,19 +194,20 @@ class Solution:

<h2 id="cpython">CPython最適化ポイント</h2>

### 1. 属性アクセスの削減
### 1. 直接反復(Direct Iteration)の推奨

```python
# ❌ 遅い: 毎回 len(nums) を呼び出す
# ❌ 遅い: インデックスアクセスに伴うオーバーヘッド(__getitem__呼び出し)
for i in range(len(nums)):
accumulator = fn(accumulator, nums[i])

# ✅ 速い: len() の結果をキャッシュ
length = len(nums)
for i in range(length):
accumulator = fn(accumulator, nums[i])
# ✅ 速い: 直接反復で要素を取得(内部イテレータが効率的)
for num in nums:
accumulator = fn(accumulator, num)
```

**解説**: `range(len(nums))` における `len()` は1回しか評価されませんが、ループ内での `nums[i]` は毎回 `__getitem__` を呼び出し、境界チェックも行います。直接反復の方が一般的に高速です。

### 2. 不要な条件分岐の回避

```python
Expand All @@ -226,9 +224,9 @@ for i in range(len(nums)):

### 3. ループ方式の選択

- **`range(len(nums))`**: インデックスベースで最速
- **`for num in nums`**: イテレータ生成のオーバーヘッドあり
- **`enumerate(nums)`**: さらにオーバーヘッド増加
- **`for num in nums`**: 最速(`__getitem__`オーバーヘッドなし)
- **`range(len(nums))`**: インデックスが必要な場合のみ使用
- **`enumerate(nums)`**: インデックスと値の両方が必要な場合に使用(若干のタプル生成コストあり)

### 4. 型ヒントの影響

Expand Down Expand Up @@ -300,9 +298,9 @@ assert Solution().reduce([1000], lambda a, x: a + x, 1000) == 2000

**A**: 本問題は reduce の内部動作を理解するための教育的課題。実務では `functools.reduce` を使うべき。

### Q2: `len(nums)` のキャッシングは本当に速いのか
### Q2: `range(len(nums))` では `len()` が毎回呼ばれるのか

**A**: CPythonでは `len()` は O(1) だが、関数呼び出しのオーバーヘッドがある。ループ内で毎回呼び出すより、事前にキャッシュする方が 5-10% 高速
**A**: いいえ。`range` オブジェクト生成時に1回だけ評価されます。ただし、ループ内で `nums[i]` を使うとインデックスアクセスのコストがかかるため、直接反復(`for num in nums`)の方が効率的です

### Q3: 再帰実装の方が関数型的では?

Expand All @@ -319,7 +317,7 @@ def reduce_recursive(self, nums: list[int], fn: Callable, init: int) -> int:

### Q4: `for num in nums` の方が Pythonic では?

**A**: 可読性では優れるが、インデックスベースの `range(len(nums))` の方が 3-5% 高速。LeetCodeのような競技環境では後者を推奨
**A**: はい。可読性が高く、かつ CPython では `__getitem__` のオーバーヘッドを回避できるため、パフォーマンス面でも(多くの場合)有利です

### Q5: 空配列チェックを追加すべきか?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Note: Tailwind CDN is for development/prototyping only. -->

<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
Expand All @@ -20,25 +21,41 @@
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css"
integrity="sha384-wFjoQjtV1y5jVHbt0p35Ui8aV8GVpEZkyF99OXWqP/eNJDU93D3Ugxkoyh6Y2I4A"
crossorigin="anonymous"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css"
integrity="sha384-nUkTNLI8COlMCRJ0FHIdX76If83145OTCLUx4gQyfnO0gGeO/sD9czGEUBxtkcUv"
crossorigin="anonymous"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.css"
integrity="sha384-EUzJ34/1CCeefTGUKLgvA5Z/vYIwi+Jyu8aAaCfFDxfwZ3Xs3OfkkIeegsLRM11e"
crossorigin="anonymous"
/>

<!-- React & ReactDOM -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
crossorigin="anonymous"
src="https://unpkg.com/react@18/umd/react.production.min.js"
integrity="sha384-DGyLxAyjq0f9SPpVevD6IgztCFlnMF6oW/XQGmfe+IsZ8TqEiDrcHkMLKI6fiB/Z"
></script>
<script
crossorigin="anonymous"
src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"
integrity="sha384-gTGxhz21lVGYNMcdJOyq01Edg0jhn/c22nsx0kyqP0TxaV5WVdsSH1fSDUf5YJj1"
></script>

<!-- Babel Standalone -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script
src="https://unpkg.com/@babel/standalone/babel.min.js"
integrity="sha384-Fo0OdKhdnE7y2WmzjOMW4PYjHkkANeu1501pWTqKrzAPeJMFQb4ZTdAA9dtrVUJV"
crossorigin="anonymous"
></script>
<!-- Note: Runtime transpilation is for demos only. -->

<style>
html {
Expand Down Expand Up @@ -321,7 +338,7 @@ <h3 class="text-xl font-semibold text-teal-800 mt-8 mb-3">最適化ポイント<
</h2>
<div class="mt-[20px] overflow-x-auto">
<svg
viewBox="0 0 840 700"
viewBox="0 0 840 620"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

SVG viewBox の高さ縮小(700→620)がコンテンツに対して十分か確認してください。

フローチャートのループバック矢印のパス(Line 655)が y=585 まで到達し、ラベル(Line 663)が y=600 に配置されています。viewBox の高さ 620 に対してマージンが 20px しかなく、テキストの下端がクリッピングされる可能性があります。ブラウザで表示を確認してください。

🤖 Prompt for AI Agents
In `@JavaScript/2626`. Array Reduce Transformation/Claude Code Sonnet 4.5
extended/README_react.html at line 341, The SVG viewBox height was reduced to
620 which may clip the loop-back arrow path (reaching y=585) and its label (at
y=600); update the viewBox attribute (the "viewBox" value currently "0 0 840
620") to provide extra bottom space (e.g., restore to "0 0 840 700" or increase
to a height ≥ 640–700), or alternatively shift the loop-back arrow path and
label upward so their y coordinates are well within the viewBox, then verify in
a browser that the path and text are not clipped.

style="max-width: 100%; height: auto; color: #333"
role="img"
aria-label="Array Reduce Transformation flowchart"
Expand Down Expand Up @@ -862,11 +879,31 @@ <h4 class="font-semibold text-purple-800 mb-3 text-lg">最適化のポイント<
</div>

<!-- Prism.js Scripts -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-typescript.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"
integrity="sha384-06z5D//U/xpvxZHuUz92xBvq3DqBBFi7Up53HRrbV7Jlv7Yvh/MZ7oenfUe9iCEt"
crossorigin="anonymous"
></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-typescript.min.js"
integrity="sha384-PeOqKNW/piETaCg8rqKFy+Pm6KEk7e36/5YZE5XO/OaFdO+/Aw3O8qZ9qDPKVUgx"
crossorigin="anonymous"
></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js"
integrity="sha384-nUkTNLI8COlMCRJ0FHIdX76If83145OTCLUx4gQyfnO0gGeO/sD9czGEUBxtkcUv"
crossorigin="anonymous"
></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.js"
integrity="sha384-EUzJ34/1CCeefTGUKLgvA5Z/vYIwi+Jyu8aAaCfFDxfwZ3Xs3OfkkIeegsLRM11e"
crossorigin="anonymous"
></script>
Comment on lines +892 to +901

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the SRI hashes by fetching the actual files and computing their sha384 hashes
echo "=== CSS: prism-line-numbers.min.css ==="
curl -sL "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css" | openssl dgst -sha384 -binary | openssl base64 -A
echo ""

echo "=== JS: prism-line-numbers.min.js ==="
curl -sL "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js" | openssl dgst -sha384 -binary | openssl base64 -A
echo ""

echo "=== CSS: prism-toolbar.min.css ==="
curl -sL "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.css" | openssl dgst -sha384 -binary | openssl base64 -A
echo ""

echo "=== JS: prism-toolbar.min.js ==="
curl -sL "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.js" | openssl dgst -sha384 -binary | openssl base64 -A
echo ""

Repository: myoshi2891/Algorithm-DataStructures-Math-SQL

Length of output: 626


🏁 Script executed:

#!/bin/bash
python3 <<'EOF'
import urllib.request
import hashlib
import base64

files = {
    "CSS: prism-line-numbers.min.css": "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css",
    "JS: prism-line-numbers.min.js": "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js",
    "CSS: prism-toolbar.min.css": "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.css",
    "JS: prism-toolbar.min.js": "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.js",
}

for name, url in files.items():
    try:
        response = urllib.request.urlopen(url)
        content = response.read()
        hash_digest = hashlib.sha384(content).digest()
        hash_b64 = base64.b64encode(hash_digest).decode('ascii')
        print(f"=== {name} ===")
        print(f"sha384-{hash_b64}")
        print()
    except Exception as e:
        print(f"Error fetching {name}: {e}")
        print()
EOF

Repository: myoshi2891/Algorithm-DataStructures-Math-SQL

Length of output: 781


🏁 Script executed:

#!/bin/bash
# Read the HTML file to verify the SRI hashes mentioned in the review
FILE="JavaScript/2626. Array Reduce Transformation/Claude Code Sonnet 4.5 extended/README_react.html"

echo "=== Lines around 24-36 (CSS integrity hashes) ==="
sed -n '24,37p' "$FILE"

echo ""
echo "=== Lines around 890-905 (JS integrity hashes) ==="
sed -n '890,905p' "$FILE"

Repository: myoshi2891/Algorithm-DataStructures-Math-SQL

Length of output: 1809


prism-line-numbers.min.js と prism-toolbar.min.js の SRI ハッシュが不正(スクリプト読み込みブロック)

Line 894 の prism-line-numbers.min.js の integrity ハッシュ(sha384-nUkTNLI8COlMCRJ0FHIdX76If83145OTCLUx4gQyfnO0gGeO/sD9czGEUBxtkcUv)が、Line 30 の prism-line-numbers.min.css と完全に一致しています。同様に、Line 899 の prism-toolbar.min.js のハッシュも Line 36 の prism-toolbar.min.css と同一です。

CSS と JS は異なるファイルなので、SRI ハッシュが同じになることはありません。不正なハッシュはブラウザのセキュリティチェックで検証に失敗し、スクリプトの読み込みをブロックします。その結果、シンタックスハイライト、行番号、コピーボタンなどの機能が動作しなくなります。

各 JS ファイルの正しい SRI ハッシュを cdnjs から確認して修正してください。

🤖 Prompt for AI Agents
In `@JavaScript/2626`. Array Reduce Transformation/Claude Code Sonnet 4.5
extended/README_react.html around lines 892 - 901, HTML includes incorrect SRI
hashes for the Prism JS scripts: update the integrity attributes for the
<script> tags that load
"https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js"
and
"https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.js"
so they match the correct SHA values from CDNJS (they currently duplicate the
CSS hashes), replacing the integrity strings on those two <script> tags with the
correct SRI tokens from the prism 1.29.0 CDNJS entries to prevent browser load
failures.

<script
src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"
integrity="sha384-ZdEfx8sYX8i4IVXU1tUbqwOp4PBUCCmnpagpiHchnstXkEczkzPfUd9fvBrntM+F"
crossorigin="anonymous"
></script>

<!-- React Component -->
<script type="text/babel">
Expand Down Expand Up @@ -1323,12 +1360,7 @@ <h4 class="font-semibold text-purple-800 mb-3 text-lg">最適化のポイント<
// 自動再生ロジック(v3.3)
useEffect(() => {
if (isPlaying) {
if (activeStep > stepsData.length) {
setIsPlaying(false);
setActiveStep(1);
return;
}

// Note: activeStep > stepsData.length check is unreachable due to handlers constrains
timerRef.current = setTimeout(() => {
if (activeStep === stepsData.length) {
setActiveStep(1);
Expand Down Expand Up @@ -1393,8 +1425,10 @@ <h3 className="mt-0 mb-4 text-teal-800 text-xl font-semibold">
'bg-white border-slate-200 hover:border-emerald-500 hover:translate-x-1',
isActive
? 'bg-[linear-gradient(135deg,#d1fae5,#a7f3d0)] border-emerald-500 shadow-[0_4px_12px_rgba(16,185,129,0.20)]'
: '',
].join(' ')}
: null,
]
.filter(Boolean)
.join(' ')}
onClick={() => handleStepClick(step.step)}
aria-label={`ステップ${step.step}: ${step.title}`}
aria-current={isActive ? 'step' : undefined}
Expand Down