46 순열

문제

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]]

해결

1st

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
# 2. 종료 케이스
# 3. 다음 내림차순 수의 인덱스 찾기
# 4. 1 6 7 4 5 3 2
# 5. 1 6 7 4 2 3 5
정리

1 코드

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

1 결과: 성공

25 / 25 test cases passed.
Status: Accepted
Runtime: 40 ms
Memory Usage: 14.2 MB

2nd

2 생각

DFS?
경우의 수?
depth
1       [  1,             2,             3  ]
2       [2]  [3]        [1]  [3]     [1]  [2]
3       [3]  [2]        [3]  [1]     [2]  [1]
        종료 종료       종료 종료     종료 종료

2 코드

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

2 결과: 성공

25 / 25 test cases passed.
Status: Accepted
Runtime: 32 ms
Memory Usage: 14.3 MB

3rd

3 itertools

3 코드

def third(self, nums: List[int]) -> List[List[int]]:
    return list(map(list, itertools.permutations(nums)))

회고