문제
번호
내용
한자리 숫자가 적힌 종이 조각이 흩어져있습니다. 흩어진 종이 조각을 붙여 소수를 몇 개 만들 수 있는지 알아내려 합니다.
각 종이 조각에 적힌 숫자가 적힌 문자열 numbers가 주어졌을 때, 종이 조각으로 만들 수 있는 소수가 몇 개인지 return 하도록 solution 함수를 완성해주세요.
제한사항
- numbers는 길이 1 이상 7 이하인 문자열입니다.
- numbers는 0~9까지 숫자만으로 이루어져 있습니다.
- 013은 0, 1, 3 숫자가 적힌 종이 조각이 흩어져있다는 의미입니다.
입출력 예
numbers | return |
17 | 3 |
011 | 2 |
입출력 예 설명
예제 #1
[1, 7]으로는 소수 [7, 17, 71]를 만들 수 있습니다.
예제 #2
[0, 1, 1]으로는 소수 [11, 101]를 만들 수 있습니다.
11과 011은 같은 숫자로 취급합니다.
언어
JAVA
풀이
여러가지를 응용도 해야했고 생각도 필요한 문제였다.
숫자의 나열을 조합하여 총 몇개의 소수를 만들 수 있는지 알아내는 문제이다.
이를 위해서는
- 숫자의 나열을 조합하여 가능한 모든 수를 파악하고,
- 해당 숫자들 각각이 소수인지를 판단하여야한다.
2번은 간단히 해결할 수 있다.
소수란 1과 자기 자신 외의 어떠한 수로도 나눠떨어지지 않는 수이다. 때문에 어떤 수가 소수인지를 판단하기 위해서는 해당 수의 제곱근까지의 숫자를 나눴을 때 모두 나머지가 0이지 않으면 된다. 왜 제곱근까지인가에 대해서는 간단하게 그 이상의 숫자들은 그 이전의 수를 제곱해서 만들어지는 수라고 생각하면 될듯하고, 더 자세한 내용은 맨 아래의 참고를 확인바란다.
문제는 1번이다.
"과연 모든 경우, 즉 순열(permutation)을 구해야만 가능한가?"에 대해 많은 고민을 하였다. 정답은 "그렇다"였다. 모든 경우를 구하지 않고 소수만 구하는 방법은 따로 없기 때문이다. 그래도 이를 조금이라도 더 간단하게 구현하고 싶었다.
코드 설명
코드에서 조합의 결과를 담을 인터페이스를 Set으로 선택하였는데, 이는 중복되는 것을 피하기 위해서이다. Set은 중복되는 요소를 허락하지 않는다. Input으로 들어오는 모든 숫자들이 반드시 고유한 숫자는 아니다. 즉 중복되는 숫자들이 있다는 것이다. 이렇게 되면 조합된 결과가 고유하지 않고 중복될 수도 있다. 중복되는 조합까지 카운팅 해버린다면 결과에 영향을 주기때문에 Set을 선택하였다.
처음에 input으로 들어온 숫자의 문자열을 <pre>split("")</pre>을 통해서 문자 하나하나로 쪼갠다. 이 때 ()안에 ""로 하였기 때문에 모든 문자단위로 쪼갤 수 있는 것이다. 쪼갠 문자들을 List 인터페이스에 담게되는데 add와 remove를 쉽게 하기 위함이다.
이후 반복문을 통하여 permutation을 실행하게 된다. 반복문 안에서 permutation 과정을 진행하면서 add/remove을 수행하다보니 순서가 뒤죽박죽이고, 이렇게 되면 중복이나 누락되는 조합이 발생할 수 있다. 그렇기에 매번 오름차순으로 정렬한다.
<pre>permutation</pre> 메소드를 통해 조합을 실시하게 된다. 위의 1번을 해결하기 위해서 어떻게 하면 좋을까 생각하다보니, 아래와 같은 그림을 그리게 되었다. 아래 처럼 자기 자신에서 끝내는 경우 + 다음 요소를 추가하는 경우를 반복해나가다 보면 모든 경우가 나오게 되는 것이다.
이를 모든 원소에 대해서 실행시키기 위해서 다음과 같은 코드가 나왔다. 각 parameter 기능은 아래와 같다.
- <pre>set</pre> : 조합의 결과를 담는 Set
- <pre>all</pre> : 현재 턴에서의 남은 요소들
- <pre>current</pre> : 현재 진행된 요소의 조합
public static void permutation(Set<Integer> set, List<String> all, String current) {
// 다음 거 추가하지 않는 경우
set.add(Integer.parseInt(current));
if(all.size() == 0) return;
// 다음 거 추가 하는 경우
for(int i = 0 ; i < all.size() ; i++) {
String next = all.remove(0);
permutation(set, all, current + next);
all.add(next);
}
}
이후에는 조합된 모든 요소들에 대해 <pre>isPrimeNumber</pre> 메소드를 통해 소수인지 판단하고 답을 도출한다.
코드
import java.util.*;
class Solution {
public int solution(String numbers) {
int answer = 0;
Set<Integer> set = new HashSet<>();
List<String> allNums = new ArrayList<>(
Arrays.asList(numbers.split(""))
);
for(int i = 0 ; i < allNums.size() ; i++) {
Collections.sort(allNums);
String current = allNums.remove(i);
permutation(set, allNums, current);
allNums.add(current);
}
for(Integer i : set) {
if(isPrimeNumber(i)) answer++;
}
return answer;
}
public static void permutation(Set<Integer> set, List<String> all, String current) {
// 다음 거 추가하지 않는 경우
set.add(Integer.parseInt(current));
if(all.size() == 0) return;
// 다음 거 추가 하는 경우
for(int i = 0 ; i < all.size() ; i++) {
String next = all.remove(0);
permutation(set, all, current + next);
all.add(next);
}
}
public static boolean isPrimeNumber(int number) {
int sqrt = (int) Math.sqrt(number);
if(number <= 1) return false;
for(int i = 2 ; i <= sqrt ; i++) {
if(number % i == 0) return false;
}
return true;
}
}
참고
소수 판별법
https://ko.wikipedia.org/wiki/%EC%86%8C%EC%88%98%ED%8C%90%EB%B3%84%EB%B2%95
'Etc > 문제 풀이' 카테고리의 다른 글
[프로그래머스 42862번] 체육복 (0) | 2021.02.21 |
---|---|
[프로그래머스 42842번] 카펫 (0) | 2021.02.21 |
[프로그래머스 42840번] 모의고사 (0) | 2021.02.19 |
[프로그래머스 42747번] H-Index (0) | 2021.02.16 |
[프로그래머스 42746번] 가장 큰 수 (0) | 2021.02.15 |
댓글