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

 

프로그래머스

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

programmers.co.kr

어렵지 않았지만, 배열 인덱스 범위를 잘못 지정해줘서 생각보다 오래걸렸던 문제다. 백준에도 비슷한 문제가 있었는데 다시 풀어봐도 헷갈렸던 문제..

triangle 2차원 배열의 인덱스를 초과 하지 않게 하기 위해서 왼쪽 가장자리와, 오른쪽 가장자리를 따로 초기화 해준다
DP[i][0] = DP[i - 1][0] + triangle[i][0];    // 왼쪽
DP[i][i] = DP[i - 1][i - 1] + triangle[i][i]; // 오른쪽

가운데가 핵심인데

이런 식으로 현재 위치에서 왼쪽 위에서 누적된 합과 오른쪽 위에서 누적된 합 중에 더 큰 값을 현재 값과 더해준다
DP[i][j] = Math.max(DP[i - 1][j], DP[i - 1][j - 1]) + triangle[i][j];

import java.util.*;

class Solution {

    public int solution(int[][] triangle) {
        int answer = 0;

        int len = triangle.length;

        int[][] DP = new int[len + 1][len + 1];

        DP[0][0] = triangle[0][0];

        for (int i = 1; i < len; i++) {
            // 맨 왼쪽
            DP[i][0] = DP[i - 1][0] + triangle[i][0];

            // 가운데
            for (int j = 1; j < i; j++)
                DP[i][j] = Math.max(DP[i - 1][j], DP[i - 1][j - 1]) + triangle[i][j];

            // 맨 오른쪽
            DP[i][i] = DP[i - 1][i - 1] + triangle[i][i];
        }

        for (int i = 0; i < len; i++)
            answer = Math.max(DP[len - 1][i], answer);

        return answer;
    }
}

성공적으로 통과!

| 자바 toCharArray 활용법

 

프로그래머스를 풀다가 자주 사용하게 될 것 같은 함수를 발견하여 정리해둡니다. 

class Main {

    public static void main(String[] args) {
        String s = "Hello World";

        char[] arr = s.toCharArray();

        for(char ch : arr)
            System.out.print(ch+" ");
    }
}

문자열 "Hello World"를 char 배열에 각각 담을 수 있는 함수!
String (문자열) 을 Char형 배열로 바꿔줍니다

결과값

Hello World 가 각각 char 배열에 정상적으로 담긴 것을 확인 할 수 있습니다.

https://school.programmers.co.kr/learn/courses/30/lessons/17680?language=java 

 

프로그래머스

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

programmers.co.kr

LRU에 대한 개념이 기억이 안나서 찾아보면서 풀어봤던 문제이다.
해야할 작업이 캐시에 있는 상태인지, 없는 상태인지 나눠서 처리해줘야하고
캐시크기가 0인 경우 예외 처리를 해주면 어렵지 않게 풀 수 있는 문제다

import java.util.*;

class Solution {
    public int solution(int cacheSize, String[] cities) {
        int answer = 0;

        /*
        LRU => 가장 오래 참조되지 않은 페이지 교체
        (시간을 기록해야한다는 단점이 있어서 오버헤드)

        cache hit : 해야할 작업이 캐시에 있는 상태
        cache miss : 해야할 작업이 캐시에 없는 상태
        */

        LinkedList<String> list = new LinkedList<>();

        if (cacheSize == 0) 
            return cities.length * 5;
        
        for (int i = 0; i < cities.length; i++) {

            String target = cities[i].toLowerCase();
            // 해야할 작업이 캐시에 있는지 없는지 확인
            boolean flag = false;
            int idx = 0;

            for (int j = 0; j < list.size(); j++) {
                // 있으면
                if (list.get(j).equals(target)) {
                    flag = true;
                    idx = j;
                }
            }

            // cache hit
            if (flag) {
                list.add(list.remove(idx));
                answer++;
            }
            // cache miss
            else {
                if (list.size() >= cacheSize) 
                    list.removeFirst();
                
                list.add(target);
                answer += 5;
            }
        }

        return answer;
    }
}

 

    List<String> sortedList = new ArrayList<>(importand_document_entities);

    Comparator<String> c = new Comparator<String>() {
        public int compare(String s1, String s2) {
            return Integer.compare(s2.length(), s1.length());
        }
    };

    Collections.sort(sortedList, c);

 

    // 배열 길이순으로 정
    Arrays.sort(tmp,new Comparator<String>(){
        public int compare(String o1, String o2){

            return Integer.compare(o1.length(), o2.length());
        }
    });

 

