Given an array nums of distinct integers, return all the possible permutations.
You can return the answer in any order.
Input: nums = [1,2,3]
Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
Input: nums = [0,1]
Output: [[0,1],[1,0]]
Input: nums = [1]
Output: [[1]]
# 4자리 수: 4 x 3 x 2 x 1 = 24 경우의 수
1 2 3 4
1 2 4 3
1 3 2 4
1 3 4 2
1 4 2 3
1 4 3 2
2 1 3 4
2 1 4 3
2 3 1 4
2 3 4 1
2 4 1 3
2 4 3 1
3 1 2 4
3 1 4 2
3 2 1 4
3 2 4 1
3 4 1 2
3 4 2 1
4 1 2 3
4 1 3 2
4 2 1 3
4 2 3 1
4 3 1 2
4 3 2 1
# source: https://www.nayuki.io/page/next-lexicographical-permutation-algorithm
def do_permutation(nums, nums_len):
# 1. 1 6 7 3 5 4 2
idx1 = nums_len - 1
while idx1 > 0 and nums[idx1 - 1] >= nums[idx1]:
idx1 -= 1
# 2. idx1이 0보다 작으면 모두 내림차순으로 종료 케이스
if idx1 <= 0:
return False
# 3. 찾아낸 오름차순인 수보다 큰 수가 우측에 있으면, `다음 내림차순` 준비
idx2 = nums_len - 1
while nums[idx2] <= nums[idx1 - 1]:
idx2 -= 1
# 다음 내림차순 위한 치환
# 4. 1 6 7 4 5 3 2
nums[idx1 - 1], nums[idx2] = nums[idx2], nums[idx1 - 1]
# 다음 내림차순이 시작된 후 idx1과 idx2 사이의 숫자는 다시 정순으로 정렬되어야 다음 순열이 진행되므로, 뒤집는다
# 5. 1 6 7 4 2 3 5
idx2 = nums_len - 1
while idx1 < idx2:
nums[idx1], nums[idx2] = nums[idx2], nums[idx1]
idx1 += 1
idx2 -= 1
return True
# 1. 1 6 7 3 5 4 2
while
문의 목적: 오름차순인 인덱스(nums[4] = 3
) 찾기# 2. 종료 케이스
# 3. 다음 내림차순 수의 인덱스 찾기
while
문의 목적: 다음 내림차순 순열을 만들기 위한 다음 수의 인덱스 찾기nums[6] = 4
) 찾는다# 4. 1 6 7 4 5 3 2
# 5. 1 6 7 4 2 3 5
nums[4]
와 nums[6]
을 바꾼 것은 다음 내림차순 순열 시작을 의미한다
1 6 7 3 5 4 2
에서 5 4 2
는 이미 역순 정렬이 끝났음을 의미1 6 7 4 5 3 2
에서 2
와 5
를 치환하는 것만으로 정순 정렬이 됨을 의미5 4 3 2 1
에서 5
와 1
을 치환하고, 4
와 2
를 치환하면 1 2 3 4 5
가 되는 것과 같다첫번째 while
문: 오름차순인 부분의 인덱스를 찾고두번째 while
문: 다음 내림차순이 될 수를 찾는다세번째 while
문: 다음 내림차순이 된 수 다음 이미 역순 정렬되어 있는 수를 정순 정렬로 바꾼다def permute(self, nums: List[int]) -> List[List[int]]:
nums = sorted(nums)
ans = [nums[:]]
def do_permutation(nums_curr, nums_len):
# 1. 1 6 7 3 5 4 2
idx1 = nums_len - 1
while idx1 > 0 and nums_curr[idx1 - 1] >= nums_curr[idx1]:
idx1 -= 1
# 2. 종료 케이스
if idx1 <= 0:
return False
# 3.
idx2 = nums_len - 1
while nums_curr[idx2] <= nums_curr[idx1 - 1]:
idx2 -= 1
# 4. 1 6 7 4 5 3 2
nums_curr[idx1 - 1], nums_curr[idx2] = nums_curr[idx2], nums_curr[idx1 - 1]
# 5. 1 6 7 4 2 3 5
idx2 = nums_len - 1
while idx1 < idx2:
nums_curr[idx1], nums_curr[idx2] = nums_curr[idx2], nums_curr[idx1]
idx1 += 1
idx2 -= 1
ans.append(nums_curr[:])
return True
while result := do_permutation(nums, len(nums)):
continue
return ans
25 / 25 test cases passed.
Status: Accepted
Runtime: 40 ms
Memory Usage: 14.2 MB
depth
1 [ 1, 2, 3 ]
2 [2] [3] [1] [3] [1] [2]
3 [3] [2] [3] [1] [2] [1]
종료 종료 종료 종료 종료 종료
[1, 2, 3]
)의 길이와 depth가 같아지는 경우def second(self, nums: List[int]) -> List[List[int]]:
ans = []
nums_len = len(nums)
'''
nums: 원본 배열. 요소를 계속 붙여 나가야 하므로 계속 전달
permutaion: 순열을 만들어 나갈 배열
depth: 백 트래킹 조건
'''
def dfs(nums, permutaion, depth):
# 배열의 길이만큰 깊어지면 종료
if depth == nums_len:
ans.append(permutaion)
return
for num in nums:
if not num in permutaion:
"""
permutaion.append(num) (X)
- append를 하면 기존 permutation에 추가되고, 유지된다.
- 리프 노드에서 백 트래킹 후 기존 permutation 배열이 있어야 하므로, 전달 시에는 이전 배열 유지 위해 + 연산자 사용
"""
dfs(nums, permutaion + [num], depth + 1)
dfs(nums, [], 0)
return ans
25 / 25 test cases passed.
Status: Accepted
Runtime: 32 ms
Memory Usage: 14.3 MB
def third(self, nums: List[int]) -> List[List[int]]:
return list(map(list, itertools.permutations(nums)))