백준: 2164번 카드2 (자바, Java)
[백준] 2164번 카드2https://www.acmicpc.net/problem/2164   문제N장의 카드가 있다. 각각의 카드는 차례로 1부터 N까지의 번호가 붙어 있으며, 1번 카드가 제일 위에, N번 카드가 제일 아래인 상태로 순서대로 카드가 놓여 있다. 이제 다음과 같은 동작을 카드가 한 장 남을 때까지 반복하게 된다. 우선, 제일 위에 있는 카드를 바닥에 버린다. 그 다음, 제일 위에 있는 카드를 제일 아래에 있는 카드 밑으로 옮긴다. 예를 들어 N=4인 경우를 생각해 보자. 카드는 제일 위에서부터 1234 의 순서로 놓여있다. 1을 버리면 234가 남는다. 여기서 2를 제일 아래로 옮기면 342가 된다. 3을 버리면 42가 되고, 4를 밑으로 옮기면 24가 된다. 마지막으로 2를 버리고 나..
2024.05.28
no image
자바: BufferedReader , Scanner
입력을 처리하는 방법 중 가장 많이 사용되는 클래스가BufferedReader, Scanner이다. BufferedReader, Scanner 특징BufferedReader- 입력을 버퍼링 하여 빠르게 읽음- readLine()을 사용해 한 줄씩 읽을 수 있음- 멀티스레드 환경에서 안전하게 사용 가능 Scanner- 사용 비교적 간편- 문자열 뿐 아니라 파일, 콘솔 등 다양한 입력 가능- nextLine(), nextInt(), nextTokenizer() 등 다양한 타입을 입력받을 수 있다.- 멀티스레드 환경에서는 부적합- 정규표현식 지  // 임포트 필요 import java.io.BufferedReader;      import java.io.InputStreamReader; import java...
2024.05.27
백준: 1436번 영화감독 숌 (자바, Java)
[백준] 1436번 영화감독 숌https://www.acmicpc.net/problem/1436      문제숫자 6이 연속으로 3개 이상 포함되는 수 중 가장 작은 수는 666이다.그렇다면 숫자 6이 연속으로 3개 이상 포함되는 수 중  N번째로 작은 수를 구하는 프로그램을 작성하라. 입력 :첫째 줄에 N이 주어진다. N은 10,000보다 작거나 같은 자연수이다. 출력 : 첫째 줄에 N번째 영화의 제목에 들어간 수를 출력한다.  나의 답안처음에 문제를 잘못 읽었다. 6이 연속해서 3개 이상 포함되어야 하는데, 연속하지 않아도 3개 이상 포함되기만 하면 되는 줄 알고 charAt() 메서드를 사용해서 코드를 작성했다... 왜 안되나 계속 들여다 보다가 한참 뒤에 문제를 다시 읽고 원인을 발견했다 ㅋㅋㅋ ..
2024.05.25
백준: 1920번 수 찾기 (자바, Java)
[백준] 1920번 수 찾기https://www.acmicpc.net/problem/1920     문제육각형으로 이루어진 벌집이 있다. 중앙의 방 1부터 시작해서 이웃하는 방에 돌아가면서 1씩 증가하는 번호를 주소로 매길 수 있다. 숫자 N이 주어졌을 때, 벌집의 중앙 1에서 N번 방까지 최소 개수의 방을 지나서 갈 때 몇 개의 방을 지나가는지(시작과 끝을 포함하여)를 계산하는 프로그램을 작성하시오. 예를 들면, 13까지는 3개, 58까지는 5개를 지난다. 입력 :첫째 줄에 N(1 ≤ N ≤ 1,000,000,000)이 주어진다. 출력 :입력으로 주어진 방까지 최소 개수의 방을 지나서 갈 때 몇 개의 방을 지나는지 출력한다.  나의 답안 import java.util.*; public class Mai..
2024.05.24
no image
자바: getter, setter 메서드
Getter와 Setter란?객체지향 프로그래밍에서 클래스의 속성(필드)을 외부에서 접근할 수 있도록 하는 메서드데이터 보존을 위해 private으로 객체를 보호하므로, 이 객체의 값에 접근하기 위해서는 같은 클래스 안의 메서드를 만들어두고 해당 메서드를 통해 접근해야 함.Getter : 클래스의 필드 값을 반환하는 메서드Setter : 클래스의 필드 값을 설정하는 메서드 작성법Getter 메서드 :- 반환타입은 필드의 타입과 동일- get + 필드이름(첫 글자 대문자)Setter 메서드 :- 반환타입은 void- set + 필드이름(첫 글자 대문자)public class Person {     // private으로 객체보호     private String name;       private int ..
2024.05.23
백준: 1920번 수 찾기 (자바, Java)
[백준] 1920번 수 찾기https://www.acmicpc.net/problem/1920     문제N개의 정수 A[1], A[2], …, A[N]이 주어져 있을 때, 이 안에 X라는 정수가 존재하는지 알아내는 프로그램을 작성하라입력 :첫째 줄에 자연수 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 줄에는 N개의 정수 A[1], A[2], …, A[N]이 주어진다. 다음 줄에는 M(1 ≤ M ≤ 100,000)이 주어진다. 다음 줄에는 M개의 수들이 주어지는데, 이 수들이 A안에 존재하는지 알아내면 된다. 모든 정수의 범위는 -231 보다 크거나 같고 231보다 작다. 출력 :M개의 줄에 답을 출력. 존재하면 1, 존재하지 않으면 0을 출력 나의 답안 import java.util.*; publ..
2024.05.23
자바: 필드와 생성자
자바에서 필드와 생성자는 모두 클래스의 구성 요소들이다. 클래스의 구성요소는 필드, 메소드, 생성자.  필드객체의 고유 데이터, 속성, 객체의 현재 상태 데이터를 저장변수 선언과 비슷하게 생김클래스 필드와 인스턴스 필드로 나뉜다.  - 클래스 필드 : 모든 객체가 공유하는 변수, 프로그램 종료 시 소멸  - 인스턴스 필드 : 객체마다 별도로 가지는 변수, 인스턴스  public class Person {     // 인스턴스 필드    private String name;     private int age;          // 클래스 필드    private static int population = 0; }   생성자객체 생성 시에만 호출하는 특수한 메서드new 연산자가 객체 생성자를 이용해 객체를..
2024.05.22
백준: 9012번 괄호 (자바, Java)
[백준] 9012번 괄호https://www.acmicpc.net/problem/9012     문제괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올바른 괄호 문자열(Valid PS, VPS)이라고 부른다. 한 쌍의 괄호 기호로 된 “( )” 문자열은 기본 VPS 이라고 부른다. 만일 x 가 VPS 라면 이것을 하나의 괄호에 넣은 새로운 문자열 “(x)”도 VPS 가 된다. 그리고 두 VPS x 와 y를 접합(concatenation)시킨 새로운 문자열 xy도 VPS 가 된다. 예를 들어 “(())()”와 “((()))” 는 VPS 이지만 “(()(”, “(())()))” ..
2024.05.21
백준: 2525번 오븐 시계 (자바, Java)
[백준] 2525번 오븐 시계https://www.acmicpc.net/problem/2525    문제KOI 전자에서는 건강에 좋고 맛있는 훈제오리구이 요리를 간편하게 만드는 인공지능 오븐을 개발하려고 한다. 인공지능 오븐을 사용하는 방법은 적당한 양의 오리 훈제 재료를 인공지능 오븐에 넣으면 된다. 그러면 인공지능 오븐은 오븐구이가 끝나는 시간을 분 단위로 자동적으로 계산한다. 또한, KOI 전자의 인공지능 오븐 앞면에는 사용자에게 훈제오리구이 요리가 끝나는 시각을 알려 주는 디지털 시계가 있다. 훈제오리구이를 시작하는 시각과 오븐구이를 하는 데 필요한 시간이 분단위로 주어졌을 때, 오븐구이가 끝나는 시각을 계산하는 프로그램을 작성하시오. 입력 :첫째 줄에는 현재 시각이 나온다. 현재 시각은 시 A ..
2024.05.20
no image
백준: 2588번 곱셈 (자바, Java)
[백준] 2388번 곱셈https://www.acmicpc.net/problem/2588   문제(세 자리 수) × (세 자리 수)는 다음과 같은 과정을 통하여 이루어진다.(1)과 (2)위치에 들어갈 세 자리 자연수가 주어질 때 (3), (4), (5), (6)위치에 들어갈 값을 구하는 프로그램을 작성하라 입력 : 첫째 줄에 (1)의 위치에 들어갈 세 자리 자연수가, 둘째 줄에 (2)의 위치에 들어갈 세자리 자연수가 주어진다. 출력 : 첫째 줄부터 넷째 줄까지 차례대로 (3), (4), (5), (6)에 들어갈 값을 출력한다. 나의 답안 일단 (6)은 그냥 A*B 해주면 되고.. 100의 자리 수는 100으로 나눠주면 몫이 그것이고, 1의 자리는 A를 10으로 나눈 나머지로 하면 되겠네? 생각했다. 그리..
2024.05.19


[백준] 2164번 카드2

https://www.acmicpc.net/problem/2164

 

 

 

문제

N장의 카드가 있다. 각각의 카드는 차례로 1부터 N까지의 번호가 붙어 있으며, 1번 카드가 제일 위에, N번 카드가 제일 아래인 상태로 순서대로 카드가 놓여 있다.

이제 다음과 같은 동작을 카드가 한 장 남을 때까지 반복하게 된다. 우선, 제일 위에 있는 카드를 바닥에 버린다. 그 다음, 제일 위에 있는 카드를 제일 아래에 있는 카드 밑으로 옮긴다.

예를 들어 N=4인 경우를 생각해 보자. 카드는 제일 위에서부터 1234 의 순서로 놓여있다. 1을 버리면 234가 남는다. 여기서 2를 제일 아래로 옮기면 342가 된다. 3을 버리면 42가 되고, 4를 밑으로 옮기면 24가 된다. 마지막으로 2를 버리고 나면, 남는 카드는 4가 된다.

N이 주어졌을 때, 제일 마지막에 남게 되는 카드를 구하는 프로그램을 작성하시오.

 

입력 :

첫째 줄에 정수 N(1 ≤ N ≤ 500,000)이 주어진다.

출력 :

첫째 줄에 남게 되는 카드의 번호를 출력한다.

 

 

나의 답안

 

처음엔 다이나믹프로그래밍인가 하고

D(1) = 1

D(2) = 2

D(3) = 2

...

풀었으나, 일정 규칙이 보이질 않았다.

 

한참 헛다리 짚다가, 리스트를 사용해 직접 처리하는 코드를 작성했지만,

 

시간 초과로 실패.

 

알고보니 큐(Queue)를 이용해 푸는 문제였다.

 

<List를 사용한 코드>
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.io.*;
import java.util.*;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());

        List<Integer> list = new ArrayList<>();

        for (int i = 1; i <= N; i++) {
            list.add(i);
        }

        while (list.size() > 1) {
            list.remove(0);
            list.add(list.get(0));
            list.remove(0);
        }

        System.out.println(list.get(0));
    }
}

 

 

 

 

