👀 문제
https://programmers.co.kr/learn/courses/30/lessons/42839
👊 첫 번째 도전
1. 설계
- String형 numbers를 쪼개서 int형으로 배열에 저장한다.
- 만들 수 있는 숫자를 모두 생성한다=>조합 이용.
- 소수 체크해서 갯수를 센다=>에라토스테네스의 체 이용.
2. 구현
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import java.util.HashSet;
import java.util.Set;
/**
*
* @author HEESOO
*
*/
class Solution {
public int solution(String numbers) {
int answer = 0;
String[] strArr=numbers.split("");
int[] numArr=new int[strArr.length];
for(int i=0;i<numArr.length;i++){
numArr[i]=Integer.parseInt(strArr[i]);
}
Set<Integer> set=new HashSet<>();
//1부터 만들 수 있는 최대 길이까지 숫자 조합
for(int i=1;i<=numArr.length;i++){
perm(strArr, 0, i, set);
}
answer=set.size();
return answer;
}
public void perm(String[] arr, int depth, int k, Set set){//숫자 조합
if(depth==k){//원하는 k개의 숫자가 세팅됐으므로 더이상 순열생성X
print(arr, k, set);
return;
}
else{
for(int i=depth;i<arr.length;i++){
swap(arr, i, depth);
perm(arr, depth+1, k, set);
swap(arr, i, depth);
}
}
}
public void swap(String[] arr, int i, int j){
String temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
public void print(String[] arr, int k, Set set){//숫자 연결
StringBuilder s=new StringBuilder();
for(int i=0;i<k;i++){
//System.out.print(arr[i]);
s.append(arr[i]);//숫자연결하기
}
//System.out.println();
primeNumber(set, s);
}
public void primeNumber(Set set, StringBuilder s){//소수 체크
int num=Integer.parseInt(String.valueOf(s));
boolean prime=true;
if(num<=1){
return;
}
for(int i=2;i<=Math.sqrt(num);i++){
if(num%i==0){
prime=false;
break;
}
}
if(prime){
set.add(num);
}
}
}
public int solution(String numbers)
- String[] strArr: numbers를 하나씩 쪼개서 배열에 저장한다.
- int[] numArr: 쪼갠 strArr를 int형을 변환한다.
- Set
set: 생성한 숫자들은 중복될 수 있으므로 HashSet을 이용하여 중복을 제거한다.
public void perm(String[] arr, int depth, int k, Set set)
- int depth: 현재 내 숫자 길이를 뜻한다.
- int k: 만들 숫자 길이이다.
3. 코드 설명
public int solution(String numbers)
: numbers를 int형으로 변환하고, for문을 통해 1부터 종이 조각을 가지고 만들 수 있는 최대 길이만큼 숫자 조합 함수 perm()을 호출한다. for문이 끝나면 set에는 소수인 숫자들이 저장되어있으므로 set의 size를 리턴한다.public void perm(String[] arr, int depth, int k, Set set)
: if 조건인 depth==k의 의미는, 현재 내 길이가 k와 같아졌으므로 원하는 k개의 숫자가 세팅되었다는 뜻이므로 더 이상 순열을 생성하지 않고 print()함수를 호출해 숫자를 연결해준다.
else문은 아직 k만큼 길이 생성이 되지 않았을 경우이다. 이 경우에는 for문을 통해 현재 내 위치 depth부터 arr.length까지 돌면서 숫자 길이를 늘린다. 이때 숫자 조합을 위해 swap()을 호출하여 arr의 순서를 바꾼다(https://gorakgarak.tistory.com/522 참고). 배열이 변경되었다면 depth+1하여 다시 perm()함수를 호출한다(재귀). 이렇게 재귀를 계속 호출하다가 if문에 걸려서 return하면 그 다음 swap()으로 넘어간다. 다음 swap()을 진행할 수 있다는 것은 숫자 조합이 완성되었다는 뜻이다. 때문에 다시 swap()을 통해 배열을 다시 원상복구해준다. 다시 swap을 호출해주지 않는다면 이후 arr사용에 문제가 생긴다. 이후에 이상한 값이 나올 것이다.public void swap(String[] arr, int i, int j)
: 배열 arr의 i와 j번째 값을 바꾼다.public void print(String[] arr, int k, Set set)
: 숫자 조합이 완성되면 이 함수에 들어온다. 숫자들을 하나의 String으로 연결시켜주기 위함이다. 이를 위해 StringBuilder가 사용된다. StringBuilder의 append()메소드를 통해 String형을 연결(+)할 수 있다. 일반적으로 +=를 이용해 연결할 수도 있지만, 연결해야할 대상이 많은 경우에는 성능이 저하될 수 있다. 때문에 StringBuilder를 사용한다.
for문으로 숫자가 하나로 연결되면 primeNumber()을 호출해 소수인지 확인한다.public void primeNumber(Set set, StringBuilder s)
: 연결된 숫자 s를 int형으로 형변환하여 num에 저장한다. 숫자 1은 소수도, 합성수도 아니므로 HashSet에 저장하지 않는다. 2부터 num의 루트값까지 순회하며 나누어지는 값이 있는지 확인한다. 참고로 특정 숫자가 소수인지 판별할 때에는 처음부터 그 값까지 확인하지 않고 루트값까지만 확인해도 된다(에라토스테네스의 체). 나눠지는 값이 있다면 소수가 아니라는 의미이므로 for문을 종료한다. 나눠지는 값이 없다면 소수이므로 HashSet에 저장한다. 이때 만들어지는 숫자 num은 중복이 생길 수 있는데, HashSet에 저장함으로써 중복을 거른다.
4. 결과
🤟 성공 🤟
👏 해결 완료!
소수를 체크하는 것은 어렵지 않았는데 숫자 조합을 생각하는 것이 어려웠다. 그래서 다른 사람 코드를 많이 참고했다. 어려운 문제였다.
참고
- 프로그래머스 알고리즘 : 소수 찾기 (java) https://jar100.tistory.com/16
- 순열(PERMUTATION) 알고리즘 https://gorakgarak.tistory.com/522
- 자바 StringBuilder 사용법 및 사용하는 이유 https://hardlearner.tistory.com/288