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

public class Main {

    static class Meeting implements Comparable<Meeting> {
        int start, end, people;

        Meeting(int start, int end, int people) {
            this.start = start;
            this.end = end;
            this.people = people;
        }

        @Override
        public int compareTo(Meeting o) {
            return this.end - o.end; // 종료 시간 기준 정렬
        }
    }

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

        Meeting[] meetings = new Meeting[n];
        for (int i = 0; i < n; i++) {
            StringTokenizer st = new StringTokenizer(bf.readLine());
            int start = Integer.parseInt(st.nextToken());
            int end = Integer.parseInt(st.nextToken());
            int people = Integer.parseInt(st.nextToken());
            meetings[i] = new Meeting(start, end, people);
        }

        // 종료 시간 기준 정렬
        Arrays.sort(meetings);

        // DP 배열 및 종료 시간 배열
        int[] dp = new int[n];
        int[] endTimes = new int[n];

        for (int i = 0; i < n; i++) {
            endTimes[i] = meetings[i].end; // 종료 시간만 저장
        }

        dp[0] = meetings[0].people; // 첫 회의 인원 초기화

        for (int i = 1; i < n; i++) {
            // 현재 회의 인원
            dp[i] = meetings[i].people;

            // 이전 회의 중 겹치지 않는 가장 마지막 회의 찾기 (이분 탐색)
            int idx = binarySearch(endTimes, meetings[i].start);
            if (idx != -1) {
                dp[i] += dp[idx];
            }

            // 이전 최대값과 비교
            dp[i] = Math.max(dp[i], dp[i - 1]);
        }

