Java/코딩테스트

백준 11501, 2169, 프로그래머스 체육복

Bubbles 2023. 11. 7. 18:21

📈 백준 11501 : 주식  

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

 

11501번: 주식

입력의 첫 줄에는 테스트케이스 수를 나타내는 자연수 T가 주어진다. 각 테스트케이스 별로 첫 줄에는 날의 수를 나타내는 자연수 N(2 ≤ N ≤ 1,000,000)이 주어지고, 둘째 줄에는 날 별 주가를 나타

www.acmicpc.net

 

📈 메인 로직

  • 각 날짜의 주식가격을 배열에 쭉 저장해둔다. 
  • 그리디 유형의 문제긴 하지만, 무조건 높을때 다 팔고 끝나는것이 아니라 마지막날에도 이전보다 올랐다면 팔 수 있다.
  • 뒤에서부터 차례로 돌면서 현재 내가 가진 최댓값보다 높은 가격이 나왔다 =  그날 기점으로 가격이 떨어졌다 이것이므로 최댓값을 갱신해준다.
  • 그 외에는 최댓값보다 낮은 날이므로 무조건 사뒀다가 파는게 이득이라 answer에 더해준다. 

📈 메인 로직을 코드화하면 아래와 같다. 

int temp = price[days-1];
for (int d = days-2; d >= 0; d--) {
	if (temp < price[d]) {
		temp = price[d]; // 최댓값 갱신해준다. 
	} else {
		answer += (temp - price[d]); // 더 낮은값일때는 계속 사놓는 것이 이득
	}
}

 

📈 전체 코드

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

public class p11501 {
    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++) {
            int days = Integer.parseInt(br.readLine());
            int[] price = new int[days];
            int answer = 0;
            StringTokenizer st = new StringTokenizer(br.readLine());

            for (int d = 0; d < days; d++) {
                price[d] = Integer.parseInt(st.nextToken());
            }

            int temp = price[days-1];
            for (int d = days-2; d >= 0; d--) {
                if (temp < price[d]) {
                    temp = price[d];
                } else {
                    answer += (temp - price[d]);
                }
            }

            System.out.println(answer);

        }

    }
}

 

 

 


 

 

🤖 백준 2169 : 로봇 조종하기

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

 

2169번: 로봇 조종하기

첫째 줄에 N, M(1≤N, M≤1,000)이 주어진다. 다음 N개의 줄에는 M개의 수로 배열이 주어진다. 배열의 각 수는 절댓값이 100을 넘지 않는 정수이다. 이 값은 그 지역의 가치를 나타낸다.

www.acmicpc.net

 

 

 

🤖 문제 유형 찾기 : DP

  • 문제 조건을 보면 이러한 말들이 있다. 
    • 한 번 탐사한 지역(배열에서 하나의 칸)은 탐사하지 않기로 한다.
    • 탐사한 지역들의 가치의 합이 최대가 되도록 하는 프로그램을 작성하시오.
  • 처음에는 2차원 배열, 3방향으로 움직일 수 있다는 조건을 보고 BFS를 생각했는데, BFS는 최단거리 찾는것이므로 가치의 합이 최대가 되는 것이라면..하고 DFS를 생각했었다.
  • 하지만 제한시간이 1초이고 n,m이 1000까지 갈 수 있으므로 동적계획법으로 푸는 건가? 라는 생각을 했다. (위의 조건을 보고 / 그리고 실제로 DP문제였다. )

🤖 메인 로직 

 

  • 이동 가능한 방향은 좌, 우, 하 이렇게 3가지이고, DP[ i ][ j ]에서 위, 오른쪽, 왼쪽을 다 비교해보고 Max를 찾아야 한다.
  • 위로 돌아가는 것은 불가능하므로, 무조건 DP 2차원 배열의 맨 윗줄은 map에서 가져와야 한다.
