백트래킹(backtracking)이란? : 한정 조건을 가진 문제를 푸는 전략이다. 해를 찾는 도중 해당 경로에서 해가 나오지 않고 막히면, 되돌아가서 다른 경로에서 해를 찾아가는 기법을 말한다.
출처: 퇴각검색 - 위키백과
Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order.
해석: 모든 순열의 경우의 수를 구하라.
순열(Permutation)이란?
서로 다른 n개 중에 n개를 모두 선택하는 경우의 수를 의미한다. 순서가 다르면 다른 경우의 수로 본다.
예를 들어 [1, 2, 3] 이라는 배열이 있다면 서로 다른 순열의 경우의 수는 총3!
인 여섯 가지가 나온다.[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]
Example 1:
Input: nums = [1,2,3]
Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
Example 2:
Input: nums = [0,1]
Output: [[0,1],[1,0]]
Example 3:
Input: nums = [1]
Output: [[1]]
Constraints:
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
result = []
self.dfs(nums, [], result)
return result
def dfs(self, nums, path, solution):
# 만약 nums 배열에 아무 원소도 없다면, path 배열에 모든 원소가 이동되었다는 뜻.
# 따라서 해당 path 배열을 정답 (result) 배열에 추가한다.
# deep copy로 추가
if len(nums) == 0:
result.append(path[:])
return
# backtracking
else:
for i in range(len(nums)):
# nums 배열에서 n 번째 숫자를 제거하고, temp 배열에 추가한다
self.dfs(nums[:i]+nums[i+1:], path+[nums[i]], result)
Example1의 예시를 가지고 백트래킹 문제를 해결해보자.
Input: nums = [1,2,3]
Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
path
라는 빈배열과 nums
라는 기존 숫자 배열 두 가지를 사용한다. path
배열에 추가한 숫자는 기존 nums
배열에서 제거를 해, 해당 경로를 지나갔다고 체크한다. nums
배열에 값이 하나도 없다면, 해당 경로는 더이상 추가할 숫자가 없다는 뜻이므로, 이전 분기점으로 돌아간다. (백트래킹)문제 해결과정을 아래와 같이 트리로 나타낼 수 있다. 첫번째 조합인 [1, 2, 3]
을 얻는 방법을 설명하면 아래와 같다.
path
: [] nums
: [1, 2, 3]nums
의 첫번째 원소 1를 path
에 넣고 다음 단계로 넘어감 path
: [1] nums
: [2, 3]nums
의 첫번째 원소 2를 path
에 넣고 다음 단계로 넘어감 path
: [1, 2] nums
: [3]nums
의 첫번째 원소 3를 path
에 넣고 다음 단계로 넘어감 path
: [1, 2, 3] nums
: []nums
에 값이 없으므로, path
에서 구한 조합을 result
해답 배열에 추가함. (백트래킹) 더 이상 다음 단계가 없으므로, 다음 경로로 넘어간다.단계별로 시각화를 하자면 아래 그림과 같다:
코드로 시각화가 잘 된 예시가 있어서 참고하면 좋을 듯 하다⬇
dfs(nums = [1, 2, 3] , path = [] , result = [] )
|____ dfs(nums = [2, 3] , path = [1] , result = [] )
| |___dfs(nums = [3] , path = [1, 2] , result = [] )
| | |___dfs(nums = [] , path = [1, 2, 3] , result = [[1, 2, 3]] ) # added a new permutation to the result
| |___dfs(nums = [2] , path = [1, 3] , result = [[1, 2, 3]] )
| |___dfs(nums = [] , path = [1, 3, 2] , result = [[1, 2, 3], [1, 3, 2]] ) # added a new permutation to the result
|____ dfs(nums = [1, 3] , path = [2] , result = [[1, 2, 3], [1, 3, 2]] )
| |___dfs(nums = [3] , path = [2, 1] , result = [[1, 2, 3], [1, 3, 2]] )
| | |___dfs(nums = [] , path = [2, 1, 3] , result = [[1, 2, 3], [1, 3, 2], [2, 1, 3]] ) # added a new permutation to the result
| |___dfs(nums = [1] , path = [2, 3] , result = [[1, 2, 3], [1, 3, 2], [2, 1, 3]] )
| |___dfs(nums = [] , path = [2, 3, 1] , result = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1]] ) # added a new permutation to the result
|____ dfs(nums = [1, 2] , path = [3] , result = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1]] )
|___dfs(nums = [2] , path = [3, 1] , result = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1]] )
| |___dfs(nums = [] , path = [3, 1, 2] , result = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2]] ) # added a new permutation to the result
|___dfs(nums = [1] , path = [3, 2] , result = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2]] )
|___dfs(nums = [] , path = [3, 2, 1] , result = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] ) # added a new permutation to the result