개선 사항

<Queue를 사용한 코드>
import java.io.*;
import java.util.LinkedList;
import java.util.Queue;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());

        Queue<Integer> queue = new LinkedList<>();

        for (int i = 1; i <= N; i++) {
            queue.add(i);
        }

        while (queue.size() > 1) {
            queue.poll();
            queue.add(queue.poll());
        }

        System.out.println(queue.peek());
    }
}
  • List에서의 remove(0)은 첫 번째 요소를 제거하고 나머지 요소를 1칸씩 당겨와야 하기 때문에
    O(N)의 시간복잡도를 가진다.
  • Queue의 poll()은 FIFO구조로 맨 앞의 것만 빼오면 알아서 정렬되기에 O(1)의 시간복잡도를 가진다.

 

큐는 거의 사용해보질 않아서 생각을 못했다.

 

가독성은 둘 다 비슷하지만, 

 

효율성 측면에서 큰 차이가 있었다.

 

각 타입의 성질을 잘 파악해서 활용해야겠다.

자바: BufferedReader , Scanner

친환경 개발자
|2024. 5. 27. 22:26


입력을 처리하는 방법 중 가장 많이 사용되는 클래스가

BufferedReader, Scanner이다.

 

BufferedReader, Scanner 특징

BufferedReader

- 입력을 버퍼링 하여 빠르게 읽음

