Python_알고리즘/Gold V

1038. [Python]감소하는 수

최근영 2023. 9. 8. 16:42

1. 문제

 

https://www.acmicpc.net/problem/1038

 

1038번: 감소하는 수

음이 아닌 정수 X의 자릿수가 가장 큰 자릿수부터 작은 자릿수까지 감소한다면, 그 수를 감소하는 수라고 한다. 예를 들어, 321과 950은 감소하는 수지만, 322와 958은 아니다. N번째 감소하는 수를

www.acmicpc.net

 

2. 접근 방법

 

  • 시간 제한: 1초
  • 메모리 제한: 128MB
  • 백트래킹
  • 브루트포스

 

3. 파이썬 코드

 

# 문자열 체크하는 함수
def checking(num, M):
    # 글로벌 문자 변수 선언
    global check
    global cnt
    global ans
    # M 의 길이가 1로 끝일때
    if M == 1:
        # 이전의 check 값과 num[0] 값의 크기를 비교해 작으면 cnt += 1
        if check > int(num[0]):
            cnt += 1
        # 외의 경우 ans = 1 반환
        else:
            ans = 1
        return
    # check 값이 비어있는 경우
    if check == "":
        # num[0]의 값을 초기값으로 넣어줌
        check = int(num[0])
        # 1 ~ 끝 까지 M은 문자열 길이로 생각해서 -1 해서 넣어줌
        checking(num[1:], M-1)
    # check에 값이 있는 경우
    else:
        # check 보다 값이 작은 경우 재귀
        if int(num[0]) < check:
            check = int(num[0])
            checking(num[1:], M-1)
        # 외의 경우
        else:
            # ans 에 현재 문자열의 길이 M 넣어줌
            ans = M
            return

N = int(input())
# N 이 10보다 작은 경우 N 출력
if N < 10:
    print(N)
# 외의 경우
else:
    # cnt 초기값 9, number는 10 으로 선언
    cnt = 9
    number = 10
    # 2자리수부터 비교하기 때문에 num_length 2로 선언
    num_length = 2
    # cnt 값이 1,000,000 이하까지
    while cnt <= 10**6:
        # check 값 ""로 초기화
        check = ""
        # ans에 문자열 길이 넣어줌
        ans = len(str(number))
        # ans 값이 num_length 보다 크면 ans 값으로 갱신
        if ans > num_length:
            num_length = ans
        # 함수 실행 => number 문자열, 문자열 길이 인자로 넣어줌
        checking(str(number), ans)
        # 초기값과 같은 경우
        if ans == num_length:
            # cnt 값이 증가했기 때문에 number + 1
            number += 1
        # 초기값과 다른 경우
        else:
            # number 값의 몫의 +1 해서 10**ans 한 값을 넣어줌
            number = (number//(10**ans) + 1) * (10**ans)
        # cnt 값이 N과 같은 경우
        if cnt == N:
            # number 에서 -1 한 값 출력 후 반복문 탈출
            print(number-1)
            break
        # 만약 9 넘어갈 경우 -1 출력
        if num_length > 10:
            print(-1)
            break

 

4. 문제를 풀고난 후 생각

 

  • N의 값은 몇번째 수인지 찾는 문제였고 최대 1,000,000 번째 수까지 물어보는 문제였다.

  • number 로 값을 1씩 증가시키며 10미만이였을 경우 0~9 값을 그대로 출력해줬고, 10부터 넘어갈 때마다 함수를 사용해서 cnt 값을 증가시켰다.

  • 10이 올경우 check = 1 을 넣고 재귀를 통해 0 을넣어 1과 0을 비교해서 작으면 cnt 증가 외의 경우 ans = 1을 반환해줬고 ans 값을 통해서 몇번째 자리에서 반환됐는지 체크를 해줬다.

  • 이 체크한 값을 바탕으로 3221 이 들어갈 경우 322 까지 값을 확인한 후 2번째 자리에서 이후 어느 값이오든 작기 때문에 3221에서 불필요한 연산없이 3300으로 넘어갈 수 있도록 ans 값을 활용했다.

  • 마지막 값이 9876543210 이므로 문자열 길이가 10을 넘을 경우 -1을 출력해준 후 break를 통해서 불필요한 연산 자체를 시행하지 않도록 해줬다.

  • 처음에는 1부터 1,000,000 까지 탐색하는 문제인 줄 알고 계산했지만, 틀린 후 문제를 다시 읽어보니 1,000,000 번째 수까지 계산을 해야하는 문제였고, 재귀랑 백트래킹을 통해서 가지치기를 시행하면 풀 수 있을 것 같다 생각해서 ans 라는 변수를 통해서 몇번째 자리에서 돌아오는지, num_length를 통해서 자리수가 몇개인지 등을 체크해서 적절한 값을 number에 할당해줬다.

 

5. 문제를 푸는데 도움이 되는 지식

 

  • 백트래킹
  • 브루트포스