silver 4. 보물(1026)

|

silver 4. 보물 (1026)

출처 : https://www.acmicpc.net/problem/1026

문제

길이가 N인 정수 배열 A와 B가 있을 때, 함수 S를 아래와 같이 정의할 때 S의 최솟값을 출력하는 프로그램 작성

[S = A[0] X B[0] + … + A[N-1] X B[N-1]]

  • S의 값을 가장 작게 만들기 위해 A의 수를 재배열. 단, B에 있는 수는 재배열하면 안됨

입력: 첫째 줄에 N이 주어지고, 둘째 줄에는 A에 있는 N개의 수가 순서대로 주어지고, 셋째 줄에는 B에 있는 수가 순서대로 주어짐

  • N은 50보다 작거나 같은 자연수이고, A와 B의 각 원소는 100보다 작거나 같은 음이 아닌 정수

출력: S의 최솟값 출력

풀이

  • 아이디어: A, B를 오름차순으로 정렬한 후 A의 가장 작은 수는 B의 가장 큰 수와 곱해주는 방식으로 해결
import java.util.*;

public class Main {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        
        int N = sc.nextInt();	// 배열 크기 저장
        int[] A = new int[N];
        int[] B = new int[N];
        int result = 0;			// S의 최솟값 저장
        String space = sc.nextLine();	// N의 값을 입력받고 문자를 입력받기 전 기존의 enter 값을 없애주는 변수

        StringTokenizer st = new StringTokenizer(sc.nextLine());  // A의 값을 받아옴
        for(int i=0; i < N; i++){
          A[i] = Integer.parseInt(st.nextToken());  // 받아온 값을 int형으로 변환 후 A에 값을 저장
        }

        StringTokenizer st2 = new StringTokenizer(sc.nextLine());  // B의 값을 받아옴
        for(int i=0; i < N; i++){
          B[i] = Integer.parseInt(st2.nextToken());	// 받아온 값을 int형으로 변환 후 B에 값을 저장
        }

        Arrays.sort(A);		// A를 오름차순으로 정렬
        Arrays.sort(B);		// B를 오름차순으로 정렬
        
        for (int i = 0; i < N; i++){
          result += A[i] * B[N-1-i];	// S의 최솟값을 구함
        }

        System.out.println(result);
    }
}
  • 백준에 제출했을 때 코드는 통과했지만, 문제에서 B에 있는 수는 재배열하면 안 된다는 조건을 만족시키지 못했다.
  • B에 있는 수를 재배열하지 않으면서 S의 최솟값을 찾을 수 있는 방법을 다시 생각해봐야겠다.

배운점

  • nextInt() 메서드 다음 nextLine() 메서드를 실행하면, nextLine() 메서드가 그냥 넘어가버리는 오류가 발생

    • 이유: nextInt() 메서드를 실행할 때 숫자를 입력하고 엔터를 누르면 숫자는 리턴시키지만 엔터의 값은 그대로 남아있음. nextLine() 메서드는 enter 값을 기준으로 메서드를 종료시키기 때문에 nextLine() 메서드가 실행될 때 남아있는 enter 값을 그대로 읽어 바로 종료됨
  • 해결 방법: 정수를 입력하고 그 다음 문자를 입력하고자 할 때는 next() 메서드를 사용하거나, 문자를 입력받기 전 nextLine() 메서드를 한번 더 써줘서 기존은 enter 값을 없애주어야 함

