개발/algorithm

[프로그래머스][level3] 줄 서는 방법 -python

zzi_on2 2022. 1. 13. 11:50

문제 링크

https://programmers.co.kr/learn/courses/30/lessons/12936

 

코딩테스트 연습 - 줄 서는 방법

n명의 사람이 일렬로 줄을 서고 있습니다. n명의 사람들에게는 각각 1번부터 n번까지 번호가 매겨져 있습니다. n명이 사람을 줄을 서는 방법은 여러가지 방법이 있습니다. 예를 들어서 3명의 사람

programmers.co.kr

풀이 - 다른 블로그 참고 

  • 처음엔 순열로 풀었는데 시간초과 
# 시간 초과 
from itertools import permutations 
def solution(n, k):
  permute = list(permutations(range(1,n+1),n))
  
  return permute[k-1]
  • 팩토리얼 이용 

앞자리에 각 숫자가 오는 경우의 수는 뒷 숫자들 배열의 경우의 수와 같으므로 (n-1)!이다.

예를 들어,  n=4, k=7이라고 하면 제일 앞에 1이 오는 경우의 수는 2, 3, 4 가 배열되는 경우의 수인 3!이다. 

따라서 앞자리가 1이 되는 경우는 1-6번까지, 2가 되는 경우는 7-12번까지가 된다. 

따라서 k / (n-1)! 했을 때 몫이 맨 첫번째 자리가 되는 것이다.  

맨 앞자리가 정해졌으면 다음 결정해야될 수들은 하나씩 줄어들고, k도 k / (n-1)!의 나머지로 줄어든다. 

이를 모든 숫자가 배열될 때까지 반복한다. 

import math

def solution(n, k):
  answer = []
  
  # 각 숫자들 
  num = [i for i in range(1,n+1)]
  # 배열은 0부터 시작하므로 -1 
  k = k - 1 

 # 숫자가 다 배열될때까지 반복 
  while n > 0 :
    # 맨 앞자리에 올 숫자의 인덱스 
    a = k // math.factorial(n-1)
    # 구한 인덱스에 해당하는 숫자 answer에 넣음 
    answer.append(num[a]) 
    # 배열된 숫자 제거 
    del num[a]
    
    # k 줄이기 
    k = k % math.factorial(n-1)
    n -= 1 

  return answer

+ 2022.04.28 다시 풀이 

- 백트래킹으로 풀었는데 시간 초과 : 실제 경우의 수를 다 구해서 k번째 값을 가져오는 건 시간초과가 발생하는 듯 하다. 

answer = []
# 백트래킹으로 줄세우기 
def dfs(s,n):
    global visited 
    
    if len(s) == n:
        answer.append(list(map(int, s)))
    for i in range(1,n+1):
        if not visited[i]:
            visited[i] = True 
            s.append(i)
            dfs(s,n)
            visited[i] = False
            s.pop()
        
def solution(n, k):
    global visited

    s = []
    visited = [False] * (n+1)
    dfs(s,n)
        
    return answer[k-1]