-
프로그래머스 코딩테스트 연습 - k진수에서 소수 개수 구하기(2022 카카오 블라인드 채용 5번 문제) 본문
# 주소
https://school.programmers.co.kr/learn/courses/30/lessons/92335#qna
# 문제
양의 정수 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 함수를 완성해 주세요.
제한사항
- 1 ≤ n ≤ 1,000,000
- 3 ≤ k ≤ 10
입출력 예nkresult
437674 | 3 | 3 |
110011 | 10 | 2 |
입출력 예 설명
입출력 예 #1
문제 예시와 같습니다.
입출력 예 #2
110011을 10진수로 바꾸면 110011입니다. 여기서 찾을 수 있는 조건에 맞는 소수는 11, 11 2개입니다. 이와 같이, 중복되는 소수를 발견하더라도 모두 따로 세어야 합니다.
# 문제 해설 및 코드 리뷰
class Solution {
public long solution(int n, int k) {
int answer = 0;
String str = "";
int pow = 30;
while(n > 0){
//11을 3진수로 나타내면 102
//9를 2진수로 나타내면 1001
if (!(Math.pow(k, pow) > n) || !str.equals("")) {
int temp = 0;
for (int x = k - 1; x >= 0; x--) {
if (x * Math.pow(k, pow) <= n) {
temp = x;
break;
}
}
n -= temp * (int) Math.pow(k, pow);
str = str + temp;
}
pow--;
}
String temp = "";
for(int i = 0; i < str.length(); i++){
char now = str.charAt(i);
if(now != '0'){
temp += now;
}else{
int t = Integer.parseInt(temp);
temp = "0";
if(t == 1 ||t == 0) {
continue;
}
if(check(t))
answer++;
}
}
long t = Long.parseLong(temp);
if(t == 1 || t == 0)
return answer;
else{
if(check(t))
answer++;
return answer;
}
}
static boolean check(long x){
for(int i = 2; i <= Math.sqrt(x); i++){
if(x % i == 0)
return false;
}
return true;
}
}
문제 해설은 카카오에서 공식적으로 제공하고 있으니 참고 바랍니다.
https://school.programmers.co.kr/learn/courses/14743?itm_content=lesson92335
요즘 포스팅을 너무 안하지요 ㅠㅠ 웹 개발이랑 cs공부하느라 정신없이 하루를 보내고 있습니다.
주말에 좀 쉬고 싶은 마음은 들지만 알고 싶은 내용들이 산더미 같이 많네요...
지식의 고뇌 그래프라고 알고 계신가요?
앞으로 공부해야할 부분과 자기가 모르는 내용에 대해 사람의 자신감은 매우 떨어지게 됩니다.
학부생 시절에는 커리큘럼에 담긴 내용만 알아도 됐지만 그 깊이가 깊어질수록 내용은 더욱더 방대해지네요.
석사, 박사원생들이 자존감이 많이 낮은 이유도 여기에 있는 것 같습니다...
포스팅은 요즘 많이 늦지만 그래도 하루에 프로그래머스 LV2는 한 개씩 풀고 있는데 그것도 벌써 끝이 보이네요.
LV2다풀면 LV3를 하지 싶은데 예전에 LV3쉬운 것만 풀다가 문자열부분이 약해서 LV2로 넘어온 거거든요 ㅋㅋ...
벌써 끝이 보이기 시작해서 다행입니다. 문제를 먼저 봅시다.
<문제 요약>
n을 받아와서 규칙에 따라 각 수를 구한뒤 소수인지 판별한다.
그 규칙을 보면 굉장히 난잡한 것 같은데 사실 이것만 기억하심 됩니다.
"0"이 나오면 지금까지 받은 문자열을 정수로 바꿔서 소수인지 확인하고
"0"이 아니면 문자열을 담으시면 됩니다.
이게 다입니다. 코드로 봅시다.
int answer = 0;
String str = "";
int pow = 30;
while(n > 0){
//11을 3진수로 나타내면 102
//9를 2진수로 나타내면 1001
if (!(Math.pow(k, pow) > n) || !str.equals("")) {
int temp = 0;
for (int x = k - 1; x >= 0; x--) {
if (x * Math.pow(k, pow) <= n) {
temp = x;
break;
}
}
n -= temp * (int) Math.pow(k, pow);
str = str + temp;
}
pow--;
}
제일 먼저 우린 k진수로 나타낼 것입니다.
이를 위해 while문을 이용하여 n을 커팅할 것인데요.
최초에 pow를 30으로 잡은 이유는 n의 값이 100만까지이기 때문에 넉넉잡아서 30부터 해도 괜찮을 것 같아 그렇게 했습니다.
50으로 해봐도 정답 나오긴 하더라고요. 전 메모리낭비 안하려구 30으로 했습니다.
어쨌든 k를 pow제곱했을 때 해당 수가 n보다 작기만 하면 저희는 커팅을 할 것인데요.
가만 보면 2진수같은경우는 그냥 1과 0이기 때문에 괜찮지만 3진수부터는 3의 pow제곱과 곱해지는 수가 0,1,2 이렇게 존재할 수 있기 때문에 for문을 이용하여 x값을 찾는 것이 중요합니다.
그렇게 찾은 x는 temp가 되고 n에서 빼시면 됩니다.
while문이 끝나면 str은 소수로 변환되는데요.
String temp = "";
for(int i = 0; i < str.length(); i++){
char now = str.charAt(i);
if(now != '0'){
temp += now;
}else{
int t = Integer.parseInt(temp);
temp = "0";
if(t == 1 ||t == 0) {
continue;
}
if(check(t))
answer++;
}
}
이후 저희는 각 문자열의 인덱스에 대해 해당 문자가 0일 경우와 아닐 때를 구분하여 조건문을 진행해보도록 하겠습니다.
만약 0이 아닐 때에는 어떤 숫자가 들어있다는 것이 되므로 temp에 계속 더해줍니다.
그리고 0일 때에는 지금까지 받아온 temp를 t라는 정수로 변환한 뒤 t가 1이거나 0일때를 제외한 나머지 t에 대해 check함수를 실행합니다.
check함수는 소수 여부를 판단하는 함수로서 에라토스테네스의 체를 이용했습니다. 정말 간단한 것이니 알아두시면 좋아요.
static boolean check(long x){
for(int i = 2; i <= Math.sqrt(x); i++){
if(x % i == 0)
return false;
}
return true;
}
해당 함수는 요렇게 생겼습니다.
x의 제곱근까지만 탐색을 진행합니다.
여기에서 i로 나눠지는 수가 없다면 true를 return하겠습니다.
이때 return된 수가 소수면 answer를 증가시킵니다.
마지막으로 여기서 끝내시면 안되고 temp가 0이 안나와서 못끝낸 temp가 분명 있을 수 있잖아요?
그 경우를 대비하여
long t = Long.parseLong(temp);
if(t == 1 || t == 0)
return answer;
else{
if(check(t))
answer++;
return answer;
}
한 번 더 check함수를 진행하면 됩니다.
여기서 꼭 아셔야 하는게 하나 있는데, temp를 int타입으로 변환하시면 1번과 11번 케이스에서 시간 초과(런타임 에러)가 나기 때문에(이거 땜에 한 시간 고민한 저의 경험....) 꼭 제발 꼭 long타입으로 푸세요.
그럼 풀립니다...
'프로그래머스 문제 풀이' 카테고리의 다른 글
코딩테스트 연습 - 기지국 설치 (그리디) (0) | 2022.09.14 |
---|---|
프로그래머스 연습 - [1차] 셔틀버스 (2018 카카오 블라인드 채용), 자바, 우선순위 큐, 문자열) (0) | 2022.09.08 |
프로그래머스 코딩테스트 연습 - [3차] 압축 (2018 카카오 블라인드) (0) | 2022.08.27 |
프로그래머스 코딩테스트 연습 - 배달 (DFS, 플로이드-와샬, 다익스트라) (0) | 2022.08.18 |
프로그래머스 코딩테스트 연습 - [1차] 뉴스 클러스터링 (0) | 2022.08.08 |