인프런 커뮤니티 질문&답변

Like me black님의 프로필 이미지
Like me black

작성한 질문수

Do it! 알고리즘 코딩테스트 with JAVA

교재 227p 백준 1016번 질문드립니다.

해결된 질문

작성

·

321

·

수정됨

1

저자 선생님 안녕하세요

좋은 교재와 강의 잘 보고 있습니다.

강의가 없는 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보다 큰 범위부터 시작하기 위한 계산 로직이라고 이해하여 주시면 좋을 것 같습니다.

 

도움이 되셨으면 좋겠습니다. 좋은하루 되세요 :)

 

 

 

Like me black님의 프로필 이미지
Like me black
질문자

선생님 가르쳐주셔서 감사합니다
적어주신 말씀을 꼼꼼히 읽어봤는데, 덕분에 하루 종일 고민한 문제가 드디어 이해가 되는 것 같습니다.

Like me black님의 프로필 이미지
Like me black

작성한 질문수

질문하기