반대순으로 정렬은 compare 내부의 o1,o2끼리 위치만 바꿔주면 된다!

Map에 값을 전체 출력하기 위해서는 entrySet(), keySet() 메소드를 사용하면 되는데 entrySet() 메서드는 key와 value의 값이 모두 필요한 경우 사용하고, keySet() 메서드는 key의 값만 필요한 경우 사용합니다.

방법 01 : entrySet()

Map<String, String> map = new HashMap<String, String>();
map.put("key01", "value01");
map.put("key02", "value02");
map.put("key03", "value03");
map.put("key04", "value04");
map.put("key05", "value05");

// 방법 01 : entrySet()
for (Map.Entry<String, String> entry : map.entrySet()) {
	System.out.println("[key]:" + entry.getKey() + ", [value]:" + entry.getValue());
}

 

방법 02 : keySet()

Map<String, String> map = new HashMap<String, String>();
map.put("key01", "value01");
map.put("key02", "value02");
map.put("key03", "value03");
map.put("key04", "value04");
map.put("key05", "value05");
        
// 방법 02 : keySet()
for (String key : map.keySet()) {
	String value = map.get(key);
    System.out.println("[key]:" + key + ", [value]:" + value);
}    

 

Iterator 인터페이스를 사용할 수 없는 컬렉션인 Map에서 Iterator 인터페이스를 사용하기 위해서는 Map에 entrySet(), keySet() 메소드를 사용하여 Set 객체를 반환받은 후 Iterator 인터페이스를 사용하시면 됩니다.

방법 03 : entrySet().iterator()

Map<String, String> map = new HashMap<String, String>();
map.put("key01", "value01");
map.put("key02", "value02");
map.put("key03", "value03");
map.put("key04", "value04");
map.put("key05", "value05");
    
// 방법 03 : entrySet().iterator()
Iterator<Map.Entry<String, String>> iteratorE = map.entrySet().iterator();
while (iteratorE.hasNext()) {
	Map.Entry<String, String> entry = (Map.Entry<String, String>) iteratorE.next();
   	String key = entry.getKey();
   	String value = entry.getValue();
   	System.out.println("[key]:" + key + ", [value]:" + value);
}

 

방법 04 : keySet().iterator()

Map<String, String> map = new HashMap<String, String>();
map.put("key01", "value01");
map.put("key02", "value02");
map.put("key03", "value03");
map.put("key04", "value04");
map.put("key05", "value05");

// 방법 04 : keySet().iterator()
Iterator<String> iteratorK = map.keySet().iterator();
	while (iteratorK.hasNext()) {
	String key = iteratorK.next();
	String value = map.get(key);
	System.out.println("[key]:" + key + ", [value]:" + value);
}

 

방법 05 : Lambda 사용

Map<String, String> map = new HashMap<String, String>();
map.put("key01", "value01");
map.put("key02", "value02");
map.put("key03", "value03");
map.put("key04", "value04");
map.put("key05", "value05");

// 방법 05 : Lambda 사용
map.entrySet().stream().forEach(entry-> {
	System.out.println("[key]:" + entry.getKey() + ", [value]:"+entry.getValue());
});

 

방법 06 : Stream 사용

Map<String, String> map = new HashMap<String, String>();
map.put("key01", "value01");
map.put("key02", "value02");
map.put("key03", "value03");
map.put("key04", "value04");
map.put("key05", "value05");

// 방법 06 : Stream 사용
map.entrySet().stream().forEach(entry-> {
	System.out.println("[key]:" + entry.getKey() + ", [value]:"+entry.getValue());
});
	        
// Stream 사용 - 내림차순
map.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry-> {
	System.out.println("[key]:" + entry.getKey() + ", [value]:"+entry.getValue());
});

// Stream 사용 - 오름차순
map.entrySet().stream().sorted(Map.Entry.comparingByKey(Comparator.reverseOrder())).forEach(entry-> {
	System.out.println("[key]:" + entry.getKey() + ", [value]:"+entry.getValue());
});

출처: https://tychejin.tistory.com/31 [너나들이 개발 이야기:티스토리]

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

 

프로그래머스

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

programmers.co.kr

문제 설명

트럭 여러 대가 강을 가로지르는 일차선 다리를 정해진 순으로 건너려 합니다. 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 알아내야 합니다. 다리에는 트럭이 최대 bridge_length대 올라갈 수 있으며, 다리는 weight 이하까지의 무게를 견딜 수 있습니다. 단, 다리에 완전히 오르지 않은 트럭의 무게는 무시합니다.