- readLine()을 사용해 한 줄씩 읽을 수 있음

- 멀티스레드 환경에서 안전하게 사용 가능

 

Scanner

- 사용 비교적 간편

- 문자열 뿐 아니라 파일, 콘솔 등 다양한 입력 가능

- nextLine(), nextInt(), nextTokenizer() 등 다양한 타입을 입력받을 수 있다.

- 멀티스레드 환경에서는 부적합

- 정규표현식 지

 

 

<BufferedReader 예시>

// 임포트 필요

import java.io.BufferedReader;      

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

public class BufferedReaderExample {
    public static void main(String[] args) {
        // 입력 받기 위한 변수 선언
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        try {
            System.out.print("Enter your name: ");
            String name = reader.readLine();  // 한 줄씩 입력
            System.out.println("Hello, " + name + "!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

<Scanner 예시>
// 임포트 필요

import java.util.Scanner;


public class ScannerExample {
    public static void main(String[] args) {
        // 입력 받기 위한 변수 선언

        Scanner scanner = new Scanner(System.in);
        System.out.print("Enter your name: ");
        String name = scanner.nextLine(); 
        System.out.println("Hello, " + name + "!");
    }
}

 

비교

 

특징 BufferedReader Scanner
입력속도 더 빠름 비교적 느림
사용 용이성 복잡 (예외처리, 입력타입 문자열 뿐) 간편 (다양한 메서드 제공)
데이터 타입 String 다양 (int, double,String 등)
정규 표현식 지원 X 지원
멀티스레드 환경 멀티스레드에서 안전 멀티스레드에서 위험

 

 

 

 

 

 

 

속도차이가 나는 이유는 Buffer 사용 여부 차이, 정규표현식 적용 과정 여부 등 때문

 

여기서 Buffer란 데이터를 일시적으로 저장하는 메모리 공간을 말함.

 

BufferedReader는 8KB 크기의 버퍼에 저장되었다가 한 번에 전송하는 방식이고

 

Scanner는 입력에 바로바로 전송되는 방식

 

바로바로 전송되는 것보다 여러개 묶어서 보내는 것이 더 효율적이라는 원리.

 

 

 

 

 

결론

 

BufferedReader는 데이터 입력이 많거나 멀티스레드 환경, 빠르고 효율적인 처리가 필요할 때 사용

Scanner 다양한 데이터 타입을 입력할 수 있어 간편하므로 간단한 입력 처리인 경우에 용이

 

웬만하면 BufferedReader 사용하는 것으로 하자..

 

 


[백준] 1436번 영화감독 숌

https://www.acmicpc.net/problem/1436

 

 

 

 

 

 

문제

숫자 6이 연속으로 3개 이상 포함되는 수 중 가장 작은 수는 666이다.

그렇다면 숫자 6이 연속으로 3개 이상 포함되는 수 중  N번째로 작은 수를 구하는 프로그램을 작성하라.
 

입력 :

첫째 줄에 N이 주어진다. N은 10,000보다 작거나 같은 자연수이다.

출력 :

첫째 줄에 N번째 영화의 제목에 들어간 수를 출력한다.

 

 

나의 답안

처음에 문제를 잘못 읽었다.

 

6이 연속해서 3개 이상 포함되어야 하는데, 연속하지 않아도 3개 이상 포함되기만 하면

 

되는 줄 알고 charAt() 메서드를 사용해서 코드를 작성했다...

 

왜 안되나 계속 들여다 보다가 한참 뒤에 문제를 다시 읽고 원인을 발견했다 ㅋㅋㅋ

 

 

import java.util.*;

public class Main {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int count = 0;
        int i = 666;

        while (count < n) {
            String s = String.valueOf(i);
            if (s.contains("666")) count++;
            if (count == n) break;
            i++;
        }

        System.out.println(i);
    }
}

 

어떻게 하면 효율적으로 풀까 하다가 생각이 나지 않아 무식하게(?) 작성해봤는데 통과되었다.

 

count 변수를 이용해 몇 번째 숫자인지를 카운트했고,

 

666부터 시작해 수를 1씩 올려가며

 

contains()메서드를 이용해 해당 숫자에 6이 연속 3회 이상 포함되는지 확인했다.

 

 

 

개선 사항

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

public class Main {
    public static void main(String[] args) throws IOException{
        // Scanner에 비해 처리속도 높음
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
        int n = Integer.parseInt(br.readLine());

        int count = 1;
        int num = 666;

        while (count < n) {
            num++;    //조건문 말미에 넣는 대신 처음에 넣음으로써 break;문 제거
            if (Integer.toString(num).contains("666")) count++;
        }

        System.out.println(num);
    }
}
  • Scanner보다 BufferedReader를 통해 입력 받는 것이 처리 속도 면에서 유리
  • 문자열 변수를 별도로 생성하는 대신 Integer.toString(num)을 사용
  • while문 첫부분에 num++를 넣음으로써 불필요한 break문 제거

 

※브루트포스 알고리즘:

문제를 해결하기 위해 가능한 모든 경우의 수를 탐색하는 방법

규모가 작거나, 다른 최적화된 알고리즘을 사용하기 어려울 때 유용하다.

 

장점

1. 확실성: 모든 가능성을 탐색하기 때문에 100%의 정확도를 가짐

2. 단순성: 구현이 쉽고 직관적임

 

단점

1. 비효율성: 경우의 수가 많아질수록 시간이 오래 걸림

2. 고비용: 데이터소모가 매우 많아짐

 

브루트포스 알고리즘을 쓰더라도, 확실하게 정답이 아닌 것들은 최대한

제거해주는 코딩을 하는 것이 바람직할 것으로 보인다!


[백준] 1920번 수 찾기

https://www.acmicpc.net/problem/1920

 

 

 

 

 

문제

육각형으로 이루어진 벌집이 있다. 중앙의 방 1부터 시작해서 이웃하는 방에 돌아가면서 1씩 증가하는 번호를 주소로 매길 수 있다. 숫자 N이 주어졌을 때, 벌집의 중앙 1에서 N번 방까지 최소 개수의 방을 지나서 갈 때 몇 개의 방을 지나가는지(시작과 끝을 포함하여)를 계산하는 프로그램을 작성하시오. 예를 들면, 13까지는 3개, 58까지는 5개를 지난다.


입력 :

첫째 줄에 N(1 ≤ N ≤ 1,000,000,000)이 주어진다.

출력 :

입력으로 주어진 방까지 최소 개수의 방을 지나서 갈 때 몇 개의 방을 지나는지 출력한다.

 

 

나의 답안

 

import java.util.*;

public class Main {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();

        int count = 1;
        int a = 1;

        for (int i=0; i<N/6; i++) {
            a += 6*i;
            if(a >= N) {
                System.out.println(count);
                break;
            }
            count++;
        }
    }
}

 

계차수열처럼, 1칸씩 바깥으로 나갈수록 그전 값이랑 6*n만큼 차이가 나는 것을 알 수 있다.

 

따라서 N=1 이면 1칸, N=2~7이면 2칸, N=8~19이면 3칸 이런 방식.

 

for문을 사용해 a값을 6*i만큼 늘려가며 범위를 넓혔고,

 

count를 사용해 값을 반환하도록 작성했다.

 

다만, for문을 사용할 경우 i의 값을 N/6까지로 설정했는데,

 

break;를 사용하긴 했지만 불필요한 반복이 발생할 수도 있고

 

그렇게 보기 좋은 코드는 아닌 것 같다.

 

 

 

개선 사항

 

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        sc.close();
        
        int count = 1; 
        int range = 1; 
        
        while (N > range) {
            range += 6 * count;
            count++;
        }
        
        System.out.println(count);
    }
}
  • 변수를 a 대신 range로 바꿔 가독성을 높였다.
  • for문 대신 while문을 사용하여 불필요한 반복의 가능성을 제거했다.
  • 코드가 한결 간결해졌다.

 