추가

  • 2022-02-03 추가

    • 처음 풀었을 때는 B에 있는 수를 재배열하지 말라는 조건을 충족시키지 못했다. 조건을 충족시켜 푼 풀이를 추가한다.
    • 아이디어
      • B에서 최댓값을 찾아주는 max 메서드를 생성함
      • A 메서드는 Arrays.sort()를 이용해 오름차순으로 정렬해줌
      • for문을 돌면서 B의 최댓값을 찾아주는 함수를 호출해 B의 최댓값과 A의 최솟값을 곱한 후 result 값에 더해줌
    import java.util.*;
      
    public class Main{
      public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
      
        int N = sc.nextInt();
        int[] A = new int[N];
        int[] B = new int[N];
        int result = 0;
        String space = sc.nextLine();
      
        StringTokenizer st1 = new StringTokenizer(sc.nextLine());
        for(int i=0; i < N; i++){
          A[i] = Integer.parseInt(st1.nextToken());
        }
      
        StringTokenizer st2 = new StringTokenizer(sc.nextLine());
        for (int i=0; i < N; i++){
          B[i] = Integer.parseInt(st2.nextToken());
        }
      
    	// A를 오름차순으로 정렬
        Arrays.sort(A);
      	
        // B와 같은 값을 가지는 BCopy 생성
        int[] BCopy = Arrays.copyOf(B, N);
      
        for(int i=0; i < N; i++) {
          int B_max = max(BCopy);	// B에서의 최댓값을 찾아줌
          result += A[i] * B_max;	// A의 최솟값과 B의 최댓값을 곱한 후 result에 더해줌
        }
      
        System.out.println(result);
      }
        
      // B에서의 최댓값을 찾아주는 함수
      public static int max(int[] arr){
        int index = -1;	// 최댓값의 인덱스 값을 저장
        int max = -1;	// 최댓값 저장
      
        // for문을 통해 최댓값을 찾아줌
        for(int i=0; i < arr.length; i++){
          if (max < arr[i]){
            max = arr[i];
            index = i;
          }
        }
          
        // 최댓값 다음으로 큰 값을 찾기 위해 최댓값을 가진 인덱스에 해당하는 값을 0으로 변경
        arr[index] = 0;
      
        // 최댓값 return
        return max;
      }
    }
    
  • 2022-02-04 추가

    • 스터디 진행하며 코드 리뷰를 하던 중, A의 최솟값과 B의 최댓값을 곱해나가는 과정이 아니라 A의 최댓값과 B의 최솟값을 곱해나가는 과정으로 계산을 하면 통과할까? 라는 질문이 나와 코드를 약간 수정해 테스트해봄
    • 위의 로직으로도 테스트 통과함
    import java.util.*;
      
    public class Main{
      public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
      
        int N = sc.nextInt();
        int[] A = new int[N];
        int[] B = new int[N];
        int resultMin = 0;
        String space = sc.nextLine();
      
        StringTokenizer st1 = new StringTokenizer(sc.nextLine());
        for(int i=0; i < N; i++){
          A[i] = Integer.parseInt(st1.nextToken());
        }
      
        StringTokenizer st2 = new StringTokenizer(sc.nextLine());
        for (int i=0; i < N; i++){
          B[i] = Integer.parseInt(st2.nextToken());
        }
      
        Arrays.sort(A);
      
        int[] BCopy = Arrays.copyOf(B, N);
      
        for(int i=0; i < N; i++) {
          int B_min = min(BCopy);			// B의 최솟값을 찾아주는 함수 호출
          resultMin += A[N-1-i] * B_min;	// A의 최댓값과 B의 최솟값을 곱해줌
        }
      
        System.out.println(resultMin);
      }
      
      // B의 최댓값을 구해주는 함수 대신 B의 최솟값을 구해주는 함수로 수정
      public static int min(int[] arr){
        int index = 0;
        int min = 101;
      
        for(int i=0; i < arr.length; i++){
          if (min > arr[i]){
            min = arr[i];
            index = i;
          }
        }
      
        arr[index] = 101;
      
        return min;
      }
    }
    

2022-01-28 TIL (자바, 알고리즘, 현대 IT&E 채용확정형 교육)

|

1. 자바의 정석

지네릭스, 열거형, 애너테이션 부분을 공부했다.

  • 지네릭스(Generics)
    • 와일드 카드
    • 지네릭 메서드
    • 지네릭 타입 형변환
  • 열거형(enums)
    • 열거형에 멤버 추가하기
    • 열거형에 추상 메서드 추가하기
  • 애너테이션(annotation)
    • 표준 애너테이션
    • 메타 애너테이션
    • 애너테이션 타입 정의하기 (애너테이션 요소의 규칙)

