Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions BOJ/[1536] 개근상/asever0318/Main_1563.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
static int N;
static final int D = 1000000;
static int[][][] attend;

public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
attend = new int[N+1][2][3]; // [일][지각][결석]

attendance();
System.out.println((attend[N][0][0] + attend[N][0][1] + attend[N][0][2] + attend[N][1][0] + attend[N][1][1] + attend[N][1][2]) % D);
}

static void attendance(){

attend[1][0][0] = 1;
attend[1][0][1] = 1;
attend[1][1][0] = 1;

for(int i = 2; i <= N; i++){
// 1. i일까지 지각을 안한 경우
// i번째 날에 지각 0, 결석 0일일 경우
attend[i][0][0] = (attend[i-1][0][0] + attend[i-1][0][1] + attend[i-1][0][2]) % D;
attend[i][0][1] = attend[i-1][0][0] % D; // i번째 날에 결석을 연속 1번 하려면 전날에는 결석을 했으면 안됨
attend[i][0][2] = attend[i-1][0][1] % D; // i번째 날에 결석을 연속 2번 하려면 전날에 결석을 연속 1번 했어야 함

// 2. i일까지 지각을 1번 한 경우
attend[i][1][0] = (attend[i-1][0][0] + attend[i-1][0][1] + attend[i-1][0][2] + attend[i-1][1][0] + attend[i-1][1][1] + attend[i-1][1][2]) % D;
attend[i][1][1] = attend[i-1][1][0] % D; // 지각과 결석을 동시에 못함주의 -> 결석만 고려
attend[i][1][2] = attend[i-1][1][1] % D;
}
}
}
// 개근상 받을 수 없는 사람 : 1. 지각 2번 이상, 2. 결석 연속 세 번이상
// result => 개근상을 받을 수 있는 출결정보의 개수
35 changes: 35 additions & 0 deletions BOJ/[1536] 개근상/asever0318/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# [1563] 개근상

## :pushpin: **Algorithm**

DP

## :round_pushpin: **Logic**
```java
static void attendance(){

attend[1][0][0] = 1;
attend[1][0][1] = 1;
attend[1][1][0] = 1;

for(int i = 2; i <= N; i++){
// 1. i일까지 지각을 안한 경우
// i번째 날에 지각 0, 결석 0일일 경우
attend[i][0][0] = (attend[i-1][0][0] + attend[i-1][0][1] + attend[i-1][0][2]) % D;
attend[i][0][1] = attend[i-1][0][0] % D; // i번째 날에 결석을 연속 1번 하려면 전날에는 결석을 했으면 안됨
attend[i][0][2] = attend[i-1][0][1] % D; // i번째 날에 결석을 연속 2번 하려면 전날에 결석을 연속 1번 했어야 함

// 2. i일까지 지각을 1번 한 경우
attend[i][1][0] = (attend[i-1][0][0] + attend[i-1][0][1] + attend[i-1][0][2] + attend[i-1][1][0] + attend[i-1][1][1] + attend[i-1][1][2]) % D;
attend[i][1][1] = attend[i-1][1][0] % D; // 지각과 결석을 동시에 못함주의 -> 결석만 고려
attend[i][1][2] = attend[i-1][1][1] % D;
}
}
```
- 일, 지각, 결석 세 가지를 고려해야 되기 때문에 3차원 배열로 선언해주었다.
- 지각을 기준으로 i일까지 지각을 안한 경우 / i일까지 지각을 1번한 경우로 나누어 각 경우의 수 6가지를 저장해준다.

## :black_nib: **Review**
- 경우의 수 구해서 풀려고 했는데 DP문제였다. 슬프다. 어렵다.
- 3차원 DP는 오랜만에 풀어봤다. 다음엔 반드시..
- 근데 마지막 N번째 값을 모두 더 할 때 처음에 함수로 빼서 작성했는데 계속 틀려서 함수를 없애고 print문에 바로 더해서 구했더니 통과했다 왜지..! 더 알아봐야겠다..
76 changes: 76 additions & 0 deletions BOJ/[15565] 귀여운 라이언/asever0318/Main_15565.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package BOJ;

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

public class Main_15565 {
static int N, K;
static int[] doll;

public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] str = br.readLine().split(" ");
N = Integer.parseInt(str[0]);
K = Integer.parseInt(str[1]);