계차수열을 어떻게 반복문에 표현할까를 생각보다 오래 고민했다.

 

바로바로 나오는 수준이 되어야 할텐데..

 

더 열공하자

자바: getter, setter 메서드

친환경 개발자
|2024. 5. 23. 21:18

 

 

Getter와 Setter란?

  • 객체지향 프로그래밍에서 클래스의 속성(필드)을 외부에서 접근할 수 있도록 하는 메서드
  • 데이터 보존을 위해 private으로 객체를 보호하므로, 이 객체의 값에 접근하기 위해서는 같은 클래스 안의 메서드를 만들어두고 해당 메서드를 통해 접근해야 함.
  • Getter : 클래스의 필드 값을 반환하는 메서드
  • Setter : 클래스의 필드 값을 설정하는 메서드

 

작성법

  • Getter 메서드 :
    - 반환타입은 필드의 타입과 동일
    - get + 필드이름(첫 글자 대문자)

  • Setter 메서드 :
    - 반환타입은 void
    - set + 필드이름(첫 글자 대문자)

public class Person {
    // private으로 객체보호

    private String name;   
    private int age;

    // 이름 반환
    public String getName() {
        return name;
    }

    // 이름 설정
    public void setName(String name) {
        this.name = name;
    }

    // 나이 반환
    public int getAge() {
        return age;
    }