예를 들어, 트럭 2대가 올라갈 수 있고 무게를 10kg까지 견디는 다리가 있습니다. 무게가 [7, 4, 5, 6]kg인 트럭이 순서대로 최단 시간 안에 다리를 건너려면 다음과 같이 건너야 합니다.


경과 시간 다리를 지난 트럭 다리를 건너는 트럭 대기 트럭
0 [] [] [7,4,5,6]
1~2 [] [7] [4,5,6]
3 [7] [4] [5,6]
4 [7] [4,5] [6]
5 [7,4] [5] [6]
6~7 [7,4,5] [6] []
8 [7,4,5,6] [] []

따라서, 모든 트럭이 다리를 지나려면 최소 8초가 걸립니다.

solution 함수의 매개변수로 다리에 올라갈 수 있는 트럭 수 bridge_length, 다리가 견딜 수 있는 무게 weight, 트럭 별 무게 truck_weights가 주어집니다. 이때 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 return 하도록 solution 함수를 완성하세요.

제한 조건
  • bridge_length는 1 이상 10,000 이하입니다.
  • weight는 1 이상 10,000 이하입니다.
  • truck_weights의 길이는 1 이상 10,000 이하입니다.
  • 모든 트럭의 무게는 1 이상 weight 이하입니다.
입출력 예
bridge_length weight truck_weights return
2 10 [7,4,5,6] 8
100 100 [10] 101
100 100 [10,10,10,10,10,10,10,10,10,10] 110

 


문제 포인트

다리가 비어있는 경우와 비어있지 않은 경우를 크게 if문으로 나누어서 구현
다리가 비어있는 경우는 그냥 단순하게 다리(Queue)에 밀어넣어주면 되고
다리가 비어있지 않은 경우 무게를 견딜수 있으면 Queue에 넣어주고
무게를 견딜수 없으면 '0'을 밀어 넣어준다 ★ 이게 포인트
Queue의 size가 시간이 되는 개념이기때문에 다리에 트럭이 올라오지 않더라고 한칸씩 밀어주기 위해서
'0'을 Queue에 삽입!


import java.util.*;

class Solution {
    public int solution(int bridge_length, int weight, int[] truck_weights) {
        Queue<Integer> qu = new LinkedList<>();

        int current_weight = 0; // 현재무게
        int timer = 0;

        for (int i = 0; i < truck_weights.length; i++) {
            // 다리가 비어있는 경우
            if (qu.isEmpty()) {
                if (truck_weights[i] <= weight) {
                    qu.add(truck_weights[i]);
                    current_weight += truck_weights[i];
                    timer++;
                    continue;
                }
            }
            // 다리가 비어있지 않은 경우
            else {
                while(true){
                    // 다리가 꽉찬 상태면 큐 하나 밀어내기!
                    if (qu.size() >= bridge_length) 
                        current_weight -= qu.poll();
                    
                    // 다리를 건널수있는 상태면 건너기
                    if (current_weight + truck_weights[i] <= weight) {
                        qu.add(truck_weights[i]);
                        current_weight += truck_weights[i];
                        timer++;
                        break;
                    }
                    // 못건너는 상태면 '0'으로 큐를 밀어내기!
                    else {
                        qu.add(0); // 이게 ...★
                        timer++;
                    }

                }

            }
        }

        return timer + bridge_length;
    }
}

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

 

프로그래머스

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

programmers.co.kr

문제 설명

ROR 게임은 두 팀으로 나누어서 진행하며, 상대 팀 진영을 먼저 파괴하면 이기는 게임입니다. 따라서, 각 팀은 상대 팀 진영에 최대한 빨리 도착하는 것이 유리합니다.

지금부터 당신은 한 팀의 팀원이 되어 게임을 진행하려고 합니다. 다음은 5 x 5 크기의 맵에, 당신의 캐릭터가 (행: 1, 열: 1) 위치에 있고, 상대 팀 진영은 (행: 5, 열: 5) 위치에 있는 경우의 예시입니다.

위 그림에서 검은색 부분은 벽으로 막혀있어 갈 수 없는 길이며, 흰색 부분은 갈 수 있는 길입니다. 캐릭터가 움직일 때는 동, 서, 남, 북 방향으로 한 칸씩 이동하며, 게임 맵을 벗어난 길은 갈 수 없습니다.
아래 예시는 캐릭터가 상대 팀 진영으로 가는 두 가지 방법을 나타내고 있습니다.

  • 첫 번째 방법은 11개의 칸을 지나서 상대 팀 진영에 도착했습니다.
  • 두 번째 방법은 15개의 칸을 지나서 상대팀 진영에 도착했습니다.

