diff --git a/Python3/46. Permutations.md b/Python3/46. Permutations.md new file mode 100644 index 0000000..69a3723 --- /dev/null +++ b/Python3/46. Permutations.md @@ -0,0 +1,92 @@ +## Step 1. Initial Solution + +- 一つずつ残っているリストから数字を取り出して末尾に入れる +- 作成済みの順列と残りのリストをペアで保持して処理していく +- なぜかエラー→next_remaining_nums=remaining_numsにすると参照先をremoveしてしまう + - copy.deepcopyで対応 + +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + result = [] + prefix_to_remaining = [([], nums)] + while prefix_to_remaining: + prefix, remaining_nums = prefix_to_remaining.pop() + for num in remaining_nums: + next_prefix = prefix + [num] + next_remaining_nums = remaining_nums.copy() + next_remaining_nums.remove(num) + if not next_remaining_nums: + result.append(next_prefix) + else: + prefix_to_remaining.append((next_prefix, next_remaining_nums)) + return result +``` + +### Complexity Analysis + +- 時間計算量:O(N*N!) +- 空間計算量:O(N*N!) + +## Step 2. Alternatives + +- 再帰関数で先頭とそれ以外の並び替えを回す方法が多い + - https://github.com/tokuhirat/LeetCode/pull/50/files#diff-f980f45b4d4f94c41556977f060a371872f422650416425386f1322e52deba58R2 + - ここは綺麗に書けていて分かりやすいと感じた + - https://github.com/tokuhirat/LeetCode/pull/50/files#diff-f980f45b4d4f94c41556977f060a371872f422650416425386f1322e52deba58R47-R58 + - まだ入っていないものを追加していく方法 + - https://github.com/tokuhirat/LeetCode/pull/50/files#r2278840164 + - 時間計算量の話は1≤num.lengths≤6では線形の方が速そうというところ + - https://github.com/docto-rin/leetcode/pull/51/files#diff-47cd87d2eeba6169d55b484ea322c16f1a03278b0d29a5b0d00f771aaf816f8bR74-R78 + - Backtrackingとも呼ぶらしい?がほぼ同じに見える +- 再帰で書いてみる + +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + if len(nums) == 1: + return [nums] + + permutations = [] + for i in range(len(nums)): + prefix = [nums[i]] + sub_permutations = self.permute(nums[:i]+nums[i+1:]) + for sub_permutation in sub_permutations: + permutations.append(prefix+sub_permutation) + return permutations +``` + +- 既出を管理する方法の方がスライスしない分速いか + +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + def permute_helper(prefix: List[int]) -> List[List[int]]: + if len(prefix) == len(nums): + return [prefix] + permutations = [] + for num in nums: + if num in prefix: + continue + permutations += permute_helper(prefix + [num]) + return permutations + + return permute_helper([]) +``` + +## Step 3. Final Solution + +- ヘルパー関数を使う方法に帰着 + +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + def permute_helper(permuted_nums: List[int]) -> List[List[int]]: + permutations = [] + for num in nums: + if num in permuted_nums: + continue + permutations += permute_helper(permuted_nums + [num]) + return permutations if permutations else [permuted_nums] + return permute_helper([]) +```