    // 나이 설정
    public void setAge(int age) {
        this.age = age;
    }
}

 

 

사용하는 이유?

  • 캡슐화: 클래스 내부 구현을 숨기고(정보 은닉), 외부에서의 접근을 제한하여 객체 보호
                 >> 마치 TV를 볼 때 TV가 어떻게 작동하는지 원리를 우리가 모르고 쓰는 것과 같음
  • 유효성 검사 : Setter를 통해 값 설정 시 유효성 검사 수행 가능
  • 디버깅, 유지보수 : 코드의 가독성을 높이고 메서드 수정을 통해 유지보수 용이하게 함

 

장점

  • 데이터 접근 제어: 객체의 속성에 대한 읽기 및 쓰기 권한 제어
  • 캡슐화

단점

  • 실질적인 정보 노출: 변수를 private를 선언하더라도 getter, setter를 통해 접근하면 데이터 접근이 가능
  • 외부 접근 시 캡슐화가 지켜지지 않아 코드 안정성이 무너질 수 있음

 

Getter, Setter 메서드 사용 시 데이터에 접근 권한을 주는 것과 마찬가지.

데이터의 무결성을 약화시킨다.

따라서 사용을 지양하는 것이 좋다.

 

 

인텔리제이 꿀팁

인텔리제이에서 편리하게 getter, setter 메서드를 작성하는 팁이 있다.

마우스 우클릭 - Generate 클릭

 

Getter and Setter 클릭

 

 

 

OK
생성 완료


[백준] 1920번 수 찾기

https://www.acmicpc.net/problem/1920

 

 

 

 

 

문제

N개의 정수 A[1], A[2], …, A[N]이 주어져 있을 때, 이 안에 X라는 정수가 존재하는지 알아내는 프로그램을 작성하라

입력 :

첫째 줄에 자연수 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 줄에는 N개의 정수 A[1], A[2], …, A[N]이 주어진다. 다음 줄에는 M(1 ≤ M ≤ 100,000)이 주어진다. 다음 줄에는 M개의 수들이 주어지는데, 이 수들이 A안에 존재하는지 알아내면 된다. 모든 정수의 범위는 -231 보다 크거나 같고 231보다 작다.

출력 :