위 예시에서는 첫 번째 방법보다 더 빠르게 상대팀 진영에 도착하는 방법은 없으므로, 이 방법이 상대 팀 진영으로 가는 가장 빠른 방법입니다.

만약, 상대 팀이 자신의 팀 진영 주위에 벽을 세워두었다면 상대 팀 진영에 도착하지 못할 수도 있습니다. 예를 들어, 다음과 같은 경우에 당신의 캐릭터는 상대 팀 진영에 도착할 수 없습니다.

게임 맵의 상태 maps가 매개변수로 주어질 때, 캐릭터가 상대 팀 진영에 도착하기 위해서 지나가야 하는 칸의 개수의 최솟값을 return 하도록 solution 함수를 완성해주세요. 단, 상대 팀 진영에 도착할 수 없을 때는 -1을 return 해주세요.

제한사항
  • maps는 n x m 크기의 게임 맵의 상태가 들어있는 2차원 배열로, n과 m은 각각 1 이상 100 이하의 자연수입니다.
    • n과 m은 서로 같을 수도, 다를 수도 있지만, n과 m이 모두 1인 경우는 입력으로 주어지지 않습니다.
  • maps는 0과 1로만 이루어져 있으며, 0은 벽이 있는 자리, 1은 벽이 없는 자리를 나타냅니다.
  • 처음에 캐릭터는 게임 맵의 좌측 상단인 (1, 1) 위치에 있으며, 상대방 진영은 게임 맵의 우측 하단인 (n, m) 위치에 있습니다.

 

입출력 예
maps answer
[[1,0,1,1,1],[1,0,1,0,1],[1,0,1,1,1],[1,1,1,0,1],[0,0,0,0,1]] 11
[[1,0,1,1,1],[1,0,1,0,1],[1,0,1,1,1],[1,1,1,0,0],[0,0,0,0,1]] -1
입출력 예 설명

입출력 예 #1
주어진 데이터는 다음과 같습니다.

캐릭터가 적 팀의 진영까지 이동하는 가장 빠른 길은 다음 그림과 같습니다.

따라서 총 11칸을 캐릭터가 지나갔으므로 11을 return 하면 됩니다.

입출력 예 #2
문제의 예시와 같으며, 상대 팀 진영에 도달할 방법이 없습니다. 따라서 -1을 return 합니다.


전형적인 BFS 문제다. N X N 에서 최단거리를 구할떄는 BFS! 이건 그냥 공식처럼 외워두자
BFS 를 돌려서 maps[N-1][M-1] 에 최종으로 도달했을때 저장되있는 값을 리턴, maps[N-1][M-1]에 방문한 적이 없으면
-1을 리턴!


import java.util.*;

class Solution {
    
    static boolean[][] visited; // 방문여부체크배열
    
    static int[] dy = {1, 0, -1, 0};
    static int[] dx = {0, 1, 0, -1};
    
    static int N,M;       // 행, 열
    
    public int solution(int[][] maps) {
        int answer = 0;
        
        N = maps.length; // 열 (가로) -> x
        M = maps[0].length;    // 행 (세로) -> y
        
        visited = new boolean[N+1][M+1];
        
        BFS(0 ,0, maps); // BFS 시작
        
        if(visited[N-1][M-1])
            return maps[N-1][M-1];   
        else
            return -1;
    }
    public static void BFS(int y ,int x, int[][] maps){
        
        Queue<int[]> qu = new LinkedList<int[]>();
        
        qu.offer(new int[] {y, x});
        
        visited[y][x] = true;
        
        while(!qu.isEmpty()){
            int curY = qu.peek()[0];
            int curX = qu.peek()[1];
            
            qu.poll();
            
            for(int i =0; i<4; i++){
                int ny = curY + dy[i];
                int nx = curX + dx[i];
                
                //지도 범위내에서 벗어나면
                if(0 <= nx && 0 <= ny && nx < M && ny < N){
                    if(!visited[ny][nx] && maps[ny][nx] !=0){
                        qu.offer(new int[] {ny,nx});
                
                         maps[ny][nx] = maps[curY][curX] + 1;

                        visited[ny][nx] = true;
                    }           
                }
            }
        }
    }
}

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

 

프로그래머스

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

programmers.co.kr


문제 설명

오픈채팅방

카카오톡 오픈채팅방에서는 친구가 아닌 사람들과 대화를 할 수 있는데, 본래 닉네임이 아닌 가상의 닉네임을 사용하여 채팅방에 들어갈 수 있다.

