Skip to content
Open
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
140 changes: 140 additions & 0 deletions 46. Permutaions/46. Permutaions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
## STEP 0
Back Trackingがよくわかってなかったので解説とか見ながら書いた。
```python
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
res = []
def backtrack(used, current_list):
if len(current_list) == len(nums):
res.append(list(current_list))
return
for num in nums:
if num not in used:
current_list.append(num)
used.add(num)
backtrack(used, current_list)
current_list.pop()
used.remove(num)

backtrack(set(),[])
return res
```

## STEP 1
忘れた頃に解き直したら要素の検索の速さに気を配るのを忘れている。
```python
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
res = []
length = len(nums)
def generate_permutation(permutation):
if len(permutation) == length:
res.append(list(permutation))
for num in nums:
if num in permutation:
continue
permutation.append(num)
generate_permutation(permutation)
permutation.pop()
generate_permutation([])
return res
```


## STEP 2
変数の名前をちょっと見直した。
他の人のコードを見ると存在確認したいものが静的な場合特にused = [False] * len(nums)使うと良さそう。動的に増える場合でもsetだと拡張する時にリハッシュするのに時間かかるから変化の程度によっては動的でもused = [False] * len(nums)としてもあんまり変わんないかもしれない。要素がuniqueでなければsetは使えないし。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

存在確認の配列を使う方法もあるんですね。勉強になりました。


```python
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
all_permutations = []
length = len(nums)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

lengthlen(nums) の値を代入していますが、length だと「何のlengthだっけ?」となるので自分なら len(nums) のままにします。

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.

ここは自分でもどうするか迷いましたし、何回も使うわけではないので確かにlen(nums)のままの方がいいかもしれないですね。

def generate_permutation(permutation, used_indices):
if len(permutation) == length:
all_permutations.append(list(permutation))
return
for i, num in enumerate(nums):
if used_indices[i]:
continue
permutation.append(num)
used_indices[i] = True
generate_permutation(permutation, used_indices)
permutation.pop()
used_indices[i] = False
generate_permutation([], [False] * length)
return all_permutations
```

手動でスタックを使うバージョンも書いてみた。
再帰で書いても結局中身ではコールスタックに積んでるからアルゴリズム的は一緒なんだけど、スタック領域を圧迫せずヒープで済ませられるからメモリの制限が大きそうな時はこっちの方がいいな。

```python
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
all_permutations = []
length = len(nums)
state_stack = [([], [False] * length)]
while state_stack:
permutation_so_far, used_indices = state_stack.pop()
if len(permutation_so_far) == length:
all_permutations.append(permutation_so_far)
continue
for index, num in enumerate(nums):
if used_indices[index]:
continue
new_used_indices = used_indices.copy()
new_used_indices[index] = True
new_permutation = [*permutation_so_far, num]
state_stack.append((new_permutation, new_used_indices))
return all_permutations
```


## STEP3
再帰と手動スタックバージョンをそれぞれ3回ずつ書いた。`new_permutation = permutation_so_far + [num]` にするか `new_permutation = [*permutation, num]` で選択肢があるが後者がモダンらしいし書いたことなかったのでそれで練習してみた。

再帰
```python
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
all_permutations = []
length = len(nums)
def generate_permutation(permutation_so_far: List[int], used_indices: List[bool]) -> None:
if len(permutation_so_far) == length:
all_permutations.append(list(permutation_so_far))
return
for index, num in enumerate(nums):
if used_indices[index]:
continue
permutation_so_far.append(num)
used_indices[index] = True
generate_permutation(permutation_so_far, used_indices)
permutation_so_far.pop()
used_indices[index] = False
generate_permutation([], [False] * length)
return all_permutations
```

手動stack
上のコードを練習している途中で `used_indices = [False] * len(nums)` はもはやbitmaskでいいのではと思ったので変えてみた。配列の方が可読性は高いし、要素数が少ない時しか使えない手だけど。
```python
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
all_permutations = []
size = len(nums)
GOAL_MASK = (1 << size) - 1
used_mask = 0
status_stack = [([], 0)]
while status_stack:
permutation_so_far, used_mask = status_stack.pop()
if used_mask == GOAL_MASK:
all_permutations.append(permutation_so_far)
continue
for index, num in enumerate(nums):
if used_mask & (1 << index):
continue
new_permutation = [*permutation_so_far, num]
status_stack.append((new_permutation, used_mask | (1 << index)))
return all_permutations
```