M개의 줄에 답을 출력. 존재하면 1, 존재하지 않으면 0을 출력

 

나의 답안

 

import java.util.*;

public class Main {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        StringBuilder sb = new StringBuilder();

        for (int i=0; i<N; i++) {
            sb.append(sc.next());
        }
        String str = sb.toString();

        int M = sc.nextInt();
        for (int i=0; i<M; i++) {
            System.out.println(str.contains(sc.next())? 1 : 0);
        }
    }
}

 

처음엔 StringBuilder를 사용하여 답을 출력하는 코드를 작성했으나 시간초과되었다.

 

contains() 메서드를 사용했는데,

 

찾아보니 해당 메서드는 O(N*M)의 시간 복잡도(여기서는 O(5*5)를 가져 시간 초과를 유발한 것으로 보인다.

 

 

import java.util.*;

public class Main {

    static int[] A;
    public static int binarySearch(int start, int end, int target) {
        int mid = (start + end) / 2;
        if (mid > end || mid < start) return 0;
        if (A[mid] == target) return 1;
        if (A[mid] < target) return binarySearch(mid+1, end, target);
        if (A[mid] > target) return binarySearch(start, mid-1, target);
        return 0;
    }

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        A = new int[N];

        for (int i=0; i<N; i++) {
            A[i] = sc.nextInt();
        }
        Arrays.sort(A);

        int M = sc.nextInt();
        for (int i=0; i<M; i++) {
            System.out.println(binarySearch(0, N-1, sc.nextInt()));
        }
    }
}

 

이진탐색 방법을 사용하여 구했다.

입력을 A배열에 담고, 오름차순 정렬한 후,

입력받은 값과 A배열의 중간값을 비교하여 더 크면

중간값 이후의 값들과 비교, 작으면 중간값 이전의 값들과 비교해가며

탐색 영역을 반씩 줄여나가는 방법.

 

첫 번째 코드의 시간 복잡도는 contains메서드를 사용해 O(5*5)정도라고 하면,

이진탐색의 시간복잡도는 O(5*log5) 이기 때문에,

두번째 코드가 시간 초과를 면할 수 있던 것으로 보인다.

 

개선 사항

 

import java.util.*;

public class Main {

    static int[] A;

    public static int binarySearch(int start, int end, int target) {

        // while문으로 가독성 UP
        while (start <=end) {
            int mid = (start + end) / 2;
            if (A[mid] == target) return 1;
            if (A[mid] < target) start = mid + 1;
            else end = mid - 1;
        }
        return 0;
    }

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        A = new int[N];

        for (int i=0; i<N; i++) {
            A[i] = sc.nextInt();
        }
        Arrays.sort(A);

        int M = sc.nextInt();
        for (int i=0; i<M; i++) {
            System.out.println(binarySearch(0, N-1, sc.nextInt()));
        }
    }
}
  • 재귀호출 대신 while 조건문을 사용하여 가독성이 좋아진 듯하다.
  • 성능 면에서는 차이가 크게 없을 것으로 보임

 

Arrays.sort를 사용하면 무조건 비효율적일 것이다 생각했는데,

오히려 contains메서드를 사용한 코드가 더 비효율적일 수 있다는 것을 깨달았던 문제이다.

자바: 필드와 생성자

친환경 개발자
|2024. 5. 22. 22:18

자바에서 필드와 생성자는 모두 클래스의 구성 요소들이다.

 

클래스의 구성요소는 필드, 메소드, 생성자.

 

 

필드

  • 객체의 고유 데이터, 속성, 객체의 현재 상태 데이터를 저장
  • 변수 선언과 비슷하게 생김
  • 클래스 필드와 인스턴스 필드로 나뉜다.
      - 클래스 필드 : 모든 객체가 공유하는 변수, 프로그램 종료 시 소멸
      - 인스턴스 필드 : 객체마다 별도로 가지는 변수, 인스턴스

 

 

public class Person {
    // 인스턴스 필드
    private String name;
    private int age;
    
    // 클래스 필드
    private static int population = 0;
}

 

 

생성자

  • 객체 생성 시에만 호출하는 특수한 메서드
  • new 연산자가 객체 생성자를 이용해 객체를 생성
  • 클래스의 이름과 동일
  • 반환형 없음

 

public class Person {
    private String name;
    private int age;
    
    // 기본 생성자
    public Person1() {
        this.name = "Unknown";
        this.age = 0;
    }

