Sad Puppy 3 [프로그래머스 lv2] k진수에서 소수 개수 구하기 :: 개발자 아지트

https://school.programmers.co.kr/learn/courses/30/lessons/92335#

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

문제설명

 

양의 정수 n이 주어집니다. 이 숫자를 k진수로 바꿨을 때, 변환된 수 안에 아래 조건에 맞는 소수(Prime number)가 몇 개인지 알아보려 합니다.

 

0P0처럼 소수 양쪽에 0이 있는 경우

P0처럼 소수 오른쪽에만 0이 있고 왼쪽에는 아무것도 없는 경우

0P처럼 소수 왼쪽에만 0이 있고 오른쪽에는 아무것도 없는 경우

P처럼 소수 양쪽에 아무것도 없는 경우

, P는 각 자릿수에 0을 포함하지 않는 소수입니다.

예를 들어, 101 P가 될 수 없습니다.

 

예를 들어, 437674 3진수로 바꾸면 211020101011입니다. 여기서 찾을 수 있는 조건에 맞는 소수는 왼쪽부터 순서대로 211, 2, 11이 있으며, 3개입니다. (211, 2, 11 k진법으로 보았을 때가 아닌, 10진법으로 보았을 때 소수여야 한다는 점에 주의합니다.) 211 P0 형태에서 찾을 수 있으며, 2 0P0에서, 11 0P에서 찾을 수 있습니다.

 

정수 n k가 매개변수로 주어집니다. n k진수로 바꿨을 때, 변환된 수 안에서 찾을 수 있는 위 조건에 맞는 소수의 개수를 return 하도록 solution 함수를 완성해 주세요.

 

문제 해결 방법

 

주어진 값을 n진수의 값으로 변환하기 위해서 divmod함수를 사용하여 나머지 값을 모아 하나의 문자열 형태로 만든뒤, 뒤집어줬다. 

해당 문자열에서 소수로 판단할 수를 하나의 리스트에 담아 모아주었다. 

 

해당 리스트의 값을 대상으로 소수를 판별하고 값을 리턴했다. 

 

 

코드 구현

 

from collections import deque
def solution(n, k):
    answer = 0
    strr = ''
    
    # n진수 -> n진수로 변환법
    while n > 0:
        n, mod = divmod(n, k)
        strr += str(mod)

    # 문자열에서 소수 조건에 맞는 수 세아리기 
    
    strr = strr[::-1]
    strr = list(strr)
    
    checkList = []
    
    tmp = ''
    cnt = 0
    for idx, i in enumerate(strr):
        if i !='0':
            tmp+=str(i)
            cnt+=1
            if idx == len(strr)-1:
                checkList.append(tmp)
        else:
            while cnt > 0:
                checkList.append(tmp)
                cnt=0
            
            tmp=''
            cnt = 0
            
    for i in checkList:
        if i == '1':
            continue
     
        cnt = 0
        
        for k in range(2, int((int(i) ** 0.5)+1)):
            if int(i) % k == 0:
                cnt +=1
        
        if cnt == 0:
            answer+=1
    
    return answer

 

시간/공간 복잡도

 

최악의 경우 O(N)

 

 

최적화 및 개선 / 어려웠던 점

 

주어진 값을 n진수로 변환할 때 코드를 통한 변환 방법을 까먹어서 다시 찾아봤고, 

문자열을 쉽게 뒤집는 방법을 알게됐다. 

 

주어진 값에 대해 소수판별을 하기 위해서 에라토스테네스의 채 방법을 사용했는데, 두개의 테스트케이스에서 자꾸 시간초과가 났다. 해당 방법을 사용할 수 없었다. 

 

소수판별을 해야하는 값들 중에서 가장 긴 값의 범위 만큼만 에라토스테네스의 채 방법을 사용해서 코드를 작성해봤지만, 그 역시도 시간 초과가 났다. 해당 방법을 사용할 수 없었다. 

 

아예 에라토스테네스의 채 방법을 사용하지 않고, 바로바로 소수 판별을 하는게 나으려나 싶어서 아래와 같은 방식을 사용했었다. 

 

from collections import deque
def solution(n, k):
    answer = 0
    strr = ''
    
    # n진수 -> n진수로 변환법
    while n > 0:
        n, mod = divmod(n, k)
        strr += str(mod)

    # 문자열에서 소수 조건에 맞는 수 세아리기 
    
    strr = strr[::-1]
    
    strr = list(strr)
    
    checkList = []
    
    tmp = ''
    cnt = 0
    for idx, i in enumerate(strr):
        if i !='0':
            tmp+=str(i)
            cnt+=1
            if idx == len(strr)-1:
                checkList.append(tmp)
                
        else:
            while cnt > 0:
                checkList.append(tmp)
                cnt=0
            
            tmp=''
            cnt = 0
    #print('checkList', checkList)
    for i in checkList:
        #print(i, answer)
        if i == '1':
            continue
        
        if i == '2' or i == '3' or i == '5' or i == '7':
            
            answer+=1
        else:
            if int(i) % 2 == 0: 
                continue
            if int(i) % 3 == 0: 
                continue
            if int(i) % 5 == 0: 
                continue
            if int(i) % 7 == 0: 
                continue
            if int(i) % (int(i) ** 0.5) == 0:
                continue
            
            #print('check', i)
            answer+=1
            
        #print(i, answer)
    
    return answer

 

처음에는 2, 3, 5, 7의 배수만 거르면 나머지는 다 소수라고 생각했었는데, 2, 3, 5, 7이상의 소수의 배수의 소수가 아닌 값을 고려하지 못했다. (ex. 121) 그래서 그런 값들을 고려하기 위해서 제곱근을 활용했다. 

제곱근을 코드로 구현하는 방법을 몰라서 해당 부분도 찾아봤다. 

 

그런데 저 코드로는 2, 3, 5, 7 이상의 값중 소수인 값을 체크할 수가 없었다. 

 

소수는 1과 자기자신으로만 나눠지는 값이고, 만약 소수가 아니라면 1과 자기자신의 값 사이에 있는 값으로 나눠져야한다. 

 

예를들어서 특정 값이 있을때, 그 값이 소수라면, 약수는 1과 자기자신뿐이다. 만약 소수가 아니라면, 약수는 1과 자기자신 그리고 자기자신의 제곱근과 그 제곱근을 기준으로 작은 약수와 큰 약수가 생긴다. 

 

이 점을 활용해서, 특정 값이 소수임을 판별할때, 1부터 자기자신의 제곱근 사이에 있는 모든 숫자를 가지고 자기자신이 0으로 나눠떨어지는지 확인하면 굳이 큰 약수를 확인하지 않아도 작은 약수임을 확인하는 것 만으로도 특정 값이 소수인지 확인할 수 있게된다. 

 

 

+ Recent posts