Skip to content
Open
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
38 changes: 38 additions & 0 deletions 46.Permutations/memo.md
Original file line number Diff line number Diff line change
@@ -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で持つべきだろう




23 changes: 23 additions & 0 deletions 46.Permutations/sol1.py
Original file line number Diff line number Diff line change
@@ -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):
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

実質外側のループを回し終えたあとの処理が、ループの内側に書かれている点に違和感を感じました。一度ループを抜けてから、この処理を書いたほうが、読み手にとって理解しやすくなると思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

なるほど、採用させていただきました。pivot変数でiを保存し、その値に応じた分岐を行うようにしました

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
23 changes: 23 additions & 0 deletions 46.Permutations/sol1_revised.py
Original file line number Diff line number Diff line change
@@ -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
29 changes: 29 additions & 0 deletions 46.Permutations/sol1_revised2.py
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions 46.Permutations/sol2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import itertools


class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
return list(itertools.permutations(nums))
14 changes: 14 additions & 0 deletions 46.Permutations/sol3.py
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions 46.Permutations/sol3_revised.py
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions 46.Permutations/sol4.py
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions 46.Permutations/sol4_revised.py
Original file line number Diff line number Diff line change
@@ -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