        System.out.println(dp[n - 1]);
    }

    // 이분 탐색: 종료 시간이 target 이하인 가장 마지막 인덱스를 찾음
    private static int binarySearch(int[] endTimes, int target) {
        int left = 0, right = endTimes.length - 1;
        int result = -1;

        while (left <= right) {
            int mid = (left + right) / 2;
            if (endTimes[mid] <= target) {
                result = mid; // 가능한 인덱스 갱신
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return result;
    }
}

1. 자바의 메모리 구조

메서드 영역

메서드 영역은 프로그램을 실행하는데 필요한 공통 데이터를 관리한다. 이 영역은 프로그램의 모든 영역에서 공유한다.

  • 클래스 정보: 클래스의 실행코드(바이트 코드), 필드, 메서드와 생성자 코드 등 모든 실행 코드가 존재한다.
  • static 영역: static 변수들을 보관한다.
  • 런타임 상수 풀: 프로그램을 실행하는데 필요한 공통 리터럴 상수를 보관한다.

스택 영역

스택 영역은 자바 실행 시 생성이 되는데, 스레드 1개당 하나의 스택이 생성된다. 그리고 메소드가 호출될 때마다 스택 영역에는 스택 프레임이 하나씩 쌓이게 된다.

  • 스택 프레임: 지역 변수(매개변수 포함), 중간 연산 결과, 메소드 호출 정보 등을 포함한다.
    - Local Variables: 메소드의 지역 변수들을 갖는다.
    - Operand Stack: 메소드 내 계산을 위한 작업 공간이다.
    - Constant Pool Reference: 런타임 상수 풀의 참조를 갖는다.

힙 영역

힙 영역은 인스턴스와 배열이 생성되는 곳이다. 가비지 컬렉션(GC)이 주로 이루어지며 더 이상 참조되지 않는 객체는 GC에 의해 청소된다. 쓱싹.


👶 인스턴스는 내부에 변수와 메서드를 가지고 있는데, 그럼 각각의 인스턴스의 메서드는 인스턴스가 생성될 때마다 인스턴스 영역에 들어가게 되는지,,?
👩🏻‍💻 인스턴스들의 필드 값은 모두 다른 주소를 가져야겠지만, 메소드의 코드는 모두 동일합니다. 따라서 메서드는 메서드 영역에서 공통으로 관리됩니다. 즉, 인스턴스의 메서드를 호출하면 힙영역이 아닌 메서드 영역에 있는 코드가 호출이 됩니다.


2. Static 변수 (정적 변수)

static 키워드가 붙는 변수는 모두 메서드 영역(스태틱 영역)에서 관리가 된다. 즉, 인스턴스 영역에 생성되지 않는 것이다.


위와 같이 인스턴스와 함께 생성이 되지 않기 때문에 현재까지 인스턴스를 몇 개를 만들었는지 확인하는 static int count 변수가 사용 가능하다. 즉, 스태틱 변수는 클래스 하나당 하나만 생성이 되며 인스턴스 변수는 인스턴스의 수만큼 생성이 된다.

변수와 생명주기

  • 지역 변수(매개변수 포함): 스택 영역의 스택 프레임에 저장되며 메서드가 종료되면 프레임이 제거됨과 동시에 제거된다.
  • 인스턴스 변수: 힙 영역에 저장되며 인스턴스가 개발자에 의해 제거되거나 GC가 발생하기 전까지 생존한다.
  • 클래스 변수(스태틱 변수, 정적 변수): 메서드 영역의 static 영역에 저장되며 JVM 로딩과 함께 생성되며 JVM이 종료되면 함께 생명이 끝난다.

Static 변수 접근법

1. 인스턴스를 통해 접근

Data data = new Data();
data.count++;

2. 클래스를 통한 접근

Data.count++;

스태틱 변수는 클래스 변수라고 불리는 만큼 클래스를 통해 접근하는 것이 가독성이 훨씬 좋다. 인스턴스 변수에 접근하는 것처럼 보이는 것 보다 한눈에 명확히 클래스 변수에 접근하는 것처럼 보이는 것이 더욱 명확하기 때문이다.

3. Static 메서드 (정적 메서드)

Static 메서드는 정적 변수와 마찬가지로 스태틱 영역에서 관리된다. 따라서 마찬가지로 인스턴스 생성 없이 클래스 명을 통해 호출이 가능하다.

public class Math() {

	public static int add(int a, int b) {
    	return a+b;
    }
    
    public static int subtract(int a, int b) {
    	return a-b;
    }
}

위와 같은 유틸리티 클래스(Utility Class, 정적 메서드만 존재하는 클래스)에서 이러한 접근법은 유용하게 쓰인다.

정적 메서드 접근법

1. 인스턴스를 통해 접근

Math math = new Math();
math.sum(1, 2);

2. 클래스명을 통해 접근

Math.sum(1, 2);

3. static import를 통해 접근 (정적 변수도 import 가능)

import static 패키지명.Math.*;

sum(1, 2);

정적 메서드 사용 시 주의할 점

static 메서드는 static 만 사용 할 수 있다.


생각해보면 당연하다. 정적 메서드는 참조값이 없다. 그런데 인스턴스 변수나 메서드를 사용하려면 참조값을 알아야한다. 따라서 정적 메서드에서 인스턴스 변수나 메서드를 불러오면 자바는 어느 주소를 찾아가야 하는지 알 수 없게 되고(참조값 부재), 컴파일 에러가 뜨게 된다.


4. main() 메서드

인스턴스 생성 없이 사용하는 메서드의 가장 대표적인 예는 main() 메서드이다. 따라서 main에서 호출할 메서드 또한 모두 static 이어야 한다. 변수 또한 마찬가지다.

정적 변수를 작성해서 에러가 나는 경우

public class Math() {
	public int count;
    
    public static void main(String[] args) {
    	count++;
    }
}

정적 메서드를 사용해서 에러가 나는 경우

public class Math() {

    public static void main(String[] args) {
    	test();
    }
    
    public void test() {
    	System.out.println("test!");
    }
}

문제 캡처

 

소스 코드

import java.io.*;
import java.util.*;
import java.util.Map.Entry;

public class Main {

    static Comparator<Integer> comparator(Map<Integer, Integer> map) {
        return (key1, key2) -> {
            int value1 = map.get(key1), value2 = map.get(key2);
            if(value1 == value2) {
                return key1 - key2;
            }
            return value1 - value2;
        };
    };

    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(bf.readLine());
        int r = Integer.parseInt(st.nextToken())-1,
        c = Integer.parseInt(st.nextToken())-1,
        k = Integer.parseInt(st.nextToken());

        int[][] arr = new int[101][101];

        for(int i=0;i<3;i++) {
            st = new StringTokenizer(bf.readLine());
            for(int j=0;j<3;j++) {
                arr[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        int time = 0;
        int rowCnt = 3, colCnt = 3;
        while(arr[r][c] != k && time <= 100) {
            time++;
            if(rowCnt >= colCnt) {
                int col = colCnt;
                //R연산
                for(int i=0;i<rowCnt;i++) {
                    Map<Integer, Integer> freqMap = new HashMap<>();
                    //행 연산 실행
                    for(int j=0;j<colCnt;j++) {
                        if(arr[i][j] == 0) continue;
                        freqMap.put(arr[i][j], freqMap.getOrDefault(arr[i][j], 0)+1);
                    }
                    TreeMap<Integer, Integer> sortMap = new TreeMap<>(comparator(freqMap));
                    sortMap.putAll(freqMap);
                    int nowColCnt = sortMap.size()*2;
                    for(int j=0;j<nowColCnt;j+=2) {
                        Entry<Integer, Integer> value = sortMap.pollFirstEntry();
                        arr[i][j] = value.getKey();
                        arr[i][j+1] = value.getValue();
                    }
                    for(int j=nowColCnt;j<colCnt;j++) {
                        arr[i][j] = 0;
                    }
                    col = Math.max(col, nowColCnt);
                }
                colCnt = col;
            } else {
                int row = rowCnt;
                //C연산
                for(int j=0;j<colCnt;j++) {
                    Map<Integer, Integer> freqMap = new HashMap<>();
                    //열 연산 실행
                    for(int i=0;i<rowCnt;i++) {
                        if(arr[i][j] == 0) continue;
                        freqMap.put(arr[i][j], freqMap.getOrDefault(arr[i][j], 0)+1);
                    }
                    TreeMap<Integer, Integer> sortMap = new TreeMap<>(comparator(freqMap));
                    sortMap.putAll(freqMap);
                    int nowRowCnt = sortMap.size()*2;
                    for(int i=0;i<nowRowCnt;i+=2) {
                        Entry<Integer, Integer> value = sortMap.pollFirstEntry();
                        arr[i][j] = value.getKey();
                        arr[i+1][j] = value.getValue();
                    }
                    for(int i=nowRowCnt;i<rowCnt;i++) {
                        arr[i][j] = 0;
                    }
                    row = Math.max(row, nowRowCnt);
                }
                rowCnt = row;
            }
        }
        
        System.out.println(time>100 ? -1 : time);

    }
}

문제 캡처

 

소스 코드

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

public class Main {
    static class Loc {
        int r, c;
        
        Loc(int r, int c) {
            this.r = r;
            this.c = c;
        }
    }
    static List<Loc> viruses = new ArrayList<>();
    static int N, M, dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1}, arr[][];
    static boolean[][] visited;
    static int minTime = Integer.MAX_VALUE;
    static int emptyCount = 0;

    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(bf.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());

        arr = new int[N][N];
        for(int i=0;i<N;i++) {
            st = new StringTokenizer(bf.readLine());
            for(int j=0;j<N;j++) {
                arr[i][j] = Integer.parseInt(st.nextToken());
                if(arr[i][j] == 2) {
                    viruses.add(new Loc(i, j));
                } else if(arr[i][j] == 0) {
                    emptyCount++;
                }
            }
        }

        activateVirus(-1, 0, new int[M]);
        System.out.println(minTime == Integer.MAX_VALUE ? -1 : minTime);
    }

    private static void activateVirus(int index, int cnt, int[] selected) {
        if(cnt == M) {
            getTime(selected);
            return;
        }

        for(int i=index+1;i<viruses.size();i++) {
            selected[cnt] = i;
            activateVirus(i, cnt+1, selected);
        }
    }

    private static void getTime(int[] selected) {
        Queue<Loc> queue = new ArrayDeque<>();
        visited = new boolean[N][N];
        int[][] times = new int[N][N];
        int infected = 0;
        int maxTime = 0;

        // 선택된 바이러스 위치 큐에 넣기
        for(int i : selected) {
            Loc virus = viruses.get(i);
            queue.offer(virus);
            visited[virus.r][virus.c] = true;
        }

        while(!queue.isEmpty()) {
            Loc cur = queue.poll();
            
            for(int d=0;d<4;d++) {
                int nx = cur.r + dx[d];
                int ny = cur.c + dy[d];
                
                if(isInRange(nx, ny) && !visited[nx][ny] && arr[nx][ny] != 1) {
                    visited[nx][ny] = true;
                    times[nx][ny] = times[cur.r][cur.c] + 1;
                    queue.offer(new Loc(nx, ny));
                    
                    if(arr[nx][ny] == 0) {
                        infected++;
                        maxTime = Math.max(maxTime, times[nx][ny]);
                    }
                }
            }
        }

        // 모든 빈 칸이 감염되었는지 확인
        if(infected == emptyCount) {
            minTime = Math.min(minTime, maxTime);
        }
    }

    private static boolean isInRange(int i, int j) {
        return 0 <= i && i < N && 0 <= j && j < N;
    }
}

'Algorithm' 카테고리의 다른 글

Boj_ 회의실 배정 4 java  (1) 2024.11.11
[boj] 이차원 배열과 연산17140 JAVA  (0) 2024.10.27
[boj] Cryptographer’s Conundrum_11269 C++  (0) 2024.10.14
[boj] 양치기꿍_3187 JAVA  (1) 2024.10.07
[boj] 좋은수열_2661 JAVA  (0) 2024.09.30

문제 캡처

소스 코드

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s;
    cin >> s;
    
    int count = 0;
    for (size_t i = 0; i < s.size(); i += 3) {
        string chunk = s.substr(i, 3);
        string target = "PER";
        for (int j = 0; j < 3; ++j) {
            if (chunk[j] != target[j]) {
                ++count;
            }
        }
    }

    cout << count << endl;
    return 0;
}