StringTokenizer st = new StringTokenizer(br.readLine());
doll = new int[N];

int i = 0;
while(st.hasMoreTokens()) {
doll[i] = Integer.parseInt(st.nextToken());
i++;
}

System.out.println(getRyanCount());
}

static int getRyanCount() {
int count = 0;
int ryan = 0;
int min = Integer.MAX_VALUE;
int left = 0;
int right = 0;

// 첫 요소가 2라면 처음 1이 나오는 위치까지 이동
if(doll[right] == 2) {
while(true) {
right++;
if(right >= N || doll[right] == 1) {
left = right;
break;
}
}
}

// 1이 나오는 위치부터 진행
while(left < N && right < N) {
count++;
if(doll[right] == 1) { // 만약 1을 만나면 라이언 추가
ryan++;

if(ryan == K) { // 만약 라이언이 K개만큼 포함되어 있다면
min = Math.min(min, count); // min값 갱신 후

while(true) { // left좌표를 다음 1이 나오는 위치로 옮겨주기
left++;
count--; // 이동하는 만큼 count에서도 제거
if(left >= N || doll[left] == 1) {
break;
}
}
ryan--; // 다음 좌표로 옮겼기 때문에 라이언 수는 -1
}
}
right++;
}

if(min == Integer.MAX_VALUE) { // min값에 변화가 없으면 K개 이상의 연속된 집합을 못찾은 것
min = -1;
}

return min;
}
}
56 changes: 56 additions & 0 deletions BOJ/[15565] 귀여운 라이언/asever0318/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# [15565] 귀여운 라이언

## :pushpin: **Algorithm**

투포인터

## :round_pushpin: **Logic**
```java
static int getRyanCount() {
[...]

// 첫 요소가 2라면 처음 1이 나오는 위치까지 이동
if(doll[right] == 2) {
while(true) {
right++;
if(right >= N || doll[right] == 1) {
left = right;
break;
}
}
}

// 1이 나오는 위치부터 진행
while(left < N && right < N) {
count++;
if(doll[right] == 1) { // 만약 1을 만나면 라이언 추가
ryan++;

if(ryan == K) { // 만약 라이언이 K개만큼 포함되어 있다면
min = Math.min(min, count); // min값 갱신 후

while(true) { // left좌표를 다음 1이 나오는 위치로 옮겨주기
left++;
count--; // 이동하는 만큼 count에서도 제거
if(left >= N || doll[left] == 1) {
break;
}
}
ryan--; // 다음 좌표로 옮겼기 때문에 라이언 수는 -1
}
}
right++;
}

if(min == Integer.MAX_VALUE) { // min값에 변화가 없으면 K개 이상의 연속된 집합을 못찾은 것
min = -1;
}

return min;
}
```
- 최소 길이를 찾는 것이기 때문에 가장 처음 1이 나오는 위치까지 먼저 이동 후 진행한다.
- 라이언의 개수가 K개가 되면 min값을 갱신하고 left 좌표를 다음 라이언이 있는 곳으로 이동 시킨 후 반복한다.

## :black_nib: **Review**
- 문제를 보고 바로 투포인터로 풀어야겠다고 생각이 들었다. 생각보다 빨리 풀 수 있었다. 쉬운 문제지만 투포인터 문제에 익숙해진 거 같아서 기분이 좋다!
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기분 좋은 것에서 그치지 말고, 다 푼 뒤에는 어떻게 최적화할 수 있을지 한 번 더 고민해보고 리팩토링해보아요 ~

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
static int N;
static int[] parent;
static Stack<Integer> p1, p2;

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

int T = Integer.parseInt(br.readLine());
for(int t = 0; t < T; t++) {
parent = new int[10001];

N = Integer.parseInt(br.readLine());

for(int i = 0; i < N-1; i++){
String[] temp = br.readLine().split(" ");
parent[Integer.parseInt(temp[1])] = Integer.parseInt(temp[0]);
}

String[] temp2 = br.readLine().split(" ");
int num1 = Integer.parseInt(temp2[0]);
p1 = new Stack<>();
int num2 = Integer.parseInt(temp2[1]);
p2 = new Stack<>();

// 부모를 거슬러가면서 스택에 넣기
int index = num1;
p1.push(index);
while(parent[index] != 0){
p1.push(parent[index]);
index = parent[index];
}

index = num2;
p2.push(index);
while(parent[index] != 0){
p2.push(parent[index]);
index = parent[index];
}

System.out.println(getAncestor(num1, num2));
}
}