2. 알고리즘

silver 4. 보물(1026) 문제를 풀었다.

  • 아이디어는 빨리 떠올랐지만, 문제 조건 하나를 만족시키지 못했고, 구현에서도 조금 오래 걸렸다.
  • 구현에서 오래 걸린 이유는 Scanner을 통해 값을 입력받을 때 nextInt()를 사용하고 바로 nextLine()를 통해 값을 입력받으려 했지만, nextLine()을 통해 값을 입력받으려할 때 프로그램이 종료되었다. 이 부분을 해결하는데 조금 오래 걸렸다. => 이 부분은 문제 해설 링크 참조

3

현대 IT&E 채용 확정형 교육 지원서를 마무리하고 제출했다. 그냥 가볍게 넣어본 서류지만 그래도 합격했으면 좋겠다,,

Chapter 11. 컬렉션 프레임웍_2

|

1. HashSet

  • HashSet의 메서드
  • Set 인터페이스를 구현한 가장 대표적인 컬렉션
  • HashSet은 중복된 요소를 저장하지 않음
  • HashSet에 이미 저장되어 있는 요소와 중복된 요소를 추가하고자 한다면 add 메서드나 addAll 메서드는 false를 반환
    • 이 특징을 이용하면, 컬렉션 내의 중복 요소들을 쉽게 제거 가능
  • HashSet은 저장순서를 유지하지 않으므로 저장순서를 유지하고자 한다면 LinkedHashSet을 사용해야 함

2. TreeSet

  • TreeSet의 생성자와 메서드
  • 이진 검색 트리(binary search tree)라는 자료구조의 형태로 데이터를 저장하는 컬렉션 클래스
    • 이진 검색트리는 정렬, 검색, 범위검색(range search)에 높은 성능을 보이는 자료구조
    • TreeSet은 이진 검색 트리의 성능을 향상시킨 Red-Black tree로 구현됨
  • Set 인터페이스를 구현했으므로 중복된 데이터의 저장을 허용하지 않으며 정렬된 위치에 저장하므로 저장순서를 유지하지도 않음

이진 트리(binary tree)

  • 여러 개의 노드(node)가 서로 연결된 구조
  • 각 노드에 최대 2개의 노드를 연결할 수 있으며 root라고 불리는 하나의 노드에서부터 시작해 계속 확장해 나감
  • 위 아래로 연결된 두 노드를 ‘부모-자식관계’에 있다고 함. 하나의 부모 노드는 최대 두 개의 자식 노드와 연결될 수 있음
class TreeNode {
    TreeNode left;	// 왼쪽 자식노드
    Object element;	// 객체를 저장하기 위한 참조변수
    TreeNode right;	// 오른쪽 자식노드
}
  • 데이터를 저장하기 위한 Object 타입의 참조변수 하나와 두 개의 노드를 참조하기 위한 두 개의 참조변수를 선언

이진 검색 트리(binary search tree)

  • 부모노드의 왼쪽에는 부모노드의 값보다 작은 값의 자식노드를 오른쪽에는 큰 값의 자식노드를 저장하는 이진 트리
  • 첫 번째로 저장되는 값은 루트가 되고, 두 번째 값은 트리의 루트부터 시작해 값의 크기를 비교하면서 트리를 따라 내려감
    • 작은 값은 왼쪽에 큰 값은 오른쪽에 저장
    • 왼쪽 마지막 레벨이 제일 박은 값이 되고 오른쪽 마지막 레벨의 값이 제일 큰 값이 됨
  • TreeSet에 저장되는 객체가 Comparable을 구현하던가 아니면, TreeSet에게 Comparator를 제공해서 두 객체를 비교할 방법을 알려줘야 함. 그렇지 않으면, TreeSet에 객체를 저장할 때 예외 발생

  • 왼쪽 마지막 값에서부터 오른쪽 값까지 값을 왼쪽 노드 -> 부모 노드 -> 오른쪽 노드 순으로 읽오면 오참차순으로 정렬된 순서를 얻을 수 있음

  • TreeSet은 정렬된 상태를 유지하기 때문에 단일 값 검색과 범위검색이 매우 빠름
  • 트리는 데이터를 순차적으로 저장하는 것이 아니라 저장위치를 찾아서 저장해야하고, 삭제하는 경우 트리의 일부를 재구성해야하므로 링크드 리스트보다 데이터의 추사/삭제 시간은 더 걸림
    • 배열이나 링크드 리스트에 비해 검색과 정렬 기능이 더 뛰어남

