no image
[JPA] 영속성 컨텍스트(Persistence Context)
이 글은 인프런 김영한님의 Spring 강의를 바탕으로 개인적인 정리를 위해 작성한 글입니다.JPA 구동 방식엔티티 매니저 팩토리 (EntityManagerFactory)정의EntityManagerFactory는 JPA 애플리케이션에서 EntityManager 인스턴스를 생성하기 위한 팩토리이다. 특징비용이 많이 드는 객체: 생성하는 데 많은 리소스를 사용하므로 애플리케이션 전체에서 한 번만 생성하고 공유하는 것이 일반적이다.애플리케이션 전체에서 공유: 여러 스레드에서 동시에 사용될 수 있다.생명 주기: 애플리케이션 시작 시 생성되고, 애플리케이션 종료 시 닫힌다.  엔티티 매니저 (EntityManager)정의EntityManager는 엔티티의 생명 주기(Life Cycle)를 관리하고, 데이터베이스 ..
2024.07.15
no image
[인프런 알고리즘] Chapter 2, 7번 문제(점수 계산)
이 알고리즘 문제는 인프런의 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 (김태원)의 문제입니다.문제 설명 코드import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public class Main { public static int solution(int N, String str) { int count = 0; int sum = 0; String[] input = str.split(" "); for (String s : input) { if(s.equals("1")) count += ++sum; else ..
2024.07.15
no image
[인프런 알고리즘] Chapter 2, 6번 문제(뒤집은 소수)
이 알고리즘 문제는 인프런의 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 (김태원)의 문제입니다.문제 설명 코드첫 번째 방법package inflearn_algorithm.chapter2;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public class sec02_06 { public static void solution(int N, String str) { String[] strArr = str.split(" "); int[] numArr = new int[N]; for(int i = 0; i 2) { ..
2024.07.14
no image
[인프런 알고리즘] Chapter 2, 5번 문제(소수(에라토스테네스의 체))
이 알고리즘 문제는 인프런의 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 (김태원)의 문제입니다.문제 설명 코드import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.Arrays;public class sec02_05 { public static int solution(int N) { boolean[] arr = new boolean[N + 1]; Arrays.fill(arr, true); int count = 0; for(int i = 2; i  설명for(int i = 2; i 2부터 N의 제곱근까지..
2024.07.14
no image
[인프런 알고리즘] Chapter 2, 4번 문제(피보나치 수열)
이 알고리즘 문제는 인프런의 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 (김태원)의 문제입니다.문제 설명 코드package inflearn_algorithm.chapter2;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public class sec02_04 { public static void solution(int N) { //배열 이용 Long[] arr = new Long[N]; arr[0] = 1L; arr[1] = 1L; System.out.print(arr[0] + " "); System.out.p..
2024.07.13
no image
[인프런 알고리즘] Chapter 2, 3번 문제(가위, 바위, 보)
이 알고리즘 문제는 인프런의 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 (김태원)의 문제입니다.문제 설명 코드import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringTokenizer;public class sec02_03 { public static void solution(int N, String A, String B) { StringTokenizer aSt = new StringTokenizer(A); StringTokenizer bSt = new StringTokenizer(B); int[] aAr..
2024.07.13
no image
[인프런 알고리즘] Chpater 2, 2번 문제(보이는 학생)
이 알고리즘 문제는 인프런의 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 (김태원)의 문제입니다.문제 설명 코드import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public class sec02_02 { public static int solution(int N, String str) { String[] numArr = str.split(" "); int count = 1; int previousNum = Integer.parseInt(numArr[0]); for (int i = 1; i previousNum) { ..
2024.07.12
no image
[인프런 알고리즘] Chpater 2, 1번 문제(큰 수 출력하기)
이 알고리즘 문제는 인프런의 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 (김태원)의 문제입니다.문제 설명 코드import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public class sec02_01 { public static String solution(int N, String str) { String[] numArr = str.split(" "); StringBuilder sb = new StringBuilder(); sb.append(numArr[0]).append(" "); for (int i = 1; i Intege..
2024.07.12

이 글은 인프런 김영한님의 Spring 강의를 바탕으로 개인적인 정리를 위해 작성한 글입니다.


JPA 구동 방식

엔티티 매니저 팩토리 (EntityManagerFactory)

정의

  • EntityManagerFactory는 JPA 애플리케이션에서 EntityManager 인스턴스를 생성하기 위한 팩토리이다.

 

특징

  • 비용이 많이 드는 객체: 생성하는 데 많은 리소스를 사용하므로 애플리케이션 전체에서 한 번만 생성하고 공유하는 것이 일반적이다.
  • 애플리케이션 전체에서 공유: 여러 스레드에서 동시에 사용될 수 있다.
  • 생명 주기: 애플리케이션 시작 시 생성되고, 애플리케이션 종료 시 닫힌다.

 

 

엔티티 매니저 (EntityManager)

정의

  • EntityManager는 엔티티의 생명 주기(Life Cycle)를 관리하고, 데이터베이스 작업을 수행하는 객체이다.

 

특징

  • 데이터베이스 연결 관리: 데이터베이스와의 연결을 관리하고, 쿼리 실행, 트랜잭션 관리 등의 작업을 수행한다.
  • 영속성 컨텍스트: 엔티티 인스턴스들을 관리하는 영속성 컨텍스트(Persistence Context)를 제공한다. 영속성 컨텍스트는 엔티티의 상태 변화를 추적하고 데이터베이스와 동기화한다.
  • 스레드 안전하지 않음: EntityManager는 스레드에 안전하지 않으므로 각 트랜잭션 또는 요청마다 새로운 인스턴스를 생성하여 사용해야 한다.
  • 생명 주기: 일반적으로 짧은 생명 주기를 가지며, 각 트랜잭션마다 생성되고 종료된다.

 

주요 메서드

  • persist(Object entity): 엔티티를 영속성 컨텍스트에 저장한다.
  • merge(Object entity): 준영속 상태의 엔티티를 영속성 컨텍스트로 병합한다.
  • remove(Object entity): 엔티티를 영속성 컨텍스트에서 제거한다.
  • find(Class<T> entityClass, Object primaryKey): 기본 키로 엔티티를 조회한다.
  • createQuery(String qlString): JPQL 쿼리를 생성한다.
  • getTransaction(): 현재 트랜잭션을 반환한다.

 

객체와 테이블을 생성하고 매핑하기
create table Member (
	id bigint not null,
	name varchar(255),
	primary key (id)
);​

 

package hellojpa;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Member {
    @Id
    private Long id;
    private String name;
    
    //Getter, Setter …
}

@Entity 어노테이션은 해당 클래스가 JPA 엔티티임을 명시한다.

-클래스 선언부에 @Entity 어노테이션을 추가하여 해당 클래스가 엔티티임을 정의한다.
-엔티티 클래스는 반드시 @Entity 어노테이션을 가져야 하며, public 또는 protected로 선언된 기본 생성자가 있어야 한다.
-@Entity가 붙은 클래스는 반드시 @Id로 표시된 기본 키 필드를 가져야 한다.
-클래스 이름이 기본적으로 데이터베이스 테이블 이름으로 사용되지만, @Table 어노테이션을 사용하여 테이블 이름을 명시적으로 지정할 수 있다.


@Id 어노테이션은 엔티티의 기본 키를 정의하는 데 사용된다. 

-엔티티 클래스의 필드나 메서드에 @Id 어노테이션을 추가하여 해당 필드가 기본 키임을 정의한다.
-모든 JPA 엔티티는 하나 이상의 @Id 어노테이션을 가져야 하며, 이를 통해 기본 키를 지정해야 한다.
-기본 키의 값을 자동으로 생성하기 위해 @GeneratedValue 어노테이션과 함께 사용할 수 있다. @GeneratedValue는 기본 키 생성 전략을 지정하는 데 사용된다.

 

주의 사항

-엔티티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유해야 한다.
- 엔티티 매니저는 쓰레드간에 공유를 하면 안된다. (공유를 하게되면 서비스의 장애를 일으킬 수 있다.)
- JPA의 모든 데이터 변경은 트랜잭션 안에서 실행된다.

 

영속성 컨텍스트

-"엔티티를 영구 저장하는 환경" 이라는 뜻

-EntityManager.persist(entity);

-영속성 컨텍스트는 논리적인 개념이다. 엔티티 매니저를 통해서 영속성 컨텍스트에 접근할 수 있다.

 

스프링 프레임워크 같은 컨테이너 환경에서는 엔티티 매니저와 영속성 컨텍스트가 N:1 의 관계이다.

 

엔티티의 생명주기

비영속 (Transient)

정의: 비영속 상태는 엔티티가 아직 영속성 컨텍스트에 의해 관리되지 않는 상태를 말한다.

 

특징

  • 데이터베이스와 전혀 관련이 없다.
  • 엔티티 매니저에 의해 관리되지 않는다.
  • 영속성 컨텍스트에 포함되지 않기 때문에 영속성 컨텍스트의 기능(변경 감지, 쓰기 지연 등)을 사용할 수 없다.
Member member = new Member();
member.setId(1L);
member.setName("Lee");

 

 

영속 (Persistent)

정의: 영속 상태는 엔티티가 영속성 컨텍스트에 의해 관리되는 상태를 말한다.

 

특징

  • 영속성 컨텍스트의 1차 캐시에 저장된다.
  • 트랜잭션을 커밋하거나 flush()를 호출하면 변경 사항이 데이터베이스에 반영된다.
  • 변경 감지(dirty checking) 기능이 적용되어 엔티티의 변경 사항이 자동으로 반영된다.
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

Member member = new Member();
member.setId(1L);
member.setName("Lee");
em.persist(member); // 엔티티를 영속성 컨텍스트에 저장

em.getTransaction().commit();

 

 

준영속 (Detached)

정의: 준영속 상태는 엔티티가 한 번 영속 상태였으나 현재는 영속성 컨텍스트에 의해 더 이상 관리되지 않는 상태를 말한다.

 

특징

  • 영속성 컨텍스트가 닫히거나, detach(), clear(), close() 메서드가 호출되면 엔티티가 준영속 상태로 전환된다.
  • 영속성 컨텍스트의 기능(변경 감지, 쓰기 지연 등)을 사용할 수 없다.

 

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

Member member = new Member();
member.setId(1L);
member.setName("Lee");
em.persist(member); // 엔티티를 영속성 컨텍스트에 저장
em.detach(member); // 엔티티를 준영속 상태로 전환

em.getTransaction().commit();
  • em.detach(entity) : 특정 엔티티만 준영속 상태로 전환
  • em.clear() : 영속성 컨텍스트를 완전히 초기화
  • em.close() : 영속성 컨텍스트를 종료

 

삭제 (Removed)

정의: 삭제 상태는 엔티티가 영속성 컨텍스트와 데이터베이스에서 삭제될 예정인 상태를 말한다.

 

특징

  • remove() 메서드를 호출하면 엔티티가 삭제 상태로 전환된다.
  • 트랜잭션을 커밋하면 데이터베이스에서 해당 엔티티가 삭제된다.
  • 삭제된 엔티티는 더 이상 영속성 컨텍스트에서 관리되지 않는다.
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

Member member = em.find(Member.class, 1L);
em.remove(member); // 엔티티를 삭제 상태로 전환

em.getTransaction().commit(); // 트랜잭션을 커밋하여 데이터베이스에서 삭제

 

주요 메서드

  • persist(Object entity): 엔티티를 영속성 컨텍스트에 저장한다.
  • remove(Object entity): 엔티티를 영속성 컨텍스트에서 제거한다.
  • find(Class<T> entityClass, Object primaryKey): 기본 키를 통해 엔티티를 조회한다.
  • merge(Object entity): 준영속 상태의 엔티티를 영속성 컨텍스트로 병합한다.
  • flush(): 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영한다.
  • clear(): 영속성 컨텍스트를 초기화하여 모든 엔티티를 준영속 상태로 만든다.

 

 

영속성 컨텍스트의 이점

엔티티 조회, 1차 캐시

    • 영속성 컨텍스트는 엔티티를 1차 캐시에 저장하여 관리한다.
    • 같은 엔티티를 반복 조회할 때, 데이터베이스를 다시 조회하지 않고 1차 캐시에서 가져온다. 이를 통해 성능을 최적화할 수 있다.

 

 

  • 만약 조회시 1차 캐시에 존재하지 않는다면, DB에서 데이터를 가져오고 자동으로 영속 컨텍스트에 저장한다.

 

영속 엔티티의 동일성 보장

  • 영속성 컨텍스트는 같은 트랜잭션 내에서 같은 식별자를 가진 엔티티에 대해 동일한 객체를 반환한다. 이는 엔티티의 동일성을 보장하여 일관된 데이터를 제공한다.

 

쓰기 지연(Write-behind)

  • 영속성 컨텍스트는 엔티티의 변경 내용을 즉시 데이터베이스에 반영하지 않고, 트랜잭션을 커밋하거나 flush를 호출할 때까지 지연시킨다.
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작

em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.

//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋

 

변경 감지(Dirty Checking)

  • 영속성 컨텍스트는 엔티티의 상태 변화를 감지하고, 트랜잭션이 커밋될 때 변경된 내용을 자동으로 데이터베이스에 반영한다.
  • 이는 엔티티를 수정하고 flush 또는 commit 시 자동으로 UPDATE 쿼리를 생성하여 데이터베이스에 적용한다.
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // [트랜잭션] 시작

// 영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");

// 영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);

transaction.commit(); // [트랜잭션] 커밋

  • 최초로 1차 캐시에 저장될때, 스냅샷을 미리 생성하고 나중에 현재 스냅샷과 최초 스냅샷을 비교하여 변경점이 있으면 UPDATE SQL을 생성한다.

 

플러시

  • 변경 감지
  • 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
  • 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송(등록, 수정, 삭제 쿼리)
  • 플러시(Flush)는 JPA에서 영속성 컨텍스트(Persistence Context)에 있는 변경 사항을 데이터베이스에 동기화하는 작업이다.

 

특징

  • 영속성 컨텍스트에서 관리되는 엔티티의 변경 사항(INSERT, UPDATE, DELETE)을 SQL 문으로 데이터베이스에 보낸다.
  • 트랜잭션이 커밋되기 전에 자동으로 발생하지만, 명시적으로 flush() 메서드를 호출하여 중간에 실행할 수도 있다.
  • 일시적 동기화: 플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하지만 트랜잭션을 종료하지는 않는다. 즉, 트랜잭션은 여전히 열려 있다.

 

플러시의 동작 시점

  • 트랜잭션 커밋: 트랜잭션을 커밋할 때 자동으로 플러시가 발생하여 변경 사항이 데이터베이스에 반영된다.
  • JPQL 쿼리 실행: JPQL 쿼리를 실행할 때 플러시가 발생하여 변경 사항이 쿼리 결과에 반영되도록 한다.
  • 명시적 호출: EntityManager의 flush() 메서드를 호출하여 명시적으로 플러시를 수행할 수 있다.

 

플러시 모드 옵션

em.setFlushMode(FlushModeType.COMMIT)
  • FlushModeType.AUTO : 커밋이나 쿼리(JPQL)를 실행할 때 플러시 (기본값)
  • FlushModeType.COMMIT : 커밋할 때만 플러시(JPQL을 작성할 때도 플러시 되지 않음)

 

주의 사항

  • 플러시는 영속성 컨텍스트를 비우지 않는다.
  • 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화한다.

이 알고리즘 문제는 인프런의 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 (김태원)의 문제입니다.


문제 설명

 

코드

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

public class Main {
    public static int solution(int N, String str) {
        int count = 0; int sum = 0;
        String[] input = str.split(" ");
        for (String s : input) {
            if(s.equals("1")) count += ++sum;
            else sum = 0;
        }
        return count;
    }

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

 

설명

  • str 문자열을 공백을 기준으로 분할하여 문자열 배열 input에 저장한다.
  • input 배열의 각 요소를 순회하며 처리한다.
  • 만약 현재 문자열이 “1”이면 sum을 1 증가시킨 후 (++sum), countsum을 더한다.
  • 만약 현재 문자열이 “1”이 아니면 sum을 0으로 초기화한다.

이 알고리즘 문제는 인프런의 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 (김태원)의 문제입니다.


문제 설명

 

코드

첫 번째 방법

package inflearn_algorithm.chapter2;

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

public class sec02_06 {
    public static void solution(int N, String str) {
        String[] strArr = str.split(" ");
        int[] numArr = new int[N];

        for(int i = 0; i < N; ++i)
        {
            StringBuilder sb = new StringBuilder();
            numArr[i] = Integer.parseInt(
                    sb.append(strArr[i])
                            .reverse()
                            .toString());
        }

        for(int i = 0; i < N; ++i)
        {
            if(numArr[i] == 2) System.out.print(2 + " ");
            else if(numArr[i] > 2)
            {
                boolean flag = true;
                for(int j = 2; j < numArr[i]; ++j){
                    if(flag && numArr[i] % j == 0){
                        flag = false;
                        break;
                    }
                }
                if(flag) System.out.print(numArr[i] + " ");
            }
        }

    }

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

 

두 번째 방법(첫 번째 방법 성능 개선)

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

public class sec02_06 {
    public static void solution(int N, String str) {
        String[] strArr = str.split(" ");
        int[] numArr = new int[N];

        for (int i = 0; i < N; ++i)
        {
            StringBuilder sb = new StringBuilder(strArr[i]);
            numArr[i] = Integer.parseInt(sb.reverse().toString());
        }

        for (int num : numArr)
        {
            if (isPrime(num)) System.out.print(num + " ");
        }
    }

    public static boolean isPrime(int num) {
        if (num <= 1) return false;
        if (num == 2) return true;
        if (num % 2 == 0) return false;
        for (int i = 3; i <= Math.sqrt(num); i += 2)
        {
            if (num % i == 0) return false;
        }
        return true;
    }

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

 

설명(두 번째 방법)

  • √num  이상을 검사할 필요가 없는 이유는 그 이상의 약수는 이미  √num 이하의 약수와 쌍을 이루고 있기 때문이다.
  • 예를 들어,  num = 36 인 경우,  √36 = 6 이다. 36의 약수는 (1, 36), (2, 18), (3, 12), (4, 9), (6, 6)으로, 6을 넘는 약수들은 모두 6 이하의 약수와 쌍을 이룬다.
  • 따라서,  √num 까지만 약수를 검사하면 모든 약수 쌍을 확인한 셈이 되어 소수 판별이 가능하다.

이 알고리즘 문제는 인프런의 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 (김태원)의 문제입니다.


문제 설명

 

코드

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

public class sec02_05 {
    public static int solution(int N) {
        boolean[] arr = new boolean[N + 1];
        Arrays.fill(arr, true);

        int count = 0;
        for(int i = 2; i <= Math.sqrt(N); ++i){
            if(arr[i]){
               for(int j = i * i; j <= N; j += i) arr[j] = false;
            }
        }

        for(int i = 2; i <= N; ++i) if(arr[i]) ++count;
        return count;
    }

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

 

설명

for(int i = 2; i <= Math.sqrt(N); ++i){
    if(arr[i]){
        for(int j = i * i; j <= N; j += i) arr[j] = false;
    }
}
  • 2부터 N의 제곱근까지 반복문을 실행한다. 이 범위 내의 숫자들로 모든 배수를 체크하면 충분하기 때문이다.
  • i가 소수(arr[i]가 true)인 경우, i의 배수들을 모두 소수가 아니라고 표시한다(false로 설정).
  • i * i부터 N까지 i의 배수들을 false로 설정한다. i 이전의 배수들은 이미 처리되었기 때문이다.

 

https://www.youtube.com/watch?v=9rLFFKmKzno&ab_channel=%ED%95%9C%EB%B9%9B%EB%AF%B8%EB%94%94%EC%96%B4

 

이 알고리즘 문제는 인프런의 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 (김태원)의 문제입니다.


문제 설명

 

코드

package inflearn_algorithm.chapter2;

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

public class sec02_04 {
    public static void solution(int N) { //배열 이용
        Long[] arr = new Long[N];
        arr[0] = 1L;
        arr[1] = 1L;
        System.out.print(arr[0] + " ");
        System.out.print(arr[1] + " ");
        for(int i = 2; i < N; ++i)
        {
            arr[i] = arr[i - 2] + arr[i - 1];
            System.out.print(arr[i] + " ");
        }
    }

    public static void solution(Long N) { //배열 이용 X
        Long p = 1L, n = 1L;
        System.out.print(p + " " + n +" ");
        for(int i = 2; i < N; ++i)
        {
            Long c = p + n;
            System.out.print(c + " ");
            p = n;
            n = c;
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        solution(Integer.parseInt(br.readLine())); //배열을 이용할 때
        solution(Long.parseLong(br.readLine())); //배열을 이용하지 않을 때
    }
}

 

설명

  • 반복문은 N-2번 반복되므로 O(N-2) = O(N)의 시간 복잡도를 가진다.
  • 각 반복에서 덧셈과 배열 접근 작업을 수행하므로 반복문의 전체 시간 복잡도는 O(N)이다.

이 알고리즘 문제는 인프런의 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 (김태원)의 문제입니다.


문제 설명

 

코드

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

public class sec02_03 {
    public static void solution(int N, String A, String B) {
        StringTokenizer aSt = new StringTokenizer(A);
        StringTokenizer bSt = new StringTokenizer(B);
        int[] aArr = new int[N];
        int[] bArr = new int[N];

        for(int i = 0; i < N; ++i){
            aArr[i] = Integer.parseInt(aSt.nextToken());
            bArr[i] = Integer.parseInt(bSt.nextToken());
            if(aArr[i] == bArr[i]) System.out.println("D");
            else if
            (
                (aArr[i] == 1 && bArr[i] == 3) ||
                (aArr[i] == 2 && bArr[i] == 1) ||
                (aArr[i] == 3 && bArr[i] == 2)
            ) System.out.println("A");
            else System.out.println("B");
        }
    }

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

 

설명

  • 두 플레이어의 선택이 같으면 “D”를 출력하여 무승부임을 나타낸다.
  • 첫 번째 플레이어가 이기는 경우
     첫 번째 플레이어가 가위(1)이고 두 번째 플레이어가 보(3)일 때
    첫 번째 플레이어가 바위(2)이고 두 번째 플레이어가 가위(1)일 때 
    첫 번째 플레이어가 보(3)이고 두 번째 플레이어가 바위(2)일 때
  • 이외의 경우는 두 번째 플레이어가 이긴다.

이 알고리즘 문제는 인프런의 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 (김태원)의 문제입니다.


문제 설명

 

코드

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

public class sec02_02 {
    public static int solution(int N, String str) {
        String[] numArr = str.split(" ");
        int count = 1;
        int previousNum = Integer.parseInt(numArr[0]);

        for (int i = 1; i < N; ++i)
        {
            int currentNum = Integer.parseInt(numArr[i]);
            if (currentNum > previousNum) {
                ++count;
                previousNum = currentNum;
            }
        }
        return count;
    }

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

 

설명

  • String.split(" ")을 사용하여 입력 문자열을 배열로 변환한다.
  • 첫 번째 숫자는 무조건 포함되므로 count를 1로 초기화한다.
  • 반복문을 돌면서 이전 숫자보다 큰 경우에만 count를 증가시킨다.
  • previousNum 변수를 업데이트하여 다음 비교에 사용한다.

이 알고리즘 문제는 인프런의 자바(Java) 알고리즘 문제풀이 입문: 코딩테스트 대비 (김태원)의 문제입니다.


문제 설명

 

코드

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

public class sec02_01 {
    public static String solution(int N, String str) {
        String[] numArr = str.split(" ");
        StringBuilder sb = new StringBuilder();

        sb.append(numArr[0]).append(" ");
        for (int i = 1; i < N; i++)
        {
            if (Integer.parseInt(numArr[i]) > Integer.parseInt(numArr[i - 1]))
            {
                sb.append(numArr[i]).append(" ");
            }
        }

        return sb.toString().trim();
    }

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

 

설명

  • String.split(" ")을 사용하여 입력 문자열을 배열로 변환한다.
  • 첫 번째 숫자는 무조건 결과에 포함되므로 StringBuilder에 미리 추가한다.
  • 두 번째 숫자부터 반복문을 돌면서 앞의 숫자보다 큰 경우에만 StringBuilder에 추가한다.
  • 마지막에 trim()을 호출하여 불필요한 공백을 제거한다.