신입사원인 김크루는 카카오톡 오픈 채팅방을 개설한 사람을 위해, 다양한 사람들이 들어오고, 나가는 것을 지켜볼 수 있는 관리자창을 만들기로 했다. 채팅방에 누군가 들어오면 다음 메시지가 출력된다.

"[닉네임]님이 들어왔습니다."

채팅방에서 누군가 나가면 다음 메시지가 출력된다.

"[닉네임]님이 나갔습니다."

채팅방에서 닉네임을 변경하는 방법은 다음과 같이 두 가지이다.

  • 채팅방을 나간 후, 새로운 닉네임으로 다시 들어간다.
  • 채팅방에서 닉네임을 변경한다.

닉네임을 변경할 때는 기존에 채팅방에 출력되어 있던 메시지의 닉네임도 전부 변경된다.

예를 들어, 채팅방에 "Muzi"와 "Prodo"라는 닉네임을 사용하는 사람이 순서대로 들어오면 채팅방에는 다음과 같이 메시지가 출력된다.

"Muzi님이 들어왔습니다."
"Prodo님이 들어왔습니다."

채팅방에 있던 사람이 나가면 채팅방에는 다음과 같이 메시지가 남는다.

"Muzi님이 들어왔습니다."
"Prodo님이 들어왔습니다."
"Muzi님이 나갔습니다."

Muzi가 나간후 다시 들어올 때, Prodo 라는 닉네임으로 들어올 경우 기존에 채팅방에 남아있던 Muzi도 Prodo로 다음과 같이 변경된다.

"Prodo님이 들어왔습니다."
"Prodo님이 들어왔습니다."
"Prodo님이 나갔습니다."
"Prodo님이 들어왔습니다."

채팅방은 중복 닉네임을 허용하기 때문에, 현재 채팅방에는 Prodo라는 닉네임을 사용하는 사람이 두 명이 있다. 이제, 채팅방에 두 번째로 들어왔던 Prodo가 Ryan으로 닉네임을 변경하면 채팅방 메시지는 다음과 같이 변경된다.

"Prodo님이 들어왔습니다."
"Ryan님이 들어왔습니다."
"Prodo님이 나갔습니다."
"Prodo님이 들어왔습니다."

채팅방에 들어오고 나가거나, 닉네임을 변경한 기록이 담긴 문자열 배열 record가 매개변수로 주어질 때, 모든 기록이 처리된 후, 최종적으로 방을 개설한 사람이 보게 되는 메시지를 문자열 배열 형태로 return 하도록 solution 함수를 완성하라.

제한사항
  • record는 다음과 같은 문자열이 담긴 배열이며, 길이는 1 이상 100,000 이하이다.
  • 다음은 record에 담긴 문자열에 대한 설명이다.
    • 모든 유저는 [유저 아이디]로 구분한다.
    • [유저 아이디] 사용자가 [닉네임]으로 채팅방에 입장 - "Enter [유저 아이디] [닉네임]" (ex. "Enter uid1234 Muzi")
    • [유저 아이디] 사용자가 채팅방에서 퇴장 - "Leave [유저 아이디]" (ex. "Leave uid1234")
    • [유저 아이디] 사용자가 닉네임을 [닉네임]으로 변경 - "Change [유저 아이디] [닉네임]" (ex. "Change uid1234 Muzi")
    • 첫 단어는 Enter, Leave, Change 중 하나이다.
    • 각 단어는 공백으로 구분되어 있으며, 알파벳 대문자, 소문자, 숫자로만 이루어져있다.
    • 유저 아이디와 닉네임은 알파벳 대문자, 소문자를 구별한다.
    • 유저 아이디와 닉네임의 길이는 1 이상 10 이하이다.
    • 채팅방에서 나간 유저가 닉네임을 변경하는 등 잘못 된 입력은 주어지지 않는다.
입출력 예
record result
["Enter uid1234 Muzi", "Enter uid4567 Prodo","Leave uid1234","Enter uid1234 Prodo","Change uid4567 Ryan"] ["Prodo님이 들어왔습니다.", "Ryan님이 들어왔습니다.", "Prodo님이 나갔습니다.", "Prodo님이 들어왔습니다."]
입출력 예 설명

입출력 예 #1
문제의 설명과 같다.


문제 포인트

1. 'Enter' 인 경우 'id + 출력 메세지' al에 String 형태로 추가
2. 'Leave' 인 경우 '출력메세지'만 al에 String 형태로 추가
3. 'Change'인 경우 기존 map 저장되있는 id를 변경된 id로 바꿔서 map에 저장