3. HashMap과 Hashtable

  • HashMap의 생성자와 메서드
  • Hashtable보다는 새로운 버전인 HashMap을 사용하는 것이 좋음
  • HashMap은 Map을 구현했으므로, 키(key)와 값(value)을 사용하기 때문에 많은 양의 데이터를 검색하는데 있어 성능이 뛰어남
Entry[] table;
class Entry{
    Object key;
    Object value;
}
  • HashMap은 Entry라는 내부 클래스를 정의하고, 다시 Entry 타입의 배열을 선언

    • 키와 값은 서로 관련된 값이기 때문에 각각의 배열로 선언하기 보다는 하나의 클래스로 정의해 하나의 배열로 다루는 것이 데이터의 무결성(integrity) 측면에서 바람직하기 때문
  • HashMap은 키와 값을 각각 Object 타입으로 저장

    키(key) 컬렉션 내의 키 중에서 유일해야 함

    값(value) 키와 달리 데이터의 중복을 허용

  • HashMap은 키나 값으로 null를 허용

해싱과 해시함수

  • 해싱: 해시함수(hash function)를 이용해서 데이터를 해시테이블(hash table)에 저장하고 검색하는 기법
    • 해시함수는 데이터가 저장되어 있는 곳을 알려 주기 때문에 다량의 데이터 중에서도 원하는 데이터를 빠르게 찾을 수 있음
  • 해싱을 구현한 컬렉션 클래스로는 HashSet, HashMap, HashTable 등이 있음
    • HashTable은 컬렉션 프레임웍이 도입되면서 HashMap으로 대체되었으나 호환성 문제로 남겨둠
  • 해싱에 사용하는 자료구조는 배열과 링크드 리스트의 조합으로 되어 있음
    • 저장할 데이터의 키를 해시함수에 넣으면 배열의 한 요소를 얻게 되고, 다시 그 곳에 연결되어 있는 링크드 리스트에 저장하게 됨

HashMap에 저장된 데이터를 찾는 과정

  1. 검색하고자 하는 값의 키로 해시함수를 호출함
  2. 해시함수의 계산결과(해시코드)로 해당 값이 저장되어 있는 링크드 리스트를 찾음
  3. 링크드 리스트에서 검색한 키와 일치하는 데이터를 찾음
  • 하나의 서랍에 많은 데이터가 저장되어 있는 형태보다 많은 서랍에 하나의 데이터만 저장되어 있는 형태가 더 빠른 검색결과를 얻을 수 있음

    • 하나의 링크드 리스트(서랍)에 최소한의 데이터만 저장하려면, 저장될 데이터의 크기를 고려해 HashMap의 크기를 적절하게 지정해주어야 함
    • 해시함수가 서로 다른 키에 대해 중복된 해시코드의 반환을 최소화해야 함
  • 해싱을 구현한 컬렉션 클래스에서는 Object 클래스에 정의된 hashCode()를 해시함수로 사용함

    • Object 클래스에 정의된 hashCode()는 객체의 주소를 이용하는 알고리즘으로 해시코드를 만들어 냄
    • String 클래스의 경우, Object로부터 상속받은 hashCod()를 오버라이딩해서 문자열의 내용으로 해시코드를 만들어 냄. 따라서 서로 다른 String인스턴스일지라도 같은 내용의 문자열을 가졌다면 hashCode()를 호출하면 같은 해시코드를 얻음
  • HashSet은 서로 다른 두 객체에 대해 equals()로 비교한 결과가 true인 동시에 hashCode()의 반환값이 같아야 같은 객체로 인식
  • HashMap도 같은 방법을 사용해 객체를 구별하며, 이미 존재하는 키에 대한 값을 저장하면 기존의 값을 새로운 값으로 덮어씀

  • 새로운 클래스를 정의할 때 equals()를 재정의 오버라이딩해야 한다면 hashCod()도 같이 재정의해서 equals()의 결과가 true인 두 객체의 해시코드 hashCode()의 결과 값이 항상 같도록 해주어야 함
    • 그렇지 않으면 HashMap과 같이 해싱을 구현한 컬렉션 클래스에서는 equals()의 호출결과가 true이지만 해시코드가 다른 두 객체를 다른 것으로 인식하고 따로 저장할 것
    • equals()로 비교한 결과가 false이고 해시코드가 같은 경우는 같은 링크드 리스트에 저장된 서로 다른 두 데이터가 됨

