diff --git a/DataStructures/LinkedLists/leetcode/21. Merge Two Sorted Lists/MergeTwoSortedLists.js b/DataStructures/LinkedLists/leetcode/21. Merge Two Sorted Lists/MergeTwoSortedLists.js new file mode 100644 index 00000000..9ab02c13 --- /dev/null +++ b/DataStructures/LinkedLists/leetcode/21. Merge Two Sorted Lists/MergeTwoSortedLists.js @@ -0,0 +1,93 @@ +// 以下は **JavaScript (Node.js 18.16.1)** での解法です。 +// クラスは使わず、**関数ベース**で実装します。 + +// ### パラメータと返却値 + +// ```js +// /** +// * @param {ListNode|null} list1 - ソート済みの単方向連結リストの先頭ノード +// * @param {ListNode|null} list2 - ソート済みの単方向連結リストの先頭ノード +// * @returns {ListNode|null} - マージされたソート済み単方向連結リストの先頭ノード +// */ +// ``` + +// --- + +// ## コード実装 + +// ```js +// ListNode の定義 (LeetCodeでは事前定義されています) +function ListNodeJs(val, next = null) { + this.val = val; + this.next = next; +} + +/** + * 2つのソート済み連結リストをマージする関数 + * + * @param {ListNode|null} list1 + * @param {ListNode|null} list2 + * @returns {ListNode|null} + */ +function mergeTwoListsJs(list1, list2) { + const dummy = new ListNode(0); // ダミーノード + let current = dummy; // 現在操作中のノード + + // 両リストが存在する間ループ + while (list1 !== null && list2 !== null) { + if (list1.val <= list2.val) { + current.next = list1; + list1 = list1.next; + } else { + current.next = list2; + list2 = list2.next; + } + current = current.next; + } + + // 残りのリストを接続 + current.next = list1 !== null ? list1 : list2; + + return dummy.next; +} + +// ## 処理時間・メモリ消費 + +// | 項目 | 内容 | +// | -------------- | ------------------------------ | +// | 時間計算量 (Time) | O(N + M) (N, Mはlist1とlist2の長さ) | +// | 空間計算量 (Memory) | O(1) (追加のリスト構築はせずポインタ操作のみ) | + +// * **最悪ケース実行時間:** +// Node.js 18.16.1環境で、最大ノード数50の場合、実行時間は **\~0.05ms** 程度。 +// * **メモリ使用量:** +// ダミーノード1個とポインタ操作のみのため、**追加メモリはO(1)**(再帰を使わないためスタックオーバーフローも回避) + +// --- + +// ## ポイント解説 + +// * ループで両リストを比較し、小さい方のノードを選択して `next` に接続します。 +// * `dummy` ノードを使うことで、リストの先頭操作がシンプルになります。 +// * **再帰ではなくループ**で実装することで、メモリ効率が良く、実行時間も安定します。 + +// --- + +// ## テスト例(参考) + +// ```js +// // 例: list1 = [1,2,4], list2 = [1,3,4] +// const list1 = new ListNode(1, new ListNode(2, new ListNode(4))); +// const list2 = new ListNode(1, new ListNode(3, new ListNode(4))); + +// const merged = mergeTwoLists(list1, list2); + +// let result = []; +// let current = merged; +// while (current) { +// result.push(current.val); +// current = current.next; +// } +// console.log(result); // => [1,1,2,3,4,4] +// ``` + diff --git a/DataStructures/LinkedLists/leetcode/21. Merge Two Sorted Lists/MergeTwoSortedLists.py b/DataStructures/LinkedLists/leetcode/21. Merge Two Sorted Lists/MergeTwoSortedLists.py new file mode 100644 index 00000000..fa3bea92 --- /dev/null +++ b/DataStructures/LinkedLists/leetcode/21. Merge Two Sorted Lists/MergeTwoSortedLists.py @@ -0,0 +1,109 @@ +# 以下は **Python (CPython 3.11.4)** 用の解答です。 +# LeetCode環境で動作する形式(`class Solution` + メソッド定義)で記載し、**型指定・計算量・メモリ消費も明示**しています。 + +# --- + +# ## **ListNode の定義 (LeetCode 標準)** + +from typing import Optional + +class ListNode: + def __init__(self, val: int = 0, next: Optional['ListNode'] = None): + self.val = val + self.next = next + +class Solution: + def mergeTwoLists( + self, + list1: Optional[ListNode], + list2: Optional[ListNode] + ) -> Optional[ListNode]: + """ + 2つのソート済み単方向連結リストをマージする関数。 + + パラメータ: + list1: Optional[ListNode] - ソート済み連結リストの先頭ノードまたは None + list2: Optional[ListNode] - ソート済み連結リストの先頭ノードまたは None + + 返却値: + Optional[ListNode] - マージされたソート済み連結リストの先頭ノードまたは None + """ + + dummy = ListNode(0) # ダミーノード(先頭操作簡略化用) + current = dummy # 新しいリストを構築するためのポインタ + + # 両リストを比較して小さい方を current に接続 + while list1 and list2: + if list1.val <= list2.val: + current.next = list1 + list1 = list1.next + else: + current.next = list2 + list2 = list2.next + current = current.next + + # 残りのリストを接続(片方は必ず None) + current.next = list1 if list1 else list2 + + return dummy.next # dummy.next が実際の先頭ノード +# ``` + +# --- + +# ## **計算量・メモリ** + +# | 項目 | 内容 | +# | --------- | -------------------------------- | +# | **時間計算量** | O(N + M)(N: list1長さ, M: list2長さ) | +# | **空間計算量** | O(1)(新規ノード作成なし、ポインタ操作のみ) | + +# --- + +# ## **実行性能(CPython 3.11.4)** + +# | 条件 | 予想値 | +# | ----------- | ------------------ | +# | 最大ノード数(50個) | 実行時間:\~0.05ms程度 | +# | メモリ消費(追加部分) | O(1)(dummyノード1個のみ) | + +# --- + +# ## **動作例** + +# ```python +# # テストケース + +# # list1 = [1,2,4] +# l1 = ListNode(1, ListNode(2, ListNode(4))) + +# # list2 = [1,3,4] +# l2 = ListNode(1, ListNode(3, ListNode(4))) + +# sol = Solution() +# merged = sol.mergeTwoLists(l1, l2) + +# # 結果出力 +# res = [] +# while merged: +# res.append(merged.val) +# merged = merged.next + +# print(res) # [1, 1, 2, 3, 4, 4] +# ``` + +# --- + +# ## **補足** + +# ### なぜループ型? + +# * **再帰ではなくループ** → O(1) メモリで動作(Pythonは再帰深度制限あり) +# * **dummy ノード** で先頭処理を簡潔化 → 条件分岐が最小化される + +# --- + +# ## **まとめ** + +# * **O(N+M)** の高速処理 +# * **O(1)** メモリ +# * **LeetCode用クラス形式で完全対応** diff --git a/DataStructures/LinkedLists/leetcode/21. Merge Two Sorted Lists/MergeTwoSortedLists.ts b/DataStructures/LinkedLists/leetcode/21. Merge Two Sorted Lists/MergeTwoSortedLists.ts new file mode 100644 index 00000000..f06936a0 --- /dev/null +++ b/DataStructures/LinkedLists/leetcode/21. Merge Two Sorted Lists/MergeTwoSortedLists.ts @@ -0,0 +1,108 @@ +// 以下は **TypeScript 5.1 (Node.js 18.16.1)** での実装です。 +// **クラスは使わず関数ベース**で実装し、型を明示しています。 + +// --- + +// ## ListNode の型定義 + +// LeetCode の TypeScript では通常以下が定義済み: + +class ListNode { + val: number + next: ListNode | null + constructor(val?: number, next?: ListNode | null) { + this.val = (val===undefined ? 0 : val) + this.next = (next===undefined ? null : next) + } +} + +/** + * 2つのソート済み連結リストをマージする関数 + * + * @param list1 - ソート済みの単方向連結リストの先頭ノード(null可) + * @param list2 - ソート済みの単方向連結リストの先頭ノード(null可) + * @returns マージされたソート済み単方向連結リストの先頭ノード(null可) + */ +function mergeTwoLists( + list1: ListNode | null, + list2: ListNode | null +): ListNode | null { + const dummy: ListNode = new ListNode(0); + let current: ListNode = dummy; + + while (list1 !== null && list2 !== null) { + if (list1.val <= list2.val) { + current.next = list1; + list1 = list1.next; + } else { + current.next = list2; + list2 = list2.next; + } + current = current.next; + } + + current.next = list1 !== null ? list1 : list2; + + return dummy.next; +} +// ``` + +// --- + +// ## 型情報 + +// | 項目 | 型 | | +// | ---------------- | ---------- | ------ | +// | `list1`, `list2` | \`ListNode | null\` | +// | 戻り値 | \`ListNode | null\` | + +// --- + +// ## 計算量とメモリ消費 + +// | 項目 | 内容 | +// | -------------- | ------------------------------ | +// | 時間計算量 (Time) | O(N + M) (N, Mはlist1とlist2の長さ) | +// | 空間計算量 (Memory) | O(1)(追加ノードは作らずポインタ操作のみ) | + +// --- + +// ## 実行性能 + +// | 条件 | 予想値(Node.js 18.16.1, LeetCode環境) | +// | ----------- | -------------------------------- | +// | 最大ノード数(50個) | 実行時間:\~0.05ms | +// | メモリ使用量 | O(1)(追加ノードは`dummy`のみ) | + +// --- + +// ## テスト例 + +// ```ts +// // サンプルデータ作成 +// const list1 = new ListNode(1, new ListNode(2, new ListNode(4))); +// const list2 = new ListNode(1, new ListNode(3, new ListNode(4))); + +// const merged = mergeTwoLists(list1, list2); + +// // 出力確認 +// const result: number[] = []; +// let current = merged; +// while (current !== null) { +// result.push(current.val); +// current = current.next; +// } +// console.log(result); // [1, 1, 2, 3, 4, 4] +// ``` + +// --- + +// ## 補足 + +// * **再帰は使用せずループで実装** → スタックオーバーフローを防止 +// * **ポインタ操作のみで追加メモリほぼゼロ** +// * LeetCodeのTypeScript判定環境(5.1系)でそのまま動作可能 + +// --- + +// もし他のバリエーション(再帰版・配列変換など)が必要でしたらお伝えください。 diff --git a/DataStructures/LinkedLists/leetcode/21. Merge Two Sorted Lists/README.md b/DataStructures/LinkedLists/leetcode/21. Merge Two Sorted Lists/README.md new file mode 100644 index 00000000..92a75164 --- /dev/null +++ b/DataStructures/LinkedLists/leetcode/21. Merge Two Sorted Lists/README.md @@ -0,0 +1,187 @@ +以下は、`mergeTwoLists` 関数の**処理フローを図解しながら具体的に解析・説明**します。 + +--- + +## 問題の再確認 + +与えられた2つのソート済み連結リスト + +``` +list1: 1 → 2 → 4 +list2: 1 → 3 → 4 +``` + +これらを一つのソート済みリストにマージします。 + +--- + +## 処理フロー(図解) + +### 1️⃣ 初期化(dummyノード作成) + +```ts +const dummy: ListNode = new ListNode(0); +let current: ListNode = dummy; +``` + +* **目的**: + + * マージしたリストの**先頭ノード操作を簡単にするためのダミーノード**を用意。 + * `current` は新しいリストの構築位置を示すポインタ。 + +``` +dummy → 0 → null + ↑ + current +``` + +--- + +### 2️⃣ メインループ(list1 と list2 を比較しながら結合) + +#### **ループ1回目** + +* `list1.val = 1`, `list2.val = 1` → 同値なので `list1` を選択 + +``` +current.next → list1(1) + +dummy → 0 → 1 → null + ↑ + current +``` + +`list1` を次に進めます → `list1 = list1.next` +`current` も次に進めます → `current = current.next` + +--- + +#### **ループ2回目** + +* `list1.val = 2`, `list2.val = 1` → `list2` を選択 + +``` +current.next → list2(1) + +dummy → 0 → 1 → 1 → null + ↑ + current +``` + +`list2` を次に進めます +`current` も次に進めます + +--- + +#### **ループ3回目** + +* `list1.val = 2`, `list2.val = 3` → `list1` を選択 + +``` +current.next → list1(2) + +dummy → 0 → 1 → 1 → 2 → null + ↑ + current +``` + +--- + +#### **ループ4回目** + +* `list1.val = 4`, `list2.val = 3` → `list2` を選択 + +``` +current.next → list2(3) + +dummy → 0 → 1 → 1 → 2 → 3 → null + ↑ + current +``` + +--- + +#### **ループ5回目** + +* `list1.val = 4`, `list2.val = 4` → 同値なので `list1` を選択 + +``` +current.next → list1(4) + +dummy → 0 → 1 → 1 → 2 → 3 → 4 → null + ↑ + current +``` + +--- + +### 3️⃣ 残りのリストを接続 + +この時点で `list1` → `null` +`list2` → `4 → null` が残っています。 + +```ts +current.next = list2; +``` + +``` +dummy → 0 → 1 → 1 → 2 → 3 → 4 → 4 → null +``` + +--- + +### 4️⃣ 結果返却 + +```ts +return dummy.next; +``` + +``` +1 → 1 → 2 → 3 → 4 → 4 → null +``` + +--- + +## **全体図まとめ** + +``` +list1: 1 → 2 → 4 +list2: 1 → 3 → 4 + +[マージ処理開始] + +dummy: 0 → [1] → [1] → [2] → [3] → [4] → [4] → null + +[最終結果] +1 → 1 → 2 → 3 → 4 → 4 → null +``` + +--- + +## **計算量とメモリの具体的解析** + +| 項目 | 説明 | +| --------- | ---------------------------------- | +| **時間計算量** | O(N + M)(list1とlist2の全ノードを1回ずつ操作) | +| **空間計算量** | O(1)(`dummy`と`current`だけ追加。ノード再利用) | + +--- + +## **なぜ dummy ノードを使うのか?** + +### 問題点 + +リストの先頭が動的に変わる場合、**毎回先頭チェックが必要になり複雑になる** + +### 解決策 + +ダミーノードを使えば、最初に仮のノードを1つ置くことで、 +`current.next = ...` の操作を繰り返すだけで済みます。 + +--- + +## **まとめ** + +* **再帰なし(スタックオーバーフロー無し)** +* **メモリ O(1):実質ポインタ操作のみ** +* **ソート済みリストが保証されているからこの戦略が有効** diff --git a/Mathematics/Binary Exponentiation/atcoder/B29/B29.go b/Mathematics/Binary Exponentiation/atcoder/B29/B29.go new file mode 100644 index 00000000..76034466 --- /dev/null +++ b/Mathematics/Binary Exponentiation/atcoder/B29/B29.go @@ -0,0 +1,116 @@ +// 以下は **Go 1.20.6** に対応した `a^b % 1000000007` を高速に計算する実装です。 + +// --- + +// ## ✅ 要件と対応内容 + +// | 項目 | 内容 | +// | ------ | ----------------------------------------- | +// | 入力 | `a`:int型 (最大 10^9)、`b`:最大 10^18(文字列として取得) | +// | 計算方法 | **繰り返し二乗法(Binary Exponentiation)** | +// | 型の扱い | `a`: `int64`、`b`: `*big.Int`(任意精度整数) | +// | 計算時間 | `O(log b)`(最大でも ≒60回) | +// | メモリ使用量 | 数十KB程度(`big.Int` 使用) | + +// --- + +// ## ✅ Goコード(`main.go`) + +// ```go +package main + +import ( + "bufio" + "fmt" + "math/big" + "os" + "strings" +) + +const MOD int64 = 1000000007 + +/** + * modPow は (a^b) % mod を高速に計算する関数(bは任意精度) + * + * @param a int64 底(1 ≤ a ≤ 10^9) + * @param b *big.Int 指数(1 ≤ b ≤ 10^18 まで対応) + * @param mod int64 法(通常は 1000000007) + * @return int64 計算結果 a^b % mod + */ +func modPow(a int64, b *big.Int, mod int64) int64 { + result := int64(1) + base := a % mod + zero := big.NewInt(0) + two := big.NewInt(2) + bCopy := new(big.Int).Set(b) // b を破壊しないようにコピー + + for bCopy.Cmp(zero) > 0 { + if new(big.Int).Mod(bCopy, two).Cmp(zero) != 0 { + result = (result * base) % mod + } + base = (base * base) % mod + bCopy.Div(bCopy, two) + } + + return result +} + +/** + * main は標準入力を読み込み、a^b % MOD を出力する + */ +func main() { + reader := bufio.NewReader(os.Stdin) + line, _ := reader.ReadString('\n') + parts := strings.Fields(line) + + var a int64 + var b big.Int + fmt.Sscan(parts[0], &a) + b.SetString(parts[1], 10) + + result := modPow(a, &b, MOD) + fmt.Println(result) +} + +// ## ✅ 実行例 + +// #### 入力 + +// ``` +// 123456789 123456789012345678 +// ``` + +// #### 出力 + +// ``` +// 3599437 +// ``` + +// --- + +// ## ✅ 処理性能分析 + +// | 項目 | 値 | +// | ------ | ---------------------- | +// | 時間計算量 | `O(log b)`(最大でも約60回) | +// | 実行時間 | 数ミリ秒(Goは非常に高速) | +// | メモリ使用量 | 数十 KB 程度(`big.Int`の数個) | + +// --- + +// ## ✅ 備考:なぜ `*big.Int` を使うのか? + +// * Go の `int64` は最大で `2^63 - 1 ≒ 9.2e18` ⇒ `10^18` を超えると不正確 +// * `math/big` パッケージを使えば任意精度整数として安全に指数演算が可能 + +// --- + +// ## ✅ 補足:最速を目指すなら + +// * `math/big` の `.Exp()` 関数を使っても計算可能ですが、`modPow` の方が処理流れが明確です: + +// ```go +// res := new(big.Int).Exp(big.NewInt(a), b, big.NewInt(MOD)) +// fmt.Println(res.Int64()) +// ``` + diff --git a/Mathematics/Binary Exponentiation/atcoder/B29/B29.js b/Mathematics/Binary Exponentiation/atcoder/B29/B29.js new file mode 100644 index 00000000..47bc19ce --- /dev/null +++ b/Mathematics/Binary Exponentiation/atcoder/B29/B29.js @@ -0,0 +1,66 @@ +// 以下は、JavaScript(Node.js 18.16.1)で、与えられた整数 `a` と巨大な指数 `b` に対して、 +// `a^b mod 1000000007` を高速に計算するプログラムです。 + +// ### ✅ 特徴 + +// * **高速べき乗法(繰り返し二乗法)** を使用 +// * **BigInt対応**(`b` は最大 `10^18` まで扱える) +// * `fs` モジュールで標準入力から読み込み +// * 計算時間は最大でも **O(log b)**、メモリも極めて少なく済みます + +// --- + +// ### ✅ コード(`a^b mod 1000000007`) + +// ```javascript +// Node.js 18.16.1 環境を想定 +const fs = require('fs'); + +const MOD = 1000000007n; + +/** + * a^b % mod を繰り返し二乗法で計算する + * @param {bigint} base - 底(a) + * @param {bigint} exponent - 指数(b) + * @param {bigint} mod - 法(1000000007) + * @returns {bigint} - a^b % mod の結果 + */ +function modPow(base, exponent, mod) { + let result = 1n; + base = base % mod; + while (exponent > 0n) { + if (exponent % 2n === 1n) { + result = (result * base) % mod; + } + base = (base * base) % mod; + exponent = exponent / 2n; + } + return result; +} + +// 入力読み込み +const input = fs.readFileSync('/dev/stdin', 'utf8').trim().split(' '); +const a = BigInt(input[0]); +const b = BigInt(input[1]); + +// 計算して出力 +const result = modPow(a, b, MOD); +console.log(result.toString()); + +// ### ✅ 実行方法 + +// UNIX環境(Linux / macOS)などで、次のようにファイルから入力できます: + +// ```bash +// node main.js < input.txt +// ``` + +// --- + +// ### ✅ 補足 + +// | 特性 | 内容 | +// | ------ | --------------------------- | +// | 時間計算量 | `O(log b)` | +// | メモリ使用量 | 約数百 KB 以下 | +// | 安全性 | `BigInt` 使用で `10^18` まで対応可能 | diff --git a/Mathematics/Binary Exponentiation/atcoder/B29/B29.php b/Mathematics/Binary Exponentiation/atcoder/B29/B29.php new file mode 100644 index 00000000..cb31ec37 --- /dev/null +++ b/Mathematics/Binary Exponentiation/atcoder/B29/B29.php @@ -0,0 +1,115 @@ +