    // 매개변수가 있는 생성자
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // getter 메서드
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }

    public static void main(String[] args) {
        // 기본 생성자를 사용하여 객체 생성
        Person person1 = new Person();
        System.out.println(person1.getName()); // 출력: Unknown
        System.out.println(person1.getAge());  // 출력: 0

        // 매개변수가 있는 생성자를 사용하여 객체 생성
        Person person2 = new Person("Alice", 30);
        System.out.println(person2.getName()); // 출력: Alice
        System.out.println(person2.getAge());  // 출력: 30

 

 

 

 

생성자 오버로딩

생성자는 같은 이름으로 여러 개를 생성할 수 있어 유연성 높임

받는 매개변수의 수를 조절해서 사용

 

public class Person {
    private String name;
    private int age;
    
    // 기본 생성자
    public Person() {
        this.name = "Unknown";
        this.age = 0;
    }

    // 매개변수가 1개인 생성자
    public Person(String name) {
        this.name = name;
        this.age = 0;
    }

    // 매개변수가 2개인 생성자
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // getter 메서드
    public String getName() {
        return name;
    }

    public static void main(String[] args) {
        // 각 생성자를 사용해 객체 생성
        Person person1 = new Person();
        Person person2 = new Person("Park");
        Person person3 = new Person("Lee", 20);

        System.out.println(person1.getName());    // 출력 : Unknown
        System.out.println(person2.getName());    // 출력 : Park
        System.out.println(person3.getName());    // 출력 : Lee
    }
}


[백준] 9012번 괄호

https://www.acmicpc.net/problem/9012

 

 

 

 

 

문제

괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올바른 괄호 문자열(Valid PS, VPS)이라고 부른다. 한 쌍의 괄호 기호로 된 “( )” 문자열은 기본 VPS 이라고 부른다. 만일 x 가 VPS 라면 이것을 하나의 괄호에 넣은 새로운 문자열 “(x)”도 VPS 가 된다. 그리고 두 VPS x 와 y를 접합(concatenation)시킨 새로운 문자열 xy도 VPS 가 된다. 예를 들어 “(())()”와 “((()))” 는 VPS 이지만 “(()(”, “(())()))” , 그리고 “(()” 는 모두 VPS 가 아닌 문자열이다. 

여러분은 입력으로 주어진 괄호 문자열이 VPS 인지 아닌지를 판단해서 그 결과를 YES 와 NO 로 나타내어야 한다. 

입력 :

입력 데이터는 표준 입력을 사용한다. 입력은 T개의 테스트 데이터로 주어진다. 입력의 첫 번째 줄에는 입력 데이터의 수를 나타내는 정수 T가 주어진다. 각 테스트 데이터의 첫째 줄에는 괄호 문자열이 한 줄에 주어진다. 하나의 괄호 문자열의 길이는 2 이상 50 이하이다. 

출력 :

출력은 표준 출력을 사용한다. 만일 입력 괄호 문자열이 올바른 괄호 문자열(VPS)이면 “YES”, 아니면 “NO”를 한 줄에 하나씩 차례대로 출력해야 한다. 

 

나의 답안

 

1. counter=0 변수 선언

2. 맨 앞글자부터 '(' 일 때 counter + 1      ')' 일 때 counter - 1 해준다.

3. counter값이 0이면 YES, 아니면 NO 출력

4. 도중에 counter값이 음수가 될 경우 반복문 종료 후 NO 출력

import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
       
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());    // 입력 개수 입력

        for (int i=0; i<N; i++) {        
            String str = br.readLine(); 
            int counter = 0;
            for (int j=0; j<str.length(); j++){
                if (str.charAt(j) == '(') {
                    counter += 1;
                } else {
                    counter -= 1;
                    if (counter < 0) {
                        break;
                    }
                }
            }
            System.out.println(counter==0 ? "YES" : "NO");
        }
    }
}

 

삼항연산자를 사용하여 작성해봤다.

 

짧지만 가독성은 좋지 않다.

 

 

다른 답안

import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int N = Integer.parseInt(br.readLine());
        Stack<Character> stack = new Stack<>();

        for(int i=0; i<N; i++) {
            String str = br.readLine();
            int length = str.length();

            for(int j=0; j<length; j++) {
                char ch = str.charAt(j);

                if(ch == '(') {
                    stack.push(ch);
                }
                else {
                    int size = stack.size();
                    if(size == 0) {
                        stack.push(ch);
                        break;
                    }
                    else {
                        stack.pop();
                    }
                }
            }

            if(stack.isEmpty()) {
                System.out.println("YES");
            }
            else {
                System.out.println("NO");
            }

            stack.clear();
        }
    }
}
  • stack구조를 사용해 좀 더 간단하게 구현했다.
  • '(' 일 때 stack.push()를, ')'일 때 stack.pop()을 사용
  • ')'일 때 stack에 요소가 없으면 반복문 빠져나와 NO 출력

stack 구조를 사용해야겠다는 생각을 하지 못했다.

stack을 사용하기에 아주 좋은 문제였던 것 같다...

 

다만, counter변수를 사용하는 것이  메모리 사용량이 더 적고 연산이 간단하며,

stack을 사용하는 것은  코드의 길이를 늘리고 복잡성을 증가시킬 수 있으므로 주의


[백준] 2525번 오븐 시계