4. TreeMap

  • TreeMap의 생성자와 메서드
  • 이진검색트리의 형태로 키와 값의 쌍으로 이주어진 데이터를 저장
  • 검색과 정렬에 적합한 컬렉션 클래스
  • HashMap과 TreeMap 중 검색에 관한한 대부분의 경우 HashMap이 TreeMap보다 더 뛰어나므로 HashMap을 사용하는 것이 좋고, 범위검색이나 정렬이 필요한 경우에는 TreeMap을 사용하는 것이 좋음

5. Properties

  • Properties의 생성자와 메서드
  • Hashtable을 상속받아 구현한 것
    • Hashtable은 키와 값을 (Object, Object)의 형태로 저장하는데 비해 Properties는 (String, String) 형태로 저장하는 단순화된 컬렉션 클래스
  • 애플리케이션의 환경설정과 관련된 속성을 저장하는데 사용되며 데이터를 파일로부터 읽고 쓰는 기능을 제공
  • Properties는 Hashtable을 상속받아 구현한 것이므로 Map이 특성상 저장순서를 유지하지 않음

6. Collections

  • 컬렉션과 관련된 메서드를 제공
  • java.util.Collection은 인터페이스, java.util.Collections는 클래스

컬렉션의 동기화

  • 멀티 쓰레드 프로그래밍에서는 하나의 객체를 여러 쓰레드가 동시에 접근할 수 있기 때문에 데이터의 일관성(consistency)을 유지하기 위해서는 공유되는 객체에 동기화(synchronization)이 필요
  • ArrayList, HashMap과 같은 컬렉션은 동기화를 자체적으로 처리하지 않고 필요한 경우에만 java.util.Collections 클래스의 동기화 메서드를 이용해 동기화 처리가 가능하도록 함
    • synchronized가 붙은 메서드 사용

변경불가 컬렛션 만들기

  • 컬렉션에 저장된 데이터를 보호하기 위해 컬렉션을 변경할 수 없게, 읽기전용으로 만들어야 할 때가 있음
    • 멀티 쓰레드 프로그래밍에서 여러 쓰레드가 하나의 컬렉션을 공유하다보면 데이터가 손상될 수 있는데, 이를 방지하고자 할 때 사용
  • unmodifiable이 붙은 메서드 사용

싱클톤 컬렉션 만들기

  • 단 하나의 객체만을 저장하는 컬렉션을 만들고 싶은 경우 사용
  • 매개변수로 저장할 요소를 지정하면 해당 요소를 저장하는 컬렉션을 반환하고, 반환된 컬렉션은 변경할 수 없음

  • singleton이 붙은 메서드 사용

한 종류의 객체만 저장하는 컬렉션 만들기

  • 컬렉션에 지정된 종류의 객체만 저장할 수 있도록 제한하고 싶을 때 사용
  • checked가 붙은 메서드 사용

  • 두 번째 매개변수에 저장할 객체의 클래스를 지정

