교재 227p 백준 1016번 질문드립니다.
저자 선생님 안녕하세요
좋은 교재와 강의 잘 보고 있습니다.
강의가 없는 1016번 문제에 대해 오래동안 고민을 해도 해결이 안되어 질문을 드리고 싶은데, 받아주시면 정말 감사하겠습니다.
시간초과가 난 전체 코드입니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
InputStreamReader is = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(is);
StringTokenizer st = new StringTokenizer(br.readLine()," ");
long min = Long.parseLong(st.nextToken());
long max = Long.parseLong(st.nextToken());
// 최댓값과 최솟값의 차이만큼 배열 선언하기
boolean[] Check = new boolean[(int)(max-min+1)];
// 2의 제곱수인 4부터 Max보다 작거나 같은 값까지 반복하기
/* 저자님 코드(정답)
for(long i=2; i*i<=max; i++){
long pow = i*i; //제곱수
long start_index = min/pow;//최솟값/제곱수
if(min%pow!=0){
start_index++;
}
for(long j = start_index; pow*j <=max; j++){//제곱수를 true로 변경하기
Check[(int)((j*pow)-min)] = true;
}
}
*/
//제 코드(시간초과)
for(long i=2; i*i<=max; i++){
long pow = i*i;//제곱수
for(long j=1; (j*pow)<=max; j++){
long t= j*pow;//제곱수의 배수
if((min<=t) && (t<=max)){//제곱수의 배수가 min과 max 범위 안이면
Check[(int)(t-min)] = true; //제곱수의 배수 표시
}
}
}
//
long count = 0;
for(long i = 0; i<=max-min; i++){
if(!Check[(int)i]){
count++;
}
}
System.out.println(count);
}
}
위의 전체 코드에서 저자 선생님 코드를 주석 /* */ 로 감싸고
제 코드를 바로 아래에 작성했는데, 보시기 힘들 것 같아서 보라색과 초록색으로 구분한 스크린샷을 같이 올려드립니다.

제 코드의 경우, 백준 문제에서 보여준 테스트케이스는 통과하는데
시간초과가 발생했습니다.
그래서 많은 테스트케이스를 시도해봤는데
입력
1000000000000 1000001000000
이 테스트케이스에서
저자 선생님 코드는 제대로 작동을 하고, 제 코드는 시간초과가 발생하는 것 같았습니다.
하루종일 고민해도 그 이유가 도저히 이해가 안돼서, 질문을 드리고 싶습니다.
가르쳐주시면 정말 감사하겠습니다.
읽어주셔서 감사합니다.
+오후 8시에 질문을 추가드립니다.
시간초과가 안나는 핵심 로직이
long start_index = min/pow;//최솟값/제곱수
if(min%pow!=0){
start_index++;
}
같은데 이 부분이 이해가 너무 어렵습니다..
이 코드를 더 자세하게 가르쳐주시면 감사하겠습니다.
답변 1
1
안녕하세요. 반갑습니다 ~.
제 생각에는 이 부분에서 먼저 짚고 넘어가야 하는 부분은 min max의 범위입니다.
1 ≤ min ≤ 1,000,000,000,000
min ≤ max ≤ min + 1,000,000
보시면 min의 범위는 엄~~~~청 넓은데 min과 max사이의 범위는 그렇게 크지 않습니다. (100만정도?)
아마도 딱 이부분에서 차이가 나지 않을까 싶습니다.
코드로 돌아가서 아래의 부분은 예를들어 min이 10000이라고 가정을 해보면 (i=2, pow=4)
long start_index = min/pow;//최솟값/제곱수
if(min%pow!=0){ start_index++; }
아래 코드에 의해서 start_index = 10000/4 = 2500이 됩니다.
(나머지가 딱 나누어 떨어지기 때문에 +1 안함)
그러면 아래쪽 for문은 2500부터 시작을 하게 됩니다. 왜냐면 2499 * 4 를 하면 min 보다 작기 때문에 범위를 벗어나기 때문입니다. min이 1,000,000,000,000면 어마어마하게 skip이 될것 같습니다.
Like me black님의 코드는 이 부분을 한번의 계산으로 skip하지 않고 1부터 for문을 돌리고 안에서 범위에 대한 체크를 하고 있습니다. 이렇게 되면 문제 조건에 따라 max는 1,000,001,000,000까지의 값을 가질 수 있고(이 경우는 min이 1,000,000,000,000일 경우입니다.)
for( j = 1 ; j*pow<=max; j++) 해당 반복문은 max가 1,000,001,000,000이고 pow가 4인 상황에서는
어마어마한 반복이 일어나 시간초과가 일어나게 됩니다.
같은 조건에서 계산식을 사용하면
start_index = 1,000,000,000,000 / 4 = 250,000,000,000이 되고 for문이
for( j = 250,000,000,000 ; j*pow<=max; j++) 으로 구성이 되어 시간 초과가 발생하지 않게 됩니다.
질문해주신 핵심로직은 제곱수를 제일 앞에서부터 하나하나 보는 것이 아닌
min보다 큰 범위부터 시작하기 위한 계산 로직이라고 이해하여 주시면 좋을 것 같습니다.
도움이 되셨으면 좋겠습니다. 좋은하루 되세요 :)
백준 1940 주몽의 명령 시간복잡도
0
62
0
다음영상이 문제 풀이 영상이라고 하셨는데 문제풀이 영상이 누락되어있는 것 같습니다
0
129
1
코딩테스트 디버깅
0
352
1
탐색 순서 질문
0
149
1
[P11726 2*N 타일채우기] top down 방식을 사용하니 런타임 에러가 발생합니다.
0
106
1
2018 연속된 자연수의 합 구하기 백준 사이트에서 메모리 초과 오류가 발생합니다.
0
204
1
1강 시간복잡도 중간에 중첩for문 직전에 상수는 상관없어요 하신 부분이 이해가 안됩니다
0
162
1
왜 int, long은 안되는지 궁금합니다.
0
225
1
DNA 비밀번호 (백준 12891) 통과가 안됩니다.
0
528
2
LCA 빠르게 구하기 Java 코드 시간초과
0
245
1
스택문제 백준 1874
1
460
1
백준11659 구간합 런타임 에러
0
308
1
백준 2178 미로탐색 질문 입니다.
0
449
1
구간합구하기1 (백준11659)
0
424
1
혹시 다른 ide에서 잘 돌아가는 프로그램이
0
352
1
내림차순으로 정렬하기 강의에서..
0
273
1
백준 11720 숫자의 합 질문 있습니다
0
436
1
(숫자의 합)1<=N <=100 사이의 값
0
386
1
소수구하기-백준 1929 질문
0
351
1
12891_DNA비밀번호
0
635
3
숫자의 합 구하기
0
393
1
안녕하세요 질문있습니다.
0
338
0
union 코드에 질문 있습니다.
0
407
2
[그리디 실전 문제] 최솟값을 만드는 괄호 배치 찾기 (백준 1541) - 반례를 못찾겠습니다 ㅠㅠ
1
312
1