static int getAncestor(int n1, int n2){
int answer = 0;

// 두 스택에서 하나씩 빼면서 같은 수가 나오면 공통 조상
// --> 마지막에 나오는 공통 조상이 제일 가까운 공통 조상

while(!p1.isEmpty() && !p2.isEmpty()){ // 둘 중 하나가 빌 때까지
int num1 = p1.pop();
int num2 = p2.pop();

if(num1 != num2){ // 부모가 다르면 멈춤
break;
}

answer = num1;
}

return answer;
}
}

// 가장 가까운 공통 조상 찾기

37 changes: 37 additions & 0 deletions BOJ/[3584] 가장 가까운 공통 조상/asever0318/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# [3584] 가장 가까운 공통 조상

## :pushpin: **Algorithm**

스택, 트리

## :round_pushpin: **Logic**
- parent라는 int배열에 해당 인덱스 숫자의 부모를 저장한다.
- 공통 조상을 찾아야하는 두 숫자 각 stack을 만들어서 부모를 root까지 쭉 push한다.

```java
static int getAncestor(int n1, int n2){
int answer = 0;

// 두 스택에서 하나씩 빼면서 같은 수가 나오면 공통 조상
// --> 마지막에 나오는 공통 조상이 제일 가까운 공통 조상

while(!p1.isEmpty() && !p2.isEmpty()){ // 둘 중 하나가 빌 때까지
int num1 = p1.pop();
int num2 = p2.pop();

if(num1 != num2){ // 부모가 다르면 멈춤
break;
}

answer = num1;
}

return answer;
}
```
- 두 스택에서 하나씩 빼면서 비교 후 두 숫자가 같으면 공통 조상이므로 answer에 저장하고, 두 수가 같지 않을 때까지 반복한다.

## :black_nib: **Review**
- 처음에는 트리를 리스트로 구현하려고 했는데 어떤 숫자에 자식이 있는지 알 수 없기 때문에 리스트를 미리 만들어 두는 것은 비효율적이라 생각해서 다른 방법을 생각하다가 조상을 찾는 것이기 때문에 부모만 저장해두고 타고타고 올라가면 된다는 생각이 들어 parent 배열을 만들었다.
- 부모를 저장하는 parent배열은 만들었는데 막상 끝에서부터 부모를 비교하면서 올라가려니 부모의 depth가 다를 수 있다는 생각이 들었다. 어떻게 해결할 지 고민하다가 결국 다른 사람의 답을 참고했다.
- stack에 넣어두면 가장 위에 있는 root가 top에 오기 때문에 같은 depth끼리 비교할 수 있게 된다. 사람들은 정말 똑똑하다....
40 changes: 40 additions & 0 deletions Programmers/[155651] 호텔 대실/asever0318/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# [155651] 호텔 대실

## :pushpin: **Algorithm**

누적합

## :round_pushpin: **Logic**
```java
public int solution(String[][] book_time) {
room = new int[24*60+10]; // 24시간*60분+10분 -> 가장 늦게 끝나는 시간

for(int i = 0; i < book_time.length; i++){
int start = getMinutes(book_time[i][0]);
int end = getMinutes(book_time[i][1]);

room[start] += 1; // 시작 시간에는 1 저장
room[end + 10] += -1; // 끝나는 시간 + 청소시간 10분에는 -1 저장
}

prefixSum(); // 누적합

return max;
}
```
- 최대 크기의 1차원 배열을 하나 생성한다.
- 시작 위치에 1을 추가하고 끝 위치에 -1을 추가한다.

```java
static void prefixSum(){
for(int i = 1; i < 24*60+10; i++){
room[i] += room[i-1]; // 이전 값을 더하기
max = Math.max(max, room[i]); // 최대값 갱신(방의 수)
}
}
```
- 앞에서부터 뒤로 진행하면서 이전 요소의 값을 더한다.
- 누적합 배열에서 최대값이 필요한 최소의 방의 수가 된다.

## :black_nib: **Review**
- 처음에 우선순위큐로 풀다가 누적합 풀이를 발견해서 누적합으로 풀어봤는데.. 시작을 1, 끝을 -1로 해서 누적합으로 카운트하다니 사람들은 정말 천재다. 좋은 풀이법을 배운 것 같다.
Loading