마지막에 'id (key) + 출력메세지'로 저장되있는 al를 '님' 문자열 앞부분 기준으로 잘라서 map에서 get!
나온 닉네임(value)으로 '닉네임 + 출력메세지'로 출력


 

import java.util.*;

class Solution {
    public String[] solution(String[] record) {


        HashMap<String, String> map = new HashMap<>();
        ArrayList<String> al = new ArrayList<>();

        // 각 명령어 대로 key+"님이 ~~~" 형식으로 al에 저장
        for (String str : record) {

            String command[] = str.split(" ");

            switch (command[0]) {

                // 들어온경우 Map 에 Key를 ID , value를 닉네임으로 저장 (uid1234 , Muzi) 
                // 들어온 id + 메세지 al에 추가
                case "Enter":
                    map.put(command[1], command[2]);
                    al.add(command[1] + "님이 들어왔습니다.");
                    break;
                // 나가는 경우 나가는 아이디 + 메세지만 al에 추가
                case "Leave":
                    al.add(command[1] + "님이 나갔습니다.");
                    break;
                // 해당  key 값에 대한 value 만 변경
                case "Change":
                    map.replace(command[1], command[2]);
                    break;
            }
        }

        // record 의 크기로 선언해주면 change 명령어까지 카운트 되므로 al.size로 선언 (메세지 출력수)  
        String[] answer = new String[al.size()];

        for (int i = 0; i < al.size(); i++) {
            String tmp = al.get(i);
            int idx = tmp.indexOf('님'); // '님'이 나오는 인덱스를 기억해서
            String key_id = tmp.substring(0, idx); // '님'이 나오기 직전 idx 까지 key_id 에 저장
            answer[i] = tmp.replace(key_id, map.get(key_id)); // key_id를 value 로 replace 로 하여 answer[i] 에 저장
        }

        return answer;
    }
}

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

 

프로그래머스

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

programmers.co.kr

문제 설명

주차장의 요금표와 차량이 들어오고(입차) 나간(출차) 기록이 주어졌을 때, 차량별로 주차 요금을 계산하려고 합니다. 아래는 하나의 예시를 나타냅니다.

  • 요금표

기본 시간(분)기본 요금(원)단위 시간(분)단위 요금(원)

180 5000 10 600

 

  • 입/출차 기록

시각(시:분)차량 번호내역

05:34 5961 입차
06:00 0000 입차
06:34 0000 출차
07:59 5961 출차
07:59 0148 입차
18:59 0000 입차
19:09 0148 출차
22:59 5961 입차
23:00 5961 출차

 

  • 자동차별 주차 요금

차량 번호누적 주차 시간(분)주차 요금(원)

0000 34 + 300 = 334 5000 + ⌈(334 - 180) / 10⌉ x 600 = 14600
0148 670 5000 +⌈(670 - 180) / 10⌉x 600 = 34400
5961 145 + 1 = 146 5000
  • 어떤 차량이 입차된 후에 출차된 내역이 없다면, 23:59에 출차된 것으로 간주합니다.
    • 0000번 차량은 18:59에 입차된 이후, 출차된 내역이 없습니다. 따라서, 23:59에 출차된 것으로 간주합니다.
  • 00:00부터 23:59까지의 입/출차 내역을 바탕으로 차량별 누적 주차 시간을 계산하여 요금을 일괄로 정산합니다.
  • 누적 주차 시간이 기본 시간이하라면, 기본 요금을 청구합니다.
  • 누적 주차 시간이 기본 시간을 초과하면, 기본 요금에 더해서, 초과한 시간에 대해서 단위 시간 마다 단위 요금을 청구합니다.
    • 초과한 시간이 단위 시간으로 나누어 떨어지지 않으면, 올림합니다.
    • ⌈a⌉ : a보다 작지 않은 최소의 정수를 의미합니다. 즉, 올림을 의미합니다.

주차 요금을 나타내는 정수 배열 fees, 자동차의 입/출차 내역을 나타내는 문자열 배열 records가 매개변수로 주어집니다. 차량 번호가 작은 자동차부터 청구할 주차 요금을 차례대로 정수 배열에 담아서 return 하도록 solution 함수를 완성해주세요.