Comment…💭

'Algorithm' 카테고리의 다른 글

[boj] 이차원 배열과 연산17140 JAVA  (0) 2024.10.27
[boj] 연구소 3_17142 JAVA  (0) 2024.10.21
[boj] 양치기꿍_3187 JAVA  (1) 2024.10.07
[boj] 좋은수열_2661 JAVA  (0) 2024.09.30
[boj] 사냥꾼_8983JAVA  (0) 2024.09.22

문제 캡처

 

소스 코드

package baekjoon;

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

public class 양치기꿍_3187 {
    static char[][] map;
    static boolean[][] visited;
    static int R, C, vCnt, kCnt, dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
    static class Loc {
        int x, y;

        Loc(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    static Queue<Loc> queue;
    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(bf.readLine());
        R = Integer.parseInt(st.nextToken()); C = Integer.parseInt(st.nextToken());
        map = new char[R][C]; visited = new boolean[R][C];

        for(int i=0;i<R;i++) {
            map[i] = bf.readLine().toCharArray();
        }

        int vAns = 0, kAns = 0;

        for(int i=0;i<R;i++) {
            for(int j=0;j<C;j++) {
                if(!visited[i][j] && map[i][j] != '#') {
                    visited[i][j] = true;
                    vCnt = 0; kCnt = 0;
                    if(map[i][j] == 'v') vCnt++;
                    if(map[i][j] == 'k') kCnt++;

                    queue = new ArrayDeque<>();
                    queue.offer(new Loc(i, j));

                    while(!queue.isEmpty()) {
                        Loc loc = queue.poll();
                        for(int idx = 0; idx < 4; idx++) {
                            int x = loc.x + dx[idx], y = loc.y + dy[idx];
                            if(!isInRange(x, y)) continue;
                            if(!visited[x][y]) {
                                visited[x][y] = true;
                                if(map[x][y] == '#') continue;
                                queue.offer(new Loc(x, y));
                                if(map[x][y] == 'v') vCnt++;
                                if(map[x][y] == 'k') kCnt++;
                            }
                        }
                    }
                    
                    if(kCnt > vCnt) {
                        kAns += kCnt;
                    } else {
                        vAns += vCnt;
                    }
                }
            }
        }
        System.out.println(kAns+" "+vAns);
    }
    static boolean isInRange(int x, int y) {
        return 0 <= x && x < R && 0 <= y && y < C;
    }

}

Comment…💭