DP[0][0] = map[0][0];
for (int j = 1; j < col; j++) {
	DP[0][j] = DP[0][j-1] + map[0][j];
}

 

  • 각 칸 별로 왼쪽에서 탐색해서 오는 경우와 오른쪽에서 탐색해서 오는 경우 중 더 큰 걸 찾아야 한다.
// 왼쪽에서 출발
left[0] = DP[i-1][0] + map[i][0];
for (int j = 1; j < col; j++) {
	left[j] = Math.max(DP[i-1][j], left[j-1]) + map[i][j];
}

// 오른쪽에서 출발
right[col-1] = DP[i-1][col-1] + map[i][col-1];
for (int j = col-2; j >= 0; j--) {
	right[j] = Math.max(DP[i-1][j], right[j+1]) + map[i][j];
}

 

  • 왼쪽 오른쪽 다 탐색 후 MAX로 갱신해준다. 
for (int j = 0; j < col; j++) {
	DP[i][j] = Math.max(left[j], right[j]);
}

 

 

🤖 전체코드 

import java.util.*;
import java.io.*;
public class p2169 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int row = Integer.parseInt(st.nextToken());
        int col = Integer.parseInt(st.nextToken());

        int[][] map = new int[row][col];
        int[][] DP = new int[row][col];

        for (int i = 0; i < row; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < col; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }
        DP[0][0] = map[0][0];
        for (int j = 1; j < col; j++) {
            DP[0][j] = DP[0][j-1] + map[0][j];
        }

        for (int i = 1; i < row; i++) {
            int[] left = new int[col];
            int[] right = new int[col];

            // 왼쪽에서 출발
            left[0] = DP[i-1][0] + map[i][0];
            for (int j = 1; j < col; j++) {
                left[j] = Math.max(DP[i-1][j], left[j-1]) + map[i][j];
            }

            // 오른쪽에서 출발
            right[col-1] = DP[i-1][col-1] + map[i][col-1];
            for (int j = col-2; j >= 0; j--) {
                right[j] = Math.max(DP[i-1][j], right[j+1]) + map[i][j];
            }
            for (int j = 0; j < col; j++) {
                DP[i][j] = Math.max(left[j], right[j]);
            }
        }

        System.out.println(DP[row-1][col-1]);
    }


}

 

 

 

 


 

 

 

⛹🏻‍♀️ 프로그래머스 : 체육복 

https://school.programmers.co.kr/learn/courses/30/lessons/42862

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

⛹🏻‍♀️ 메인로직

  • 먼저 모든 학생들이 참석할 수 있다고 가정하고 answer을 초기화 시킨 다음, 참석 불가능한 애들만 빼주면 된다.
  • set에다가 여벌을 가지고 온 학생들 번호를 넣는다.
  • 문제 조건에 따르면, 여벌 가지고 온 애들이 도난당한 경우 여벌을 빌려줄 수 없다. 그러므로 먼저 이 경우를 반복문을 돌린다.
    • reserve 배열 탐색하면서 set과 동일한 애가 있는 경우가 위의 예시이므로, set에서 제거해준 후 list에 넣지 않는다. 
  • list는 중복을 제거한, 진짜 잃어버린 애들을 담는 리스트이며, 번호 순대로 정렬해준다.(체격 순으로 번호가 매겨지니까) 
  • 그 후 set에서 자기 앞뒤 사이즈의 여벌이 있는지 확인하고, 없다면 answer--해준다. 

⛹🏻‍♀️ 전체코드 

import java.util.*;
class Solution {
    public int solution(int n, int[] lost, int[] reserve) {
        int answer = n;
        Set<Integer> set = new HashSet<>();
        List<Integer> list = new ArrayList<>();
        for (int i : reserve) {
            set.add(i);
        }
        for (int i : lost) {
            if (set.contains(i)) {
                set.remove(i);
            } else {
                list.add(i);
            }
        }
        Collections.sort(list);
        
        for (int i : list) {
            if (set.contains(i-1)) {
                set.remove(i-1);
            } else if (set.contains(i+1)) {
                set.remove(i+1);
            } else {
                answer--;
            }
        }
        return answer;
    }
}