라떼는말이야

[프로그래머스 lv2] 소수 찾기 (파이썬) 본문

알고리즘/코딩 테스트

[프로그래머스 lv2] 소수 찾기 (파이썬)

MangBaam 2021. 8. 3. 12:35
반응형

문제 설명

한자리 숫자가 적힌 종이 조각이 흩어져있습니다. 흩어진 종이 조각을 붙여 소수를 몇 개 만들 수 있는지 알아내려 합니다.

각 종이 조각에 적힌 숫자가 적힌 문자열 numbers가 주어졌을 때, 종이 조각으로 만들 수 있는 소수가 몇 개인지 return 하도록 solution 함수를 완성해주세요.

제한사항

  • numbers는 길이 1 이상 7 이하인 문자열입니다.
  • numbers는 0~9까지 숫자만으로 이루어져 있습니다.
  • "013"은 0, 1, 3 숫자가 적힌 종이 조각이 흩어져있다는 의미입니다.

입출력 예

입출력 예

입출력 예 설명

예제 #1
[1, 7]으로는 소수 [7, 17, 71]를 만들 수 있습니다.

예제 #2
[0, 1, 1]으로는 소수 [11, 101]를 만들 수 있습니다.

  • 11과 011은 같은 숫자로 취급합니다.

 


나의 풀이

이 문제는 크게 두 부분을 구현 해야 한다.

  1. 숫자의 조합
  2. 소수 판별

 

숫자의 조합(순열)

숫자를 조합하는 경우는 파이썬 라이브러리 itertools의 permutations를 사용했다.

permutations는 수학적인 용어로는 순열인데

예를 들어 [1, 3, 5] 라는 리스트가 있을 때 순열로 조합하면 1, 3, 5, 13, 31, 15, 51, 35, 53, 135, 153, 315, 351, 513, 531 과 같이 순서를 가지는 조합을 의미한다.

 

이 부분의 코드는 다음과 같다.

from itertools import permutations

def makeCase(numbers):
    result = []
    for i in range(1, len(numbers)+1):
        result.extend(list(map(int, map(''.join, permutations(numbers, i)))))
    result = list(filter(lambda x: x > 1, list(set(result))))
    
    return result

permutations를 사용하기 위해 상단에 import를 시켜주고

permutations의 사용법은 permutations(대상, 갯수)로 사용하면 된다.

대상에는 리스트, 문자열, 집합 등 iterable한 자료형이 올 수 있다.

 

permutations의 결과는 튜플 형식으로 반환된다.

예를 들어 ('1', '3') 과 같은 형식으로 반환된는 것인데 우리는 숫자 13으로 사용하기 위해서

map 함수로 각각의 경우에 ''.join를 사용하여 "13"을 만들어준다.

 

''.join은 리스트의 각 요소를 ' ' 안에 들어있는 문자를 구분자로 묶는 역할을 하는데 ' ' 안이 공백이므로 하나의 문자로 연결해준다.

 

그리고 또 그렇게 만들어진 문자열 요소들을 정수로 바꿔주기 위하여 map을 한번 더 사용하여 int형으로 만들어주었다.

 

이것을 list( ) 로 감싸서 리스트로 만들어준 후 result 리스트에 붙여넣었다.

 

이 문제에서는 소수를 판별하는 문제이므로 2 이하의 숫자는 소수가 아니기 때문에 리스트 내에서 1보다 큰 숫자만 filter를 사용하여 걸러낸다. 그리고 그 결과를 반환했다.

 

 

 

 

소수 판별

소수를 판별하는 방법은 아주 다양하다.

가장 보편적이고 코딩테스트 등에서 자주 쓰이는 방법이 '아리스토텔레스의 체' 이다.

2021.06.17 - [프로그래머스 lv1] 소수 만들기 (파이썬)

 

[프로그래머스 lv1] 소수 만들기 (파이썬)

Summer/Winter Coding(~2018) 의 소수 만들기 문제이다. 문제 주어진 숫자 중 3개의 수를 더했을 때 소수가 되는 경우의 개수를 구하려고 합니다. 숫자들이 들어있는 배열 nums가 매개변수로 주어질 때, num

latte-is-horse.tistory.com

이 문제에서 "아리스토텔레스의 체"를 사용해 풀이했다.

자세한 내용은 위 게시글을 참고하거나 구글링을 해보면 자세히 나와있다.

 

이번 풀이에서는 가장 무식하고 단순한 방법을 사용했다.

 

일일히 나눠보는 방법이다.

범위 내의 모든 소수를 구하는 것이 아닌 해당 숫자가 소수인지 판별하는 것이기 때문에 이 방법을 선택했다.

 

def isPrime(n):
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0: return False
    return True

하지만 범위를 보면 n까지가 아닌 √n 까지 나누었다.

어떤 수의 약수는 항상 짝을 이룬다.

예를 들어 100의 약수는 1, 2, 4, 5, 10, 20, 25, 50, 100 인데

(1, 100), (2, 50), (4, 25), (5, 20), (10, 10) 과 같이 짝을 이룰 수 있다.

즉 100의 제곱근보다 작은 수까지만 나눠보면 소수인지 아닌지 판별할 수 있다.

1, 2, 4, 5, 10까지만 나눠보면 짝을 이루는 100, 50, 25, 20, 10 까지 모두 구할 수 있기 때문이다.

 

2부터 √n까지 차례로 나누어 가면서 한 번이라도 나누어 떨어진다면 소수가 아니다.

모두 나눠봤지만 나누어 떨어지지 않았다면 소수이다.

 

전체 코드

from itertools import permutations

def solution(numbers):
    answer = 0
    case = makeCase(numbers)
    for n in case:
        if isPrime(n): answer += 1

    return answer

def makeCase(numbers):
    result = []
    for i in range(1, len(numbers)+1):
        result.extend(list(map(int, map(''.join, permutations(numbers, i)))))
    result = list(filter(lambda x: x > 1, list(set(result))))
    
    return result

def isPrime(n):
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0: return False
    return True

위에서 구한 숫자들의 순열을 for문으로 순회하며 소수인지 판별하고 소수라면 answer에 1씩 더하여 풀이할 수 있다.

테스트 결과

 

반응형
Comments