타겟 넘버(python)

참고자료

프로그래머스 - 타겟 넘버

문제 설명

n개의 음이 아닌 정수가 있습니다. 이 수를 적절히 더하거나 빼서 타겟 넘버를 만들려고 합니다.
예를 들어 [1, 1, 1, 1, 1]로 숫자 3을 만들려면 다음 다섯 방법을 쓸 수 있습니다.

-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3

사용할 수 있는 숫자가 담긴 배열 numbers, 타겟 넘버 target이 매개변수로 주어질 때 숫자를 적절히 더하고 빼서 타겟 넘버를 만드는 방법의 수를 return 하도록 solution 함수를 작성해주세요.

제한 사항

  • 주어지는 숫자의 개수는 2개 이상 20개 이하입니다.
  • 각 숫자는 1 이상 50 이하인 자연수입니다.
  • 타겟 넘버는 1 이상 1000 이하인 자연수입니다.

입출력 예제

numberstargetreturn
[1, 1, 1, 1, 1]35

나의 생각

우선 완전 탐색을 시도해야된다고 생각을 했고, c++의 next_permutation STL이 생각이 났다.
예시를 보니 target을 만들려면 numbers 중 target의 수 만큼의 1은 무조건 필요하다고 느꼈다.
그리고 target 수 만큼 뺀 나머지 1의 갯수의 반은 +1, 나머지 반은 -1로 해서 next_permutation을 적용하면 되겠다.
하지만 python에서의 permutation과 c++ next_permutation은 약간의 차이가 존재했고,
문제를 잘 읽어보니 숫자가 무조건 1인 경우가 아니였다..

솔루션

  1. DP 느낌
    for문을 통해서 numbers의 숫자 탐색하고, for문을 통해서 기존 배열에 값에 숫자 값을 더한 값, 뺀 값을 저장하여 빈 배열에 저장 후 기존 배열을 빈 배열로 초기화.
    이 경우 기존 배열은 numbers의 각 숫자를 더한 값, 뺀 값의 결과들이 저장되어 있다. 이제 기존 배열에서 target의 값을 카운팅해주면 된다.

  2. DFS
    (numbers의 index, numbers 리스트, target, numbers[index]값이 더해지거나 뺀 값) 이렇게 4가지 인수가 필요. 시작은 0번째 index, value는 0부터 시작. index가 numbers의 길이(모든 numbers를 다 탐색한 후)일때 그리고 target == value일 때 갯수를 카운팅 후 함수 종료. index가 numbers의 길이(모든 numbers를 다 탐색한 후)일때 그리고 target != value일 때 아무 액션없이 함수 종료. 함수 종료 요건이 안되면 DFS(index + 1, numbers, target, value + numbers[index])를 부름(재귀) DFS(index + 1, numbers, target, value - numbers[index])를 부름(재귀)

  3. BFS
    queue에 index, value 값으로 초기화
    while queue:를 통해서 queue가 빈 리스트일 때까지 진행
    index == len(numbers)이고 target == value인 경우만 answer += 1을 해주고
    index == len(numbers)인 경우는 아무것도 안함
    그 외의 경우는 queue에 (index + 1, value + numbers[index]), (index + 1, value - numbers[index])을 추가

코드

  1. 첫번째 코드
    def solution(numbers, target):
     answers = [0]
    
     for n in numbers:
         new_answers = []
         for a in answers:
             new_answers.append(a + n)
             new_answers.append(a - n)
         answers = new_answers
    
     return answers.count(target)
    
  2. 두번째 코드
    • 갯수를 전역 변수를 설정해서 구해주는 경우.
      answer = 0
      def DFS(idx, numbers, target, value):
       global answer
       N = len(numbers)
       if(idx== N and target == value):
         answer += 1
         return
       if(idx == N):
         return
       DFS(idx+1,numbers,target,value+numbers[idx])
       DFS(idx+1,numbers,target,value-numbers[idx])
      
      def solution(numbers, target):
       global answer
       DFS(0,numbers,target,0)
       return answer
      
  3. 세번째 코드
    • 갯수를 지역 변수를 설정해서 구해주는 경우.
      def DFS(idx, numbers, target, value):
       ret = 0
       if idx == len(numbers):
         if target == value: return 1
         else: return 0
       ret += DFS(idx + 1, numbers, target, value + numbers[idx])
       ret += DFS(idx + 1, numbers, target, value - numbers[idx])
       return ret
      
      def solution(numbers, target):
       answer = DFS(0, numbers, target,0)
       return answer
      
  4. 네번째 코드
    • slicing을 활용하고 return에서 갯수를 구해주는 경우.
    • solution함수를 재귀 함수로 썼다는 점에서 신기했다.
      def solution(numbers, target):
       if not numbers and target == 0 :
         return 1
       elif not numbers:
         return 0
       else:
         return solution(numbers[1:], target-numbers[0]) + solution(numbers[1:], target+numbers[0])
      

몰랐던 지식

c++의 next_permutation과 python의 permutations의 차이.
순열을 구하는 것은 맞지만 c++의 nexT_permutation은 중복이 있는 원소의 경우 중복인 경우를 제외하고 순열을 만들어준다.

더 알아볼 지식

stackoverflow를 참고해서 python으로 c++ next_permutation을 구현해보자