https://www.acmicpc.net/problem/2525

 

 

 

 

문제

KOI 전자에서는 건강에 좋고 맛있는 훈제오리구이 요리를 간편하게 만드는 인공지능 오븐을 개발하려고 한다. 인공지능 오븐을 사용하는 방법은 적당한 양의 오리 훈제 재료를 인공지능 오븐에 넣으면 된다. 그러면 인공지능 오븐은 오븐구이가 끝나는 시간을 분 단위로 자동적으로 계산한다.

또한, KOI 전자의 인공지능 오븐 앞면에는 사용자에게 훈제오리구이 요리가 끝나는 시각을 알려 주는 디지털 시계가 있다.

훈제오리구이를 시작하는 시각과 오븐구이를 하는 데 필요한 시간이 분단위로 주어졌을 때, 오븐구이가 끝나는 시각을 계산하는 프로그램을 작성하시오.


입력 :

첫째 줄에는 현재 시각이 나온다. 현재 시각은 시 A (0 ≤ A ≤ 23) 와 분 B (0 ≤ B ≤ 59)가 정수로 빈칸을 사이에 두고 순서대로 주어진다. 두 번째 줄에는 요리하는 데 필요한 시간 C (0 ≤ C ≤ 1,000)가 분 단위로 주어진다.

출력 :

첫째 줄에 종료되는 시각의 시와 분을 공백을 사이에 두고 출력한다. (단, 시는 0부터 23까지의 정수, 분은 0부터 59까지의 정수이다. 디지털 시계는 23시 59분에서 1분이 지나면 0시 0분이 된다.)

 

 

나의 답안

 

분이 60분이 넘을 때, 60으로 나눈 몫만큼 '시' 부분을 높여주되,

'시' 부분이 24이상일 경우에는 0부터 표현해줘야 한다.

 

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();
        int c = sc.nextInt();

        System.out.println(a+(b+c)/60 > 23 ? a+(b+c)/60-24 + " " + (b+c)%60 : a+(b+c)/60 + " " + (b+c)%60);
    }
}

 

삼항연산자를 사용하여 작성해봤다.

 

짧지만 가독성은 좋지 않다.

 

 

모범 답안

import java.util.Scanner;

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

int A = sc.nextInt();
int B = sc.nextInt();
int C = sc.nextInt();

B += C;

A = (A + B/60)%24;
B = B%60;

System.out.println(A+" "+B);
}
}
  • B에 C를 더한 값으로 B에 다시 할당함
  • 나는 if문을 사용해 '시'가 24 이상일 경우 24를 빼도록 작성했지만,
    해당 답안에서는 if문 사용 없이 답을 도출할 수 있도록 작성되었다.

 

B에 바로 C값을 더해주는 부분과 A값을 if문 없이 표현했다는 점이 인상 깊다.

내 코드에 비해 가독성과 효율성 측면에서 더 좋은 코드라는 생각이 든다.


[백준] 2388번 곱셈

https://www.acmicpc.net/problem/2588

 

 

 

문제

(세 자리 수) × (세 자리 수)는 다음과 같은 과정을 통하여 이루어진다.

(1)과 (2)위치에 들어갈 세 자리 자연수가 주어질 때 (3), (4), (5), (6)위치에 들어갈 값을 구하는 프로그램을 작성하라

 

입력 :

첫째 줄에 (1)의 위치에 들어갈 세 자리 자연수가, 둘째 줄에 (2)의 위치에 들어갈 세자리 자연수가 주어진다.

출력 :

첫째 줄부터 넷째 줄까지 차례대로 (3), (4), (5), (6)에 들어갈 값을 출력한다.

 

나의 답안

 

일단 (6)은 그냥 A*B 해주면 되고..

 

100의 자리 수는 100으로 나눠주면 몫이 그것이고,

 

1의 자리는 A를 10으로 나눈 나머지로 하면 되겠네? 생각했다.

 

그리고 10의 자리가 조금 고민이었다.

 

그러다 결국 10으로 나누면, 100의 자리와 10의 자리만 남을 것이고, 거기에 10을 나눈 나머지가

 

10의 자리 수가 되겠다는 생각을 하고 코드를 작성했다.

 

 

import java.util.*;

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


        System.out.println(A*(B%10));
        System.out.println(A*((B/10)%10));
        System.out.println(A*(B/100));
        System.out.println(A*B);
    }
}

 

 

모범 답안

import java.util.Scanner;

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

         int c = (b % 10) * a;
         int d = ((b % 100) / 10) * a;
         int e = (b / 100) * a;
         System.out.println(c);
         System.out.println(d);
         System.out.println(e);
         System.out.println(a * b);
    }
}

 

 

  • 1의 자리 수와 100의 자리는 내 답안과 동일.
  • 10의 자리는 100을 나눈 나머지에 10을 나눈 몫으로 추출