컬렉션 클래스 정리

collectionclass

이미지 출처: https://steady-snail.tistory.com/78

컬렉션 특징
ArrayList 배열기반, 데이터의 추가와 삭제에 불리, 순차적인 추가삭제는 제일 빠름. 임의의 요소에 대한 접근성(accessibility)이 뛰어남
LinkedList 연결기반. 데이터의 추가와 삭제에 유리. 임의의 요소에 대한 접근성이 좋지 않음
HashMap 배열과 연결이 결합된 형태. 추가, 삭제, 검색, 접근성이 모두 뛰어남. 검색에는 최고 성능을 보임
TreeMap 연결기반. 정렬과 검색에 적합. 검색성능은 HashMap보다 떨어짐
Stack Vector를 상속받아 구현
Queue LinkedList가 Queue 인터페이스를 구현
Properties Hashtable을 상속받아 구현
HashSet HashMap을 이용해서 구현
TreeSet TreeMap을 이용해서 구현
LinkedHashMap
LinkedHashSet
HashMap과 HashSet에 저장순서 유지기능 추가

Chapter 11 끝!!!

bronze 1. 설탕 배달(2839)

|

bronze 1. 설탕 배달 (2839)

출처 : https://www.acmicpc.net/problem/2839

문제

설탕을 정확하게 N 킬로그램을 배달해야 함. 봉지는 3 킬로그램, 5 킬로그램이 있음. 최대한 적은 봉지로 배달하려고 할 때 봉지 몇 개를 가져가면 되는지 그 수를 구하는 프로그램을 작성

입력: 배달해야할 설탕 무게

출력: 들고가야할 봉지 수

풀이

  • 아이디어: 5 킬로그램 봉지를 최대한 많이 들고가는 것이 효율적
    • 주어진 무게가 5의 배수일 경우 5로 나눈 몫만큼의 봉지만 들고가면됨
    • 5의 배수가 아닐 경우 5의 배수가 될 때까지 무게에서 3을 빼준 후 봉지 수를 3를 빼준 횟수만큼 증가시킴
    • 3을 뺀 후 남은 무게가 0보다 작을 경우 -1를 출력하고 프로그램을 종료 (정확하게 N 킬로그램을 만들 수 없는 경우)
import java.util.*;

public class Main {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        
        int num = sc.nextInt();
        int count = 0;

        while(true) {
          // 무게가 5의 배수인 경우
          if (num % 5 == 0){
            count += num / 5;
            System.out.println(count);
            break;
          }
          // 무게가 5의 배수가 아닌 경우
          else {
            num -= 3;
            count ++;
          }

          // 정확하게 N 킬로그램을 만들 수 없는 경우
          if (num < 0){
            System.out.println(-1);
            break;
          }
        } 
    }
}

silver 5. 30(10610)

|

silver 5. 30 (10610)

출처 : https://www.acmicpc.net/problem/10610

문제

입력된 수에 포함된 숫자들을 섞어 30의 배수가 되는 가장 큰 수를 만들어주는 프로그램

입력: N를 입력받음. N은 최대 10^5개의 숫자로 구성되어 있으며, 0으로 시작하지 않음

출력: 주어진 숫자로 30의 배수를 만들 수 있다면, 만들 수 있는 30의 배수 중 가장 큰 수 출력. 만들 수 없다면, -1를 출력

풀이

  • 아이디어: 30의 배수는 마지막 자리가 항상 0이고, 각 자리수의 합이 3의 배수가 되어야 함
    • StringBuffer로 입력된 변수를 저장하고 for문을 통해 각 자리수를 더해줌
    • 각 자리수의 합이 3의 배수인 경우, 주어진 수로 만들 수 있는 가장 큰 30의 배수를 찾기 위해 각 자리수를 정렬해주어야 함
      • StringBuffer 변수의 경우 정렬해주는 함수가 없으므로 char형 배열로 변경해 sort()를 수행
      • sort()의 결과는 오름차순이므로, StringBuffer 변수로 값을 받아와 reverse() 연산을 수행함
      • 연산을 마치면 정수형으로 형 변환 해준 뒤 출력
    • 각 자리수의 합이 3의 배수가 아닌 경우, 입력받은 수로 30의 배수를 만들어줄 수 없으므로 -1를 출력

