diff --git a/46.Permutations/memo.md b/46.Permutations/memo.md new file mode 100644 index 0000000..de36bd7 --- /dev/null +++ b/46.Permutations/memo.md @@ -0,0 +1,38 @@ +# 46. Permutations + +https://leetcode.com/problems/permutations/description/ + +見たことあるやつだと思いながら自分では書けず、調べた +next permutationというアルゴリズムを学んだ +時間計算量 O(N N!)、空間計算量 O(1) +後からdeepcopyを使う必要はないことに気がついたので書き直す + +- mutableなオブジェクトを含むオブジェクト:深いコピー +- immutableなオブジェクトだけを含むオブジェクト:浅いコピー + + +itertoolsにも実装がある: sol2.py + +https://github.com/naoto-iwase/leetcode/blob/0046-permutations/0046-permutations/0046-permutations.md#%E5%AE%9F%E8%A3%852 + +https://github.com/mamo3gr/arai60/blob/46_permutations/46_permutations/memo.md + +https://leetcode.com/problems/permutations/solutions/18239/a-general-approach-to-backtracking-questions-in-java-subsets-permutations-combination-sum-palindrome-partioning/ + +バックトラック:「探索中に一時的に状態を変更し、再帰から戻るときに必ず元に戻す DFS」 + +おそらくこの問題の題意はこれだろう。 +スタックと再帰関数で実装する + +sol3.py +人のコードを一通り見た後に空で書くとこうなった +時間:O(n n!)、空間:ざっくりO(n n!) +- geminiにrevisedさせるとビットマスクを提案された + +sol4.py +geminiにrevisedさせると順序一定のためにsortを提案された +値に重複があるときはindexで持つべきだろう + + + + diff --git a/46.Permutations/sol1.py b/46.Permutations/sol1.py new file mode 100644 index 0000000..f4e8fb0 --- /dev/null +++ b/46.Permutations/sol1.py @@ -0,0 +1,23 @@ +import copy + + +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + def next_permutation(sequence): + for i in range(len(sequence) - 1, 0, -1): + if sequence[i] <= sequence[i - 1]: + continue + for j in range(len(sequence) - 1, i - 1, -1): + if sequence[j] >= sequence[i - 1]: + sequence[i - 1], sequence[j] = sequence[j], sequence[i - 1] + sequence[i:] = reversed(sequence[i:]) + return True + + return False + + nums_sorted = sorted(nums) + permutations = [copy.deepcopy(nums_sorted)] + while next_permutation(nums_sorted): + permutations.append(copy.deepcopy(nums_sorted)) + + return permutations diff --git a/46.Permutations/sol1_revised.py b/46.Permutations/sol1_revised.py new file mode 100644 index 0000000..d095ea9 --- /dev/null +++ b/46.Permutations/sol1_revised.py @@ -0,0 +1,23 @@ +import copy + + +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + def next_permutation(sequence): + for i in range(len(sequence) - 1, 0, -1): + if sequence[i] <= sequence[i - 1]: + continue + for j in range(len(sequence) - 1, i - 1, -1): + if sequence[j] >= sequence[i - 1]: + sequence[i - 1], sequence[j] = sequence[j], sequence[i - 1] + sequence[i:] = reversed(sequence[i:]) + return True + + return False + + nums_sorted = sorted(nums) + permutations = [nums_sorted.copy()] + while next_permutation(nums_sorted): + permutations.append(nums_sorted.copy()) + + return permutations diff --git a/46.Permutations/sol1_revised2.py b/46.Permutations/sol1_revised2.py new file mode 100644 index 0000000..79d3515 --- /dev/null +++ b/46.Permutations/sol1_revised2.py @@ -0,0 +1,29 @@ +import copy + + +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + def next_permutation(sequence): + n = len(sequence) + pivot = -1 + + for i in range(n - 1, 0, -1): + if sequence[i] > sequence[i - 1]: + pivot = i - 1 + break + + if pivot == -1: + return False + + for j in range(n - 1, pivot, -1): + if sequence[j] > sequence[pivot]: + sequence[pivot], sequence[j] = sequence[j], sequence[pivot] + sequence[pivot + 1 :] = reversed(sequence[pivot + 1 :]) + return True + + nums_sorted = sorted(nums) + permutations = [nums_sorted.copy()] + while next_permutation(nums_sorted): + permutations.append(nums_sorted.copy()) + + return permutations diff --git a/46.Permutations/sol2.py b/46.Permutations/sol2.py new file mode 100644 index 0000000..1e38798 --- /dev/null +++ b/46.Permutations/sol2.py @@ -0,0 +1,6 @@ +import itertools + + +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + return list(itertools.permutations(nums)) diff --git a/46.Permutations/sol3.py b/46.Permutations/sol3.py new file mode 100644 index 0000000..64bf59b --- /dev/null +++ b/46.Permutations/sol3.py @@ -0,0 +1,14 @@ +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + permutations = [] + frontier = [([], set(nums))] + + while frontier: + fixed, not_used = frontier.pop() + if len(fixed) == len(nums): + permutations.append(fixed) + continue + for num in not_used: + frontier.append((fixed + [num], not_used - {num})) + + return permutations diff --git a/46.Permutations/sol3_revised.py b/46.Permutations/sol3_revised.py new file mode 100644 index 0000000..024d329 --- /dev/null +++ b/46.Permutations/sol3_revised.py @@ -0,0 +1,19 @@ +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + n = len(nums) + permutations = [] + frontier = [([], (1 << n) - 1)] + + while frontier: + fixed, mask = frontier.pop() + if len(fixed) == n: + permutations.append(fixed) + continue + m = mask + while m: + lsb = m & -m + i = lsb.bit_length() - 1 + m ^= lsb + frontier.append((fixed + [nums[i]], mask ^ lsb)) + + return permutations diff --git a/46.Permutations/sol4.py b/46.Permutations/sol4.py new file mode 100644 index 0000000..0c23852 --- /dev/null +++ b/46.Permutations/sol4.py @@ -0,0 +1,19 @@ +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + permutations = [] + fixed = [] + not_used = set(nums) + + def traverse(): + if len(fixed) == len(nums): + permutations.append(fixed.copy()) + return + for num in list(not_used): + not_used.remove(num) + fixed.append(num) + traverse() + fixed.pop() + not_used.add(num) + + traverse() + return permutations diff --git a/46.Permutations/sol4_revised.py b/46.Permutations/sol4_revised.py new file mode 100644 index 0000000..3b84f2e --- /dev/null +++ b/46.Permutations/sol4_revised.py @@ -0,0 +1,19 @@ +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + permutations = [] + fixed = [] + not_used = set(nums) + + def traverse(): + if len(fixed) == len(nums): + permutations.append(fixed.copy()) + return + for num in sorted(list(not_used)): + not_used.remove(num) + fixed.append(num) + traverse() + fixed.pop() + not_used.add(num) + + traverse() + return permutations