자바: Queue(큐)
Queue(큐)데이터의 순서를 유지, 가장 먼저 들어온 데이터가 가장 먼저 나가는 자료 구조(선입선출 = FirstInFirstOut)줄 서기, 인쇄 작업 처리, 프로세스 관리 등에서 사용  자바에서 큐의 주요 메서드add(요소값): 큐의 끝에 요소를 추가 (큐가 다 차면 예외 발생)offer(요소값): 큐의 끝에 요소를 추가 (큐가 다 차면 false 반환)remove(): 큐의 앞에서 요소를 제거하고 반환 (비어있으면 예외 발생)poll(): 큐의 앞에서 요소를 제거하고 반환 (비어있으면 null 반환)element(): 큐의 앞에 있는 요소를 반환 (비어있으면 예외 발생)peek(): 큐의 앞에 있는 요소를 반환 (비어있으면 null 반환)isEmpty(): 큐가 비어있는지 확인 (true / fa..
2024.06.02
자바: StringTokenizer 사용법, split과의 차이
StringTokenizer??문자열을 원하는 구분자로 나누어 토큰으로 분리할 때 사용java.util 패키지에 속해 있음기본은 공백 기준으로 쪼개준다  사용법1. 기본 구분 (공백으로 구분) String str = "Java is fun"; StringTokenizer st = new StringTokenizer(str); while (st.hasMoreTokens()) {     System.out.println(st.nextToken()); }     // 출력: Java   is   fun    2. 원하는 구분자로 구분두 번째 매개변수로 원하는 구분자를 입력하면 해당 구분자를 기준으로 쪼개준다.String str = "Java, is, fun"; StringTokenizer st = new St..
2024.05.29
백준: 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

자바: Queue(큐)

친환경 개발자
|2024. 6. 2. 21:56



Queue(큐)

  • 데이터의 순서를 유지, 가장 먼저 들어온 데이터가 가장 먼저 나가는 자료 구조(선입선출 = FirstInFirstOut)
  • 줄 서기, 인쇄 작업 처리, 프로세스 관리 등에서 사용

 

 

자바에서 큐의 주요 메서드

  • add(요소값): 큐의 끝에 요소를 추가 (큐가 다 차면 예외 발생)
  • offer(요소값): 큐의 끝에 요소를 추가 (큐가 다 차면 false 반환)

  • remove(): 큐의 앞에서 요소를 제거하고 반환 (비어있으면 예외 발생)

  • poll(): 큐의 앞에서 요소를 제거하고 반환 (비어있으면 null 반환)

  • element(): 큐의 앞에 있는 요소를 반환 (비어있으면 예외 발생)

  • peek(): 큐의 앞에 있는 요소를 반환 (비어있으면 null 반환)

  • isEmpty(): 큐가 비어있는지 확인 (true / false)

  • size(): 큐의 요소 개수 반환

 

 

예시

import java.util.LinkedList;
import java.util.Queue;

public class Main {
    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();

        // 요소 추가 (enqueue)
        queue.add(1);  // 또는 queue.offer(1);
        queue.add(2);
        queue.add(3);

        // 요소 확인 (peek)
        System.out.println("Front element: " + queue.peek());  // 또는 queue.element();

        // 요소 제거 (dequeue)
        System.out.println("Removed element: " + queue.poll());  // 또는 queue.remove();

        // 큐가 비어있는지 확인
        System.out.println("Is queue empty? " + queue.isEmpty());

        // 큐의 크기 확인
        System.out.println("Queue size: " + queue.size());
    }
}



StringTokenizer??

  • 문자열을 원하는 구분자로 나누어 토큰으로 분리할 때 사용
  • java.util 패키지에 속해 있음
  • 기본은 공백 기준으로 쪼개준다

 

 

사용법

1. 기본 구분 (공백으로 구분)

 

String str = "Java is fun";
StringTokenizer st = new StringTokenizer(str);

while (st.hasMoreTokens()) {
    System.out.println(st.nextToken());
}
    // 출력: Java   is   fun

 

 

 

 

2. 원하는 구분자로 구분

두 번째 매개변수로 원하는 구분자를 입력하면 해당 구분자를 기준으로 쪼개준다.

String str = "Java, is, fun";
StringTokenizer st = new StringTokenizer(str, ", ");

while (st.hasMoreTokens()) {
    System.out.println(st.nextToken());
}
   //출력: Java   is   fun

   

 

 

3. 구분자까지 토큰으로 포함

 

세 번째 매개변수를 true로 설정할 경우 구분자까지 하나의 토큰으로 간주한다!

String str = "Java,is,fun";
StringTokenizer st = new StringTokenizer(str, ",", true);

while (st.hasMoreTokens()) {
    System.out.println(st.nextToken());
}
    // 출력: Java   ,   is   , fun

  

 

 

 

 

StringTokenizer의 주요 메서드

1. hasMoreTokens(): 다음 토큰이 있는지 확인

 

2. nextToken(): 다음 토큰을 반환

 

3. countTokens(): 남은 토큰의 수 반환

 

 

 

 

 

 

split과의 차이?

 

StringTokenizer는 클래스이고, split은 String클래스에 있는 메서드이다!

 

StringTokenizer는 구분자로 문자열 or 문자 사용, split은 정규표현식 지원한다.

 

따라서 StringTokenizer는 간단한 작업, 가볍게 사용할 때 사용하며,

 

split은 정규표현식을 처리하는 만큼 복잡하고 유연한 사용이 필요할 경우에 사용하기 좋다.


[백준] 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을 사용하는 것은  코드의 길이를 늘리고 복잡성을 증가시킬 수 있으므로 주의