  • bfs만 돌리면 된다!
  • 좀만 수정하면 코드길이와 메모리를 줄일 수 있을 것 같지만 시간이없다!

'Algorithm' 카테고리의 다른 글

[boj] 연구소 3_17142 JAVA  (0) 2024.10.21
[boj] Cryptographer’s Conundrum_11269 C++  (0) 2024.10.14
[boj] 좋은수열_2661 JAVA  (0) 2024.09.30
[boj] 사냥꾼_8983JAVA  (0) 2024.09.22
[boj] 최소 편집_15483JAVA  (0) 2024.09.16

문제는 이러하다.

 

먼저, 수열은 1, 2, 3만 사용하므로 배열 list에 이를 저장한다.

답은 무조건 9보다 작기 때문에 answer을 9 로 설정해놓는다!

 

DFS를 돌면서, 현재 수열에서 마지막 두 개의 인접한 부분 수열을 비교하고

 

만약 인접한 부분 수열이 동일하면 해당 수열은 나쁜 수열로 간주,

그렇지 않으면 탐색을 계속 진행하여 수열을 확장하기!

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.*;
import java.util.*;
 
 
public class Main {
 
    static int n;
    static String[] list = {"1", "2", "3"};
    static String answer = "9";
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(br.readLine());
 
 
        dfs(0, "");
 
