Skip to content

Commit ba03a90

Browse files
committed
leetcode 31. Next Permutation
1 parent 35f9371 commit ba03a90

7 files changed

Lines changed: 1149 additions & 0 deletions

File tree

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// 以下は、Node.js 18.16.1 / LeetCode 実行環境で動作する **関数ベース** の JavaScript 実装例です。
2+
3+
// * **処理時間**: O(n)
4+
// * **追加メモリ**: O(1)(定数)
5+
// * **in-place** で次の順列を求めます。
6+
7+
// ```javascript
8+
/**
9+
* 次の辞書順順列を計算し、numsを直接変更する
10+
* @param {number[]} nums - 整数配列(1 <= nums.length <= 100)
11+
* @returns {void} - 配列を直接変更するため返却値はなし
12+
*
13+
* アルゴリズム:
14+
* 1. 後ろから探索して、最初に nums[i] < nums[i+1] となる位置を探す (i が "転換点")
15+
* 2. さらに後ろから nums[i] より大きい最小の要素 nums[j] を探す
16+
* 3. nums[i] と nums[j] をスワップ
17+
* 4. i+1 以降を昇順に反転(reverse)する
18+
*
19+
* 時間計算量: O(n) (最大100要素)
20+
* 空間計算量: O(1) (定数メモリでin-place処理)
21+
*/
22+
function nextPermutationJs(nums) {
23+
// 1. 後ろから転換点を探す
24+
let i = nums.length - 2;
25+
while (i >= 0 && nums[i] >= nums[i + 1]) {
26+
i--;
27+
}
28+
29+
if (i >= 0) {
30+
// 2. 後ろから nums[i] より大きい最小の要素を探す
31+
let j = nums.length - 1;
32+
while (j >= 0 && nums[j] <= nums[i]) {
33+
j--;
34+
}
35+
// 3. スワップ
36+
[nums[i], nums[j]] = [nums[j], nums[i]];
37+
}
38+
39+
// 4. i+1 以降を反転
40+
let left = i + 1;
41+
let right = nums.length - 1;
42+
while (left < right) {
43+
[nums[left], nums[right]] = [nums[right], nums[left]];
44+
left++;
45+
right--;
46+
}
47+
}
48+
// ```
49+
50+
// ---
51+
52+
// ### **動作例**
53+
54+
// ```javascript
55+
// let nums1 = [1,2,3];
56+
// nextPermutation(nums1);
57+
// console.log(nums1); // [1,3,2]
58+
59+
// let nums2 = [3,2,1];
60+
// nextPermutation(nums2);
61+
// console.log(nums2); // [1,2,3]
62+
63+
// let nums3 = [1,1,5];
64+
// nextPermutation(nums3);
65+
// console.log(nums3); // [1,5,1]
66+
// ```
67+
68+
// ---
69+
70+
// この方法は **LeetCodeの`Next Permutation`問題(31番)** にそのまま提出可能です。
71+
// 処理は **最大100要素** なので O(n) で十分高速、かつ追加配列を作らず **定数メモリ** で完結します。
72+
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# 以下に、**Python (CPython 3.11.4)** で動作する、**LeetCode形式 (class Solution + メソッド)** の解答例を示します。
2+
3+
# * **処理時間**: O(n)(最大 n=100 で高速)
4+
# * **メモリ消費量**: O(1)(in-place 処理)
5+
# * **型アノテーション付き**
6+
# * **関数ベースだが LeetCode の仕様に合わせて class Solution を使用**
7+
8+
from typing import List
9+
10+
class Solution:
11+
def nextPermutation(self, nums: List[int]) -> None:
12+
"""
13+
次の辞書順順列を nums に対して in-place で生成する
14+
:param nums: List[int] - 配列 (1 <= len(nums) <= 100)
15+
:return: None - 配列を直接変更するため返却値なし
16+
17+
処理手順:
18+
1. 後ろから転換点 i (nums[i] < nums[i+1]) を探索
19+
2. さらに後ろから nums[i] より大きい最小の要素 nums[j] を探索
20+
3. nums[i] と nums[j] をスワップ
21+
4. i+1 以降を反転 (昇順化)
22+
23+
時間計算量: O(n)
24+
空間計算量: O(1)
25+
"""
26+
n: int = len(nums)
27+
28+
# Step 1: 後ろから転換点を探す
29+
i: int = n - 2
30+
while i >= 0 and nums[i] >= nums[i + 1]:
31+
i -= 1
32+
33+
if i >= 0:
34+
# Step 2: 後ろから nums[i] より大きい要素を探す
35+
j: int = n - 1
36+
while j >= 0 and nums[j] <= nums[i]:
37+
j -= 1
38+
# Step 3: スワップ
39+
nums[i], nums[j] = nums[j], nums[i]
40+
41+
# Step 4: 転換点以降を反転
42+
left, right = i + 1, n - 1
43+
while left < right:
44+
nums[left], nums[right] = nums[right], nums[left]
45+
left += 1
46+
right -= 1
47+
# ```
48+
49+
# ---
50+
51+
# ### **動作確認例**
52+
53+
# ```python
54+
# nums1 = [1, 2, 3]
55+
# Solution().nextPermutation(nums1)
56+
# print(nums1) # [1, 3, 2]
57+
58+
# nums2 = [3, 2, 1]
59+
# Solution().nextPermutation(nums2)
60+
# print(nums2) # [1, 2, 3]
61+
62+
# nums3 = [1, 1, 5]
63+
# Solution().nextPermutation(nums3)
64+
# print(nums3) # [1, 5, 1]
65+
# ```
66+
67+
# ---
68+
69+
# ### **解析**
70+
71+
# * **時間計算量**
72+
73+
# * 転換点探索 O(n)
74+
# * 後ろから j 探索 O(n)
75+
# * 反転 O(n)
76+
# → 合計 **O(n)** (最大 n=100 なので高速)
77+
78+
# * **メモリ消費量**
79+
80+
# * 定数個の変数のみ使用し、配列は in-place 更新
81+
# → **O(1)**
82+
83+
# ---
84+
85+
# このアルゴリズムは **LeetCode 31. Next Permutation** にそのまま提出可能です。
86+
87+
# ---
88+
89+
# 次に、**この Python 実装の各処理を図解して解析したバージョン** も作成できますが、必要ですか?
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// 以下は、**TypeScript 5.1 (Node.js 18.16.1)** で動作する **関数ベースのLeetCode解答** です。
2+
3+
// * **処理時間**: O(n)
4+
// * **メモリ消費量**: O(1)(in-place処理)
5+
// * **クラス非使用**、関数と明示的な型注釈付き
6+
7+
// ---
8+
9+
// ```typescript
10+
/**
11+
* 次の辞書順順列を計算し、numsを直接変更する
12+
* @param nums 整数配列 (1 <= nums.length <= 100)
13+
* @returns void 配列を直接変更するため返却値なし
14+
*
15+
* アルゴリズム概要:
16+
* 1. 後ろから探索して、nums[i] < nums[i+1] となる最初の位置 i を探す
17+
* 2. さらに後ろから nums[i] より大きい最小の要素 nums[j] を探す
18+
* 3. nums[i] と nums[j] をスワップ
19+
* 4. i+1 以降を反転して昇順にする
20+
*
21+
* 時間計算量: O(n) (最大100要素)
22+
* 空間計算量: O(1) (定数メモリでin-place処理)
23+
*/
24+
function nextPermutation(nums: number[]): void {
25+
// 1. 後ろから転換点を探す
26+
let i: number = nums.length - 2;
27+
while (i >= 0 && nums[i] >= nums[i + 1]) {
28+
i--;
29+
}
30+
31+
if (i >= 0) {
32+
// 2. 後ろから nums[i] より大きい要素を探す
33+
let j: number = nums.length - 1;
34+
while (j >= 0 && nums[j] <= nums[i]) {
35+
j--;
36+
}
37+
// 3. スワップ
38+
[nums[i], nums[j]] = [nums[j], nums[i]];
39+
}
40+
41+
// 4. i+1 以降を反転
42+
let left: number = i + 1;
43+
let right: number = nums.length - 1;
44+
while (left < right) {
45+
[nums[left], nums[right]] = [nums[right], nums[left]];
46+
left++;
47+
right--;
48+
}
49+
}
50+
// ```
51+
52+
// ---
53+
54+
// ### **使用例(ローカルテスト用)**
55+
56+
// ```typescript
57+
// const nums1: number[] = [1, 2, 3];
58+
// nextPermutation(nums1);
59+
// console.log(nums1); // [1, 3, 2]
60+
61+
// const nums2: number[] = [3, 2, 1];
62+
// nextPermutation(nums2);
63+
// console.log(nums2); // [1, 2, 3]
64+
65+
// const nums3: number[] = [1, 1, 5];
66+
// nextPermutation(nums3);
67+
// console.log(nums3); // [1, 5, 1]
68+
// ```
69+
70+
// ---
71+
72+
// この実装は **LeetCode 31. Next Permutation** に直接提出可能です。
73+
74+
// * **O(n)** で最大 100 要素まで高速に処理
75+
// * **O(1)** 追加メモリで in-place 処理
76+

0 commit comments

Comments
 (0)