1차 코드

import java.util.*;

public class Main {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        
        StringBuffer tmp = new StringBuffer(sc.nextLine());
        int result = 0;
        
        // 각 자리 수를 모두 더해 result에 저장
        for (int i=0; i<tmp.length(); i++){
            result += tmp.charAt(i);
        }
        
        // result가 3의 배수인 경우 (입력받은 숫자로 30의 배수를 만들 수 있는 경우)
        if (result % 3 == 0){
            char[] cArr = tmp.toString().toCharArray();	// 정렬을 위해 char형 배열로 생성
            Arrays.sort(cArr);	// 오름차순으로 정렬
            tmp = new StringBuffer(new String(cArr)).reverse();	// Stringbuffer에 저장 후 내림차순으로 변경
            System.out.println(Integer.parseInt(tmp.toString()));	// 정수형으로 형변환 후 결과를 보여줌
        }
        else{	// result가 3의 배수가 아닌 경우 (입력받은 숫자로 30의 배수를 만들 수 없는 경우)
            System.out.println(-1);
        }   
    }
}
  • 결과

    • Replit에서는 잘 돌아가지만, 백준에 제출할 경우 Runtime Error 발생

    • 아직 어느 부분이 문제인지 발견하지 못 함 (2022-01-28 문제점 발견)
    • 문제점: input의 최댓값은 자리수가 10^5(십만 자리)인 수. 하지만 int형이 담을 수 있는 최댓값은 20억(10자리)까지이므로 출력해주는 과정에서 int형으로 형변환해서 출력할 경우 런타임 에러(NumberFormat)이 발생
      • NumberFormat: 문자열을 수로 변환할 때 발생하는 에러

2차 코드

import java.util.*;

public class Main {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        
        StringBuffer tmp = new StringBuffer(sc.nextLine());
        int result = 0;
        
        for (int i=0; i<tmp.length(); i++){
            result += tmp.charAt(i)-'0';
        }
        
        if (result % 3 == 0){
            char[] cArr = tmp.toString().toCharArray();
            Arrays.sort(cArr);
            StringBuffer num = new StringBuffer(new String(cArr)).reverse();
            System.out.println(num.toString());	// 수정
        }
        else{
            System.out.println(-1);
        }   
    }
}
  • 출력할 때 int형으로 형변환해주지 않고 문자열로 출력해주는 코드로 변경
  • 결과
    • 백준에 제출했을 때 출력 초과 발생
    • 원인: 30의 배수이기 위해서는 input 값에 0이 포함되어 있어야 하는데 input 값에서 0의 존재를 확인하는 조건을 빼먹음

3차 코드

import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        StringBuilder num = new StringBuilder(sc.nextLine());
        int sum = 0;
        
        for (int i=0; i < num.length(); i++){
            sum += num.charAt(i);
        }
        
        if (num.toString().contains("0") && (sum % 3 == 0)){	// 수정
            char[] cArr = num.toString().toCharArray();
            Arrays.sort(cArr);
            num = new StringBuilder(new String(cArr)).reverse();
            System.out.println(num.toString());
        }
        else {
            System.out.println(-1);
        }
    }
}
  • if문 조건에 input 값에서 0의 존재를 확인하는 코드 추가
  • StringBuffer 대신 StringBuilder 사용
    • 이유: StringBuffer는 멀티 쓰레드 환경에서 동기화 때문에 사용하는 것이기 때문에 알고리즘같은 단일 쓰레드 환경에서는 StringBuilder가 성능이 더 좋음

배운점