본문 바로가기
Language/Java

[백준 | Java] 15829번 Hashing

by ㅇ달빛천사ㅇ 2025. 1. 21.
728x90
15829번 / Hashing

Hashing

🏷️ 관련 주제 : 자료형

 

💦 나의 시도

Try01. int형과 BufferedReaderread() 메서드를 이용한 시도

  1. 문자열 길이 L, 거듭제곱해주는 숫자 r, moduler Number M을 int형 변수로 선언
    • r = 31
    • M = 1234567891
  2. 0 ~ (L - 1) 범위를 반복문을 돌면서 알파벳을 한 글자씩 읽기
    • BufferedReaderread()메서드를 사용하여 알파벳을 정수로 읽은 값에 ('a' - 1) 값을 뺀 값을 int형 변수에 할당
      (이렇게 하면 알파벳 'a' 값을 1, 'b'는 2, ...로 바꿀 수 있음)
    • 0 ~ (i - 1) 범위를 반복문을 돌면서 a에 r을 곱함.
      • 만약 a가 M보다 크면 a를 M으로 나눈 나머지를 a에 할당
    • 반복문이 끝나면 H에 a를 더해줌
    • 반복문이 끝나면 H를 출력

💥 50점(Small 문제만 맞았습니다.)

문제에 두가지 유형의 테스트 케이스가 있는데
첫번째 Small 문제는 1 ≤ L ≤ 5 범위에서 문제를 해결하는 것이고
두번째 Large 문제는 1 ≤ L ≤ 50 범위에서 문제를 해결해야하는데
Large문제에서 틀림

  • 변수의 범위가 달라지는 것이므로 자료형의 문제일 것 같아서 int형을 long형으로 바꿔봄.

Try02. 결과값으로 반환하는 H 변수를 long형으로 변경

💥 50점(Small 문제만 맞았습니다.)

Try03. 반복문에서 $r^i$을 매번 새롭게 구하던 것을 int R을 반복문 밖에서 선언하여 시도

💥 50점(Small 문제만 맞았습니다.)

이전 코드
import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStreamReader;

  public class Main {
      public static void main(String[] args) throws IOException {
          BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
          int L = Integer.parseInt(br.readLine());
          int r = 31;
          int M = 1234567891;
          long H = 0L;

          for (int i = 0; i < L; i++) {
              int a = br.read() - 'a' + 1;

              for (int j = 0; j < i; j++) {
                  a *= r;

                  if (a > M) {
                      a %= M;
                  }
              }
              H += a;

          }

          System.out.println(H);
      }
  }
바꾼 코드
import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStreamReader;

  public class Main {
      public static void main(String[] args) throws IOException {
          BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
          int L = Integer.parseInt(br.readLine());
          int r = 31;
          int M = 1234567891;
          int R = 1;
          Long H = 0L;

          for (int i = 0; i < L; i++) {
              int a = br.read() - 'a' + 1;
              a = a * R % M;
              H = (H + a) % M;
              R = R * r % M;
          }

          System.out.println(H);
      }
  }

Try04. 거듭제곱과 관련된 모든 변수를 long으로 선언

R : r을 거듭제곱한 값($r^i$)
a : 입력한 문자열에서 읽어 온 알파벳을 정수로 변환한 값
H : 결과값으로 출력할 변수

 

   맞았습니다!!

  • 메모리 : 14220 KB
  • 시간 : 108 ms
  • 코드 길이 : 636 B



Large문제가 범위만 달라서 깊게 생각하지 않고 어림짐작으로 r을 거듭제곱하는 부분에서 자료형의 범위를 초과할 것 같아서 변수형만 바꿔서 문제를 맞혔는데
아무래도 변수 L의 범위에 따라 값들이 어떻게 바뀌는지 깊게 생각해 보는 것이 더 좋겠지?
라는 생각이 들어서 값의 범위를 생각해 보았다.

 

System.out.println("int형 최댓값:"+Integer.MAX_VALUE+", long형 최댓값:"+Long.MAX_VALUE);
long maxR = 1234567890L * 31;
System.out.println("maxR:"+maxR+", int형 최댓값 초과:" + (maxR > Integer.MAX_VALUE) + ", long형 최댓값 초과:"+(maxR > Long.MAX_VALUE));
long maxA = 26L * 1234567890;
System.out.println("maxA:"+maxA+", int형 최댓값 초과:" + (maxA > Integer.MAX_VALUE) + ", long형 최댓값 초과:"+(maxA > Long.MAX_VALUE));
long maxH = 1234567890L + 1234567890;
System.out.println("maxH:"+maxH+", int형 최댓값 초과:" + (maxH > Integer.MAX_VALUE) + ", long형 최댓값 초과:"+(maxH > Long.MAX_VALUE));

 