제한사항

  • fees의 길이 = 4
    • fees[0] = 기본 시간(분)
    • 1 ≤ fees[0] ≤ 1,439
    • fees[1] = 기본 요금(원)
    • 0 ≤ fees[1] ≤ 100,000
    • fees[2] = 단위 시간(분)
    • 1 ≤ fees[2] ≤ 1,439
    • fees[3] = 단위 요금(원)
    • 1 ≤ fees[3] ≤ 10,000
  • 1 ≤ records의 길이 ≤ 1,000
    • records의 각 원소는 "시각 차량번호 내역" 형식의 문자열입니다.
    • 시각, 차량번호, 내역은 하나의 공백으로 구분되어 있습니다.
    • 시각은 차량이 입차되거나 출차된 시각을 나타내며, HH:MM 형식의 길이 5인 문자열입니다.
      • HH:MM은 00:00부터 23:59까지 주어집니다.
      • 잘못된 시각("25:22", "09:65" 등)은 입력으로 주어지지 않습니다.
    • 차량번호는 자동차를 구분하기 위한, `0'~'9'로 구성된 길이 4인 문자열입니다.
    • 내역은 길이 2 또는 3인 문자열로, IN 또는 OUT입니다. IN은 입차를, OUT은 출차를 의미합니다.
    • records의 원소들은 시각을 기준으로 오름차순으로 정렬되어 주어집니다.
    • records는 하루 동안의 입/출차된 기록만 담고 있으며, 입차된 차량이 다음날 출차되는 경우는 입력으로 주어지지 않습니다.
    • 같은 시각에, 같은 차량번호의 내역이 2번 이상 나타내지 않습니다.
    • 마지막 시각(23:59)에 입차되는 경우는 입력으로 주어지지 않습니다.
    • 아래의 예를 포함하여, 잘못된 입력은 주어지지 않습니다.
      • 주차장에 없는 차량이 출차되는 경우
      • 주차장에 이미 있는 차량(차량번호가 같은 차량)이 다시 입차되는 경우

입출력 예

fees records result
[180, 5000, 10, 600] ["05:34 5961 IN", "06:00 0000 IN", "06:34 0000 OUT", "07:59 5961 OUT", "07:59 0148 IN", "18:59 0000 IN", "19:09 0148 OUT", "22:59 5961 IN", "23:00 5961 OUT"] [14600, 34400, 5000]
[120, 0, 60, 591] ["16:00 3961 IN","16:00 0202 IN","18:00 3961 OUT","18:00 0202 OUT","23:58 3961 IN"] [0, 591]
[1, 461, 1, 10] ["00:00 1234 IN"] [14841]

입출력 예 설명

입출력 예 #1

문제 예시와 같습니다.

입출력 예 #2

  • 요금표

기본 시간(분)기본 요금(원)단위 시간(분)단위 요금(원)

120 0 60 591

 

  • 입/출차 기록

시각(시:분)차량 번호내역

16:00 3961 입차
16:00 0202 입차
18:00 3961 출차
18:00 0202 출차
23:58 3961 입차

 

  • 자동차별 주차 요금

차량 번호누적 주차 시간(분)주차 요금(원)

0202 120 0
3961 120 + 1 = 121 0 +[(121 - 120) / 60]x 591 = 591
  • 3961번 차량은 2번째 입차된 후에는 출차된 내역이 없으므로, 23:59에 출차되었다고 간주합니다.

 

입출력 예 #3

  • 요금표

기본 시간(분)기본 요금(원)단위 시간(분)단위 요금(원)

1 461 1 10

 

  • 입/출차 기록

시각(시:분)차량 번호내역

00:00 1234 입차

 

  • 자동차별 주차 요금

차량 번호누적 주차 시간(분)주차 요금(원)

1234 1439 461 +[(1439 - 1) / 1]x 10 = 14841
  • 1234번 차량은 출차 내역이 없으므로, 23:59에 출차되었다고 간주합니다.

 

 


import java.util.*;

class Solution {
    public int[] solution(int[] fees, String[] records) {
        int[] answer = {};
        // 기본 시간(분) / 기본 요금(원) / 단위 시간(분) /단위 요금(원)

        HashMap<String, Integer> map = new HashMap<>();
        HashMap<String, Integer> result_map = new HashMap<>();      // 결과값 저장

        // 주차시간 누적시키기
        for (int i = 0; i < records.length; i++) {
            String car_record[] = records[i].split(" ");

            if (car_record[2].equals("IN")) {
                // 입차일 경우 ( 차량번호(key) , 입차시간(value) ) 형태로 map 에 저장
                map.put(car_record[1], hourtomin(car_record[0]));
            } else if (car_record[2].equals("OUT")) {
                // 출차일 경우
                int parking_time = map.get(car_record[1]);   // 주차시간
                int exiting_time = hourtomin(car_record[0]); // 출차시간

                int cal_time = exiting_time - parking_time; // 계산해야되는 시간(분)

                if (result_map.get(car_record[1]) == null)
                    result_map.put(car_record[1], cal_time);
                else
                    result_map.put(car_record[1], result_map.get(car_record[1]) + cal_time);

                map.remove(car_record[1]);
            }
        }

        // 남은 차 계산
        for (String key : map.keySet()) {
            int time = 0;
            if (result_map.get(key) != null)
                time = result_map.get(key);

            int cal_time = 1439 - map.get(key);

            result_map.put(key, time + cal_time);
        }

        List<String> al = new ArrayList<>(result_map.keySet());

        // 키 값으로 오름차순 정렬
        Collections.sort(al);

        answer = new int[al.size()];
        int idx = 0;

        // 금액계산
        for (String key : al) {

            int time = result_map.get(key); // 해당 차의 주차 총 시간 (분)

            // 기본시간보다 적으면
            if (time <= fees[0]) {
//                result_map.put(key, fees[1]);
                answer[idx] = fees[1];
            }
            // 기본시간보다 많으면
            else {
                double tmp = Math.ceil((time - fees[0]) / (double) fees[2]);
                answer[idx] = fees[1] + (int) tmp * fees[3];
            }
            idx++;
        }

        return answer;
    }

    public int hourtomin(String time) {
        String tmp[] = time.split(":");
        int hour = Integer.parseInt(tmp[0]); // 시간
        int minutes = Integer.parseInt(tmp[1]); // 분

        return hour * 60 + minutes;
    }
}

 

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

 

프로그래머스

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

programmers.co.kr

문제 설명

전화번호부에 적힌 전화번호 중, 한 번호가 다른 번호의 접두어인 경우가 있는지 확인하려 합니다.
전화번호가 다음과 같을 경우, 구조대 전화번호는 영석이의 전화번호의 접두사입니다.

  • 구조대 : 119
  • 박준영 : 97 674 223
  • 지영석 : 11 9552 4421

전화번호부에 적힌 전화번호를 담은 배열 phone_book 이 solution 함수의 매개변수로 주어질 때, 어떤 번호가 다른 번호의 접두어인 경우가 있으면 false를 그렇지 않으면 true를 return 하도록 solution 함수를 작성해주세요.

제한 사항
  • phone_book의 길이는 1 이상 1,000,000 이하입니다.
    • 각 전화번호의 길이는 1 이상 20 이하입니다.
    • 같은 전화번호가 중복해서 들어있지 않습니다.
입출력 예제
phone_book return
["119", "97674223", "1195524421"] false
["123","456","789"] true
["12","123","1235","567","88"] false
입출력 예 설명

입출력 예 #1
앞에서 설명한 예와 같습니다.

입출력 예 #2
한 번호가 다른 번호의 접두사인 경우가 없으므로, 답은 true입니다.

입출력 예 #3
첫 번째 전화번호, “12”가 두 번째 전화번호 “123”의 접두사입니다. 따라서 답은 false입니다.


문제 포인트

처음에 직관적으로 2중 포문을 돌려서 해당 전화번호가 앞에 있으면 접두어인 걸로 구현하였으나 그렇게 하면 효율성 false,,,, 다른 방법 찾아보니 Collections.sort(al); 해서 바로 옆끼리만 체크하면 되는 방법.. 발견.... 천재다... 

※ List<Sring> al = Arrays.asList(phone_book) <- 이것도 기억해두자 Array 를 ArrayList로 변환하는 방법


// 119 , 12119 테스트케이스 추가해보기
import java.util.*;

class Solution {
    public boolean solution(String[] phone_book) {
        boolean answer = true;

        List<String> al = Arrays.asList(phone_book);

        Collections.sort(al);

        for (int i = 0; i < al.size() - 1; i++) {

            // 
            if (al.get(i+1).contains(al.get(i)) && al.get(i+1).charAt(0) == al.get(i).charAt(0)) {
                answer = false;
                break;
            }
//            String cur = al.get(i);
//            String target = al.get(i + 1).substring(0, cur.length());
//            if (cur.equals(target)) {
//                answer = false;
//                break;
//            }
        }

        /* 효율성 테스트 실패
//        String prefix = phone_book[0];
//        int prefix_length = prefix.length();
//        Loop1:
//        for (int i = 0; i < phone_book.length; i++) {
//            String cur = phone_book[i];
//            int cur_length = cur.length();
//
//            for (int j = i + 1; j < phone_book.length; j++) {
//                if (cur_length <= phone_book[j].length()) {
//                    String target = phone_book[j].substring(0, cur_length);
//
//                    if (target.equals(cur)) {
//                        answer = false;
//                        break Loop1;
//                    }
//                }
//            }
//        }

         */
        return answer;
    }
}

 

+ Recent posts