        System.out.println(answer);
    }
 
    private static void dfs(int index, String origin) {
        if (index == n) {
            System.out.println(origin);
            System.exit(0);
        }
 
        for (int i = 0; i <= 2; i++) {
            if (check(origin+list[i])) {
                dfs(index + 1, origin + list[i]);
            }
        }
    }
 
    private static boolean check(String checkStr) {
        int length = checkStr.length() / 2;
 
        for (int i = 1; i <= length; i++) {
            if (checkStr.substring(checkStr.length() - i).equals(checkStr.substring(checkStr.length() - 2 * i, checkStr.length() - i))) {
                return false;
            }
        }
 
        return true;
    }
}

 

 

문제는 다음과 같다.

 

 

이 문제에서는 거리를 맨해튼거리로 계산하기 때문에 조금 더 난이도가 쉬운편!

각 플랫폼에서 맨해튼거리로 L 보다 같거나 작은 거리 내 동물들을 다 잡을 수 있다고 가정했을 때

잡을 수 있는 모든 동물의 수를 구하는 문제이다!

 

플랫폼의 수를 M,  동물의 수를 N, 거리를 L이라고 둔다.

 

플랫폼의 y좌표는 어짜피 0이므로, 플랫폼의 x좌표를 저장할 배열을 만들어준다. 값을 입력받고 오름차순 정렬해준다.

Long[] plate = new Long[M];
...
Arrays.sort(plate);

 

이렇게 된다면 plate[0] 에는 x축에 가장 가까운 사대가, plate[plate.length-1]에는 x축에서 가장 먼 사대가 되는 것이다.

 

동물의 x, y좌표를 입력받으면서

 

plate를 기준으로 start값과 end 값을 잡아준다.

가장 초기에는 start는 0, end는 plate.length-1로 둔다.

mid값은 (start + end)/2 이다.

 

이분탐색을 돌며 plate[mid]에서 해당 동물의 거리를 구하고, 그 값을 기준으로

1. L과 같거나 작으면 답을 추가한다.

2. L보다 크다면 ...

// 모든 사대는 y의 값이 0이다. 따라서 맨해튼 거리를 구할 때 mid값이 바뀌어도 x좌표끼리의 값만 바뀌지, y 값은 항상 일정하다.

    2-1. plate[mid] - x가 0보다 크다면, L과 같거나 작게 만드려면 plate[mid] 의 값이 줄어들어야된다. 따라서 mid값을 줄이기 위해 end값을 mid - 1 로 바꾼다.

    2-2. plate[mid] - x가 0보다 작다면, plate[mid] 값은 항상 양수기때문에 값이 커져야된다. 따라서 start값을 mid + 1로 바꾼다.

 

이렇게 이분탐색을 시행하면 문제가 풀린다!

이분탐색을 들어가기 전

동물의 y값이 L보다 이미 큰 상태라면 -> 모든 동물이 다 포함될 수 없으므로 이분탐색 하지말고 바로넘긴다!

이거까지 하면 실행속도가 더 줄어든다.

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

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(bf.readLine());
        int M = Integer.parseInt(st.nextToken()),
        N = Integer.parseInt(st.nextToken()),
        L = Integer.parseInt(st.nextToken());

        Long[] plate = new Long[M];
        st = new StringTokenizer(bf.readLine());
        for(int i=0;i<M;i++) {
            plate[i] = Long.parseLong(st.nextToken());
        }
        Arrays.sort(plate);

        int ans = 0;
        for(int i=0;i<N;i++) {
            st = new StringTokenizer(bf.readLine());
            Long x = Long.parseLong(st.nextToken()), y = Long.parseLong(st.nextToken());
            int start = 0, end = M-1;
            if(y > L) continue;
            while(start <= end) {
                int mid = (start+end)/2;
                Long target = plate[mid] - x;
                Long distance = Math.abs(target) + y;

                if(distance <= L) {
                    ans++;
                    break;
                } else if(target > 0) {
                    end = mid - 1;
                } else {
                    start = mid + 1;
                }
            }

        }

        System.out.println(ans);

    }
}

+ Recent posts