(출력 결과)

int형 최댓값:2147483647, long형 최댓값:9223372036854775807
maxR:38271604590, int형 최댓값 초과:true, long형 최댓값 초과:false
maxA:32098765140, int형 최댓값 초과:true, long형 최댓값 초과:false
maxH:2469135780, int형 최댓값 초과:true, long형 최댓값 초과:false

 

즉, RaH는 int형 범위를 초과하는 경우가 생길 수 있으므로 long형으로 선언해야 문제를 맞힐 수 있다!

R : r의 거듭제곱
a : 알파벳 소문자 a ~ z를 1 ~ 26으로 변환한 정수
H : 해쉬 함수 결과값

 

📑제출 기록 및 오답 원인

 

💯 해결 방법

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int L = Integer.parseInt(br.readLine());
        int r = 31;
        int M = 1234567891;
        long R = 1L;
        long H = 0L;

        for (int i = 0; i < L; i++) {
            long a = br.read() - 'a' + 1;
            a = (a * R) % M;
            H = (H + a) % M;
            R = (R * r) % M;
        }

        System.out.println(H);
    }
}

 

ℹ️ 자바 기본 자료형 크기 및 범위

자바 기본 자료형 크기 및 범위 구하는 코드
import java.text.DecimalFormat;

  public class Test {
      public static void main(String[] args) {
          DecimalFormat formatter = new DecimalFormat("###,###.###");
          System.out.println("\n[정수 자료형]\n");
          System.out.println("1. byte");
          System.out.println("- 크기: " + Byte.BYTES + "바이트");
          System.out.println("- 최솟값: " + formatter.format(Byte.MIN_VALUE));
          System.out.println("- 최댓값: " + formatter.format(Byte.MAX_VALUE));
          System.out.println("---------------------------");
          System.out.println("2. short");
          System.out.println("- 크기: " + Short.BYTES + "바이트");
          System.out.println("- 최솟값: " + formatter.format(Short.MIN_VALUE));
          System.out.println("- 최댓값: " + formatter.format(Short.MAX_VALUE));
          System.out.println("---------------------------");
          System.out.println("3. int");
          System.out.println("- 크기: " + Integer.BYTES + "바이트");
          System.out.println("- 최솟값: " + formatter.format(Integer.MIN_VALUE));
          System.out.println("- 최댓값: " + formatter.format(Integer.MAX_VALUE));
          System.out.println("---------------------------");
          System.out.println("4. long");
          System.out.println("- 크기: " + Long.BYTES + "바이트");
          System.out.println("- 최솟값: " + formatter.format(Long.MIN_VALUE));
          System.out.println("- 최댓값: " + formatter.format(Long.MAX_VALUE));
          System.out.println("---------------------------");
          System.out.println("\n[실수 자료형]\n");
          System.out.println("5. float");
          System.out.println("- 크기: " + Float.BYTES + "바이트");
          System.out.println("- 최솟값: " + Float.MIN_VALUE);
          System.out.println("- 최댓값: " + Float.MAX_VALUE);
          System.out.println("---------------------------");
          System.out.println("6. double");
          System.out.println("- 크기: " + Double.BYTES + "바이트");
          System.out.println("- 최솟값: " + Double.MIN_VALUE);
          System.out.println("- 최댓값: " + Double.MAX_VALUE);
          System.out.println("---------------------------");
          System.out.println("\n[문자 자료형]\n");
          System.out.println("7. char");
          System.out.println("- 크기: " + Character.BYTES + "바이트");
          System.out.println("- 최솟값: " + formatter.format((int) Character.MIN_VALUE));
          System.out.println("- 최댓값: " + formatter.format((int) Character.MAX_VALUE));
      }
  }

 

(출력 결과)

[정수 자료형]

1. byte
- 크기: 1바이트
- 최솟값: -128
- 최댓값: 127
---------------------------
2. short
- 크기: 2바이트
- 최솟값: -32,768
- 최댓값: 32,767
---------------------------
3. int
- 크기: 4바이트
- 최솟값: -2,147,483,648
- 최댓값: 2,147,483,647
---------------------------
4. long
- 크기: 8바이트
- 최솟값: -9,223,372,036,854,775,808
- 최댓값: 9,223,372,036,854,775,807
---------------------------

[실수 자료형]

5. float
- 크기: 4바이트
- 최솟값: 1.4E-45
- 최댓값: 3.4028235E38
---------------------------
6. double
- 크기: 8바이트
- 최솟값: 4.9E-324
- 최댓값: 1.7976931348623157E308
---------------------------

[문자 자료형]

7. char
- 크기: 2바이트
- 최솟값: 0
- 최댓값: 65,535

🏷️ 문제 풀면서 참고한 블로그

728x90


Top