링크

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

 

프로그래머스

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

programmers.co.kr

 

문제

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

풀이

1. 아이디 리스트 정렬
2. 신고 내역 중복 제거
3. 신고 내역 취합
4. 받은 메일 결과 반환

총 4단계로 분류해서 풀었습니다.

String[] id_list: 유저 ID
String[] report: {유저 ID  / 유저가 신고한 ID}
int k: 정지 기준 신고 횟수


1. 아이디 리스트 정렬
id_list 순서대로 메일 받은 수를 반환하기 때문에 해당 순서를 저장합니다.
setId 함수를 만들어서 따로 정렬했습니다.

public int[] solution(String[] id_list, String[] report, int k) {

    // 1. 아이디 리스트 정렬
    HashMap<String, String> map = setId(id_list);
}
public HashMap<String, String> setId(String[] id_list) {
    HashMap<String, String> map = new HashMap<>();
    for (int i = 0; i < id_list.length; i++) {
        map.put(i+"", id_list[i]);
        map.put(id_list[i], i+"");
    }
    return map;
}

 

2. 신고 내역 중복 제거
중복된 신고는 제거해줍니다. (동일한 아이디가 동일한 신고를 했을 시)
스트림을 사용하여 제거 했습니다.

public int[] solution(String[] id_list, String[] report, int k) {

    // 1. 아이디 리스트 정렬
    HashMap<String, String> map = setId(id_list);

    // 2. 신고 내역 중복 제거
    String[] list = Arrays.stream(report).distinct().toArray(String[]::new);
}

 

3. 신고 내역 취합
중복된 신고가 제거되었으니 신고 목록에 있는 내용을 취합합니다.
getReportCounts 함수로 기능을 구현했습니다.

public int[] solution(String[] id_list, String[] report, int k) {

    // 1. 아이디 리스트 정렬
    HashMap<String, String> map = setId(id_list);

    // 2. 신고 내역 중복 제거
    String[] list = Arrays.stream(report).distinct().toArray(String[]::new);

    // 3. 신고 내역 취합
    int[] reportCounts = getReportCounts(map, list, id_list.length);
}
public int[] getReportCounts(HashMap<String, String> map, String[] list, int cnt) {
    int[] result = new int[cnt];
    for (String reporter : list) {
        int index = Integer.parseInt(map.get((reporter).split(" ")[1]));
        result[index] += 1;
    }
    return result;
}

 

4. 받은 메일 결과 반환
신고 내역을 취합한 기준으로 정지 기준 횟수가 해당되는 경우 메일 발송 대상자로 체크합니다.
그리고 각 유저가 몇 번의 메일을 받았는지 최종 결과로 반환해줍니다.
getMailCounts 함수로 기능을 구현했습니다.

public int[] solution(String[] id_list, String[] report, int k) {

    // 1. 아이디 리스트 정렬
    HashMap<String, String> map = setId(id_list);

    // 2. 신고 내역 중복 제거
    String[] list = Arrays.stream(report).distinct().toArray(String[]::new);

    // 3. 신고 내역 취합
    int[] reportCounts = getReportCounts(map, list, id_list.length);

    // 4. 받은 메일 결과 반환
    return getMailCounts(map, list, reportCounts, k);
}
public int[] getMailCounts(HashMap<String, String> map, String[] list, int[] reportCounts, int k) {
    int[] result = new int[reportCounts.length];
    for (String reporter : list) {
        int index = Integer.parseInt(map.get((reporter).split(" ")[1]));
        if (reportCounts[index] < k) continue;
        int answerIndex = Integer.parseInt(map.get((reporter).split(" ")[0]));
        result[answerIndex] += 1;
    }
    return result;
}

 

전체코드

public HashMap<String, String> setId(String[] id_list) {
    HashMap<String, String> map = new HashMap<>();
    for (int i = 0; i < id_list.length; i++) {
        map.put(i+"", id_list[i]);
        map.put(id_list[i], i+"");
    }
    return map;
}

public int[] getReportCounts(HashMap<String, String> map, String[] list, int cnt) {
    int[] result = new int[cnt];
    for (String reporter : list) {
        int index = Integer.parseInt(map.get((reporter).split(" ")[1]));
        result[index] += 1;
    }
    return result;
}

public int[] getMailCounts(HashMap<String, String> map, String[] list, int[] reportCounts, int k) {
    int[] result = new int[reportCounts.length];
    for (String reporter : list) {
        int index = Integer.parseInt(map.get((reporter).split(" ")[1]));
        if (reportCounts[index] < k) continue;
        int answerIndex = Integer.parseInt(map.get((reporter).split(" ")[0]));
        result[answerIndex] += 1;
    }
    return result;
}

public int[] solution(String[] id_list, String[] report, int k) {

    // 1. 아이디 리스트 정렬
    HashMap<String, String> map = setId(id_list);

    // 2. 신고 내역 중복 제거
    String[] list = Arrays.stream(report).distinct().toArray(String[]::new);

    // 3. 신고 내역 취합
    int[] reportCounts = getReportCounts(map, list, id_list.length);

    // 4. 받은 메일 결과 반환
    return getMailCounts(map, list, reportCounts, k);
}

 

후기

* 난이도 (5점 만점)

5 : 풀 줄 알면 기업 코딩 테스트는 문제없음.

4 : 평균적인 기업 코딩 테스트의 중간 이상.

3 : 평균적인 기업 코딩테스트의 쉬운 문제.

2 : 알고리즘 문제를 연습하고 있다면 풀 수 있는 문제.

1 : 시간이 오래 걸리지 않고, 누구나 풀 수 있는 문제.

 

[카카오 코딩 테스트 2022 신입 공채] 신고 결과 받기는 평균적인 기업 코딩테스트 문제로 보입니다.
난이도나 문제 유형이 코딩테스트를 볼 때 출제되는 문제와 흡사했습니다.
한 번 씩 풀어보시길 바랍니다.

링크

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

 

프로그래머스

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

programmers.co.kr

 

문제

 

풀이

1. 누적 입/출차 시간 계산
2. 출차된 내역 없는 차량 시간 계산
3. 차량 번호 정렬
4. 요금 정산

순서로 문제를 풀었습니다.
Int[] fees: 각 원소는 "기본 시간(분), 기본 요금(원), 단위 시간(분), 단위 요금(원)" 형식의 숫자입니다.
String[] records: 각 원소는 "시각, 차량번호, 내역" 형식의 문자열입니다.

 

1. 누적 입/출차 시간 계산
records 배열만큼 반복문을 이용했습니다.
split 함수를 이용하여 records 각 원소의  "시각, 차량번호, 내역"을 구분하였습니다.

// 1.누적 입/출차 시간 계산
for (String record : records) {
	String[] arr = record.split(" ");
    
}


parkingTime 이라는 함수를 만들어서 입/출차 시간을 계산했습니다.
record 매개변수는 각 원소의 "시각, 차량번호, 내역"을 순서대로 갖고 있기 때문에 
시각: time
차량번호: carNumber
내역: inOut
으로 분류했습니다.

내역이 IN 이면 Map에 해당 데이터를 저장하고
Out 이면 저장되어 있는 데이터를 꺼내서
IN 시간과 OUT 시간을 계산 후 누적 주차 시간을 구했습니다.

public void parkingTime(String[] record) {
    String time = record[0];
    String carNumber = record[1];
    String inOut = record[2];

    if ("IN".equals(inOut)) {
        parkingMap.put(carNumber, time);
        return;
    }

    int inTime = toMinutes(parkingMap.get(carNumber).split(":"));
    int outTime = toMinutes(time.split(":"));
    int useTime = outTime - inTime;

    parkingMap.remove(carNumber);
    if (resultMap.containsKey(carNumber)) {
        resultMap.put(carNumber, resultMap.get(carNumber) + useTime);
        return;
    }
    resultMap.put(carNumber, useTime);
}
// 1.누적 입/출차 시간 계산
for (String record : records) {
    String[] arr = record.split(" ");
    parkingTime(arr);
}


중복을 제외한 입차된 차량 수를 구하기 위해 Set을 이용하였습니다.
Set에 차량번호가 이미 있다면 카운트를 올리지 않고, 차량번호가 없을 경우만 카운트를 올립니다.

// 1.누적 입/출차 시간 계산
Set<String> car = new HashSet<>();
int cnt = 0;
for (String record : records) {
    String[] arr = record.split(" ");
    parkingTime(arr);
    if (car.contains(arr[1])) continue;
    car.add(arr[1]);
    cnt++;
}

 

2. 출차된 내역 없는 차량 시간 계산
records 배열에 있는 입/출차 시간을 계산 후 
아직 출차되지 않은 차가 있다면 23:59로 계산하여 출차시킵니다.
출차되지 않은 차량 기준은 내역이 IN 이면 Map에 해당 데이터를 저장하고 OUT이 없어서 꺼내지 못한 데이터입니다.
lastTime이라는 함수에  구현하였습니다.
parkingMap은 IN 데이터를 저장해놓은 HashMap입니다.

// 2.출차된 내역 없는 차량 시간 계산
for (Map.Entry<String, String> map : parkingMap.entrySet()) {
    lastTime(map.getKey(), map.getValue());
}
public void lastTime(String carNumber, String time) {

    int inTime = toMinutes(time.split(":"));
    int outTime = toMinutes("23:59".split(":"));
    int useTime = outTime - inTime;

    if (resultMap.containsKey(carNumber)) {
        resultMap.put(carNumber, resultMap.get(carNumber) + useTime);
        return;
    }
    resultMap.put(carNumber, useTime);
}

 

3. 차량 번호 정렬
입/출차 시간이 계산된 Map을 list로 변환하여 차량 번호 순서대로 정렬했습니다.
정렬하는 이유는 반환하는 차량 번호를 차량 번호 순서대로 해야 하기 때문입니다.

// 3.차량 번호 정렬
List<String> keyList = new ArrayList<>(resultMap.keySet());
Collections.sort(keyList);

 

4. 요금 정산
입/출차 시간이 계산된 데이터와 차량 번호 순서로 정렬되어 있으니
요금 정산 후 반환해주면 완료입니다.
반환할 배열을 생성합니다.
배열 수는 처음에 중복을 제외한 입차 된 차량 수를 담은 cnt라는 변수를 사용합니다.

int[] answer = new int[cnt];

반복문을 사용하여 차량 번호 순서로 요금 정산을 해줍니다.
요금 정산은 calculate라는 함수를 만들어서 계산했습니다.

// 4.요금 정산
int[] answer = new int[cnt];
int index = 0;
for (String key : keyList) {
    answer[index] = calculate(fees, resultMap.get(key));
    index++;
}

calculate의 매개변수는 fees(요금표)와 parkingTime(누적 주차 시간)을 받습니다.
만약 누적 주차 시간이 기본 이용 시간보다 적거나 같으면 기본 이용 요금을 지불합니다.
누적 주차 시간이 기본 이용 시간보다 많다면 기본 이용 시간을 제외 후 나머지 시간을 계산합니다.
단위 시간만큼 몫을 구하고 나머지 시간이 있다면 단위시간 1회 더 해당하는 것으로 간주합니다.

ex. 
단위 시간: 10분
단위 요금: 100원
이용시간: 11분
지불금액: 200원

public int calculate(int[] fees, int parkingTime) {
    int defaultTime = fees[0];
    int defaultPay = fees[1];
    int time = fees[2];
    int pay = fees[3];

    int useTime = parkingTime;

    if (defaultTime >= useTime) {
        return defaultPay;
    }

    useTime -= defaultTime;

    int quotient = useTime / time;

    if (quotient == 0) {
        quotient = 1;
        return defaultPay + (pay * quotient);
    }

    if (((quotient * time) - useTime) != 0) {
        quotient += 1;
    }

    return defaultPay + (pay * quotient);
}

 

전체 코드

HashMap<String, String> parkingMap = new HashMap<>();
HashMap<String, Integer> resultMap = new HashMap<>();
public int[] solution(int[] fees, String[] records) {

    // 1.누적 입/출차 시간 계산
    Set<String> car = new HashSet<>();
    int cnt = 0;
    for (String record : records) {
        String[] arr = record.split(" ");
        parkingTime(arr);
        if (car.contains(arr[1])) continue;
        car.add(arr[1]);
        cnt++;
    }

    // 2.출차된 내역 없는 차량 시간 계산
    for (Map.Entry<String, String> map : parkingMap.entrySet()) {
        lastTime(map.getKey(), map.getValue());
    }

    // 3.차량 번호 정렬
    List<String> keyList = new ArrayList<>(resultMap.keySet());
    Collections.sort(keyList);


    // 4.요금 정산
    int[] answer = new int[cnt];
    int index = 0;
    for (String key : keyList) {
        answer[index] = calculate(fees, resultMap.get(key));
        index++;
    }

    return answer;
}

public void parkingTime(String[] record) {
    String time = record[0];
    String carNumber = record[1];
    String inOut = record[2];

    if ("IN".equals(inOut)) {
        parkingMap.put(carNumber, time);
        return;
    }

    int inTime = toMinutes(parkingMap.get(carNumber).split(":"));
    int outTime = toMinutes(time.split(":"));
    int useTime = outTime - inTime;

    parkingMap.remove(carNumber);
    if (resultMap.containsKey(carNumber)) {
        resultMap.put(carNumber, resultMap.get(carNumber) + useTime);
        return;
    }
    resultMap.put(carNumber, useTime);
}

public int toMinutes(String[] time) {
    int hour = Integer.parseInt(time[0]) * 60;
    int minute = Integer.parseInt(time[1]);
    return hour + minute;
}

public void lastTime(String carNumber, String time) {

    int inTime = toMinutes(time.split(":"));
    int outTime = toMinutes("23:59".split(":"));
    int useTime = outTime - inTime;

    if (resultMap.containsKey(carNumber)) {
        resultMap.put(carNumber, resultMap.get(carNumber) + useTime);
        return;
    }
    resultMap.put(carNumber, useTime);
}

public int calculate(int[] fees, int parkingTime) {
    int defaultTime = fees[0];
    int defaultPay = fees[1];
    int time = fees[2];
    int pay = fees[3];

    int useTime = parkingTime;

    if (defaultTime >= useTime) {
        return defaultPay;
    }

    useTime -= defaultTime;

    int quotient = useTime / time;

    if (quotient == 0) {
        quotient = 1;
        return defaultPay + (pay * quotient);
    }

    if (((quotient * time) - useTime) != 0) {
        quotient += 1;
    }

    return defaultPay + (pay * quotient);
}

 

후기

* 난이도 (5점 만점)

5 : 풀 줄 알면 기업 코딩 테스트는 문제없음.

4 : 평균적인 기업 코딩 테스트의 중간 이상.

3 : 평균적인 기업 코딩테스트의 쉬운 문제.

2 : 알고리즘 문제를 연습하고 있다면 풀 수 있는 문제.

1 : 시간이 오래 걸리지 않고, 누구나 풀 수 있는 문제.

 

시간 계산(시, 분)에 대해 겁먹지 않는다면 차분하게 풀 수 있는 문제입니다.
감사합니다.

 

링크

https://programmers.co.kr/learn/courses/30/lessons/92335

 

코딩테스트 연습 - k진수에서 소수 개수 구하기

문제 설명 양의 정수 n이 주어집니다. 이 숫자를 k진수로 바꿨을 때, 변환된 수 안에 아래 조건에 맞는 소수(Prime number)가 몇 개인지 알아보려 합니다. 0P0처럼 소수 양쪽에 0이 있는 경우 P0처럼 소

programmers.co.kr

 

문제

 

 

풀이

 

-양의 정수 n이 주어집니다.
-이 숫자를 k진수로 바꿉니다.
-변환된 수 안에 아래 조건에 맞는 소수(Prime number)가 몇 개인지 봅니다.

  • 0P0처럼 소수 양쪽에 0이 있는 경우
  • P0처럼 소수 오른쪽에만 0이 있고 왼쪽에는 아무것도 없는 경우
  • 0P처럼 소수 왼쪽에만 0이 있고 오른쪽에는 아무것도 없는 경우
  • P처럼 소수 양쪽에 아무것도 없는 경우
  • 단, P는 각 자릿수에 0을 포함하지 않는 소수입니다.
    • 예를 들어, 101은 P가 될 수 없습니다.

 

1. 양의 정수 n이 주어집니다.

첫 번째 n: 437674
두 번째 n: 110011

 

2. 이 숫자를 k진수로 바꿉니다.

첫 번째 k: 3
첫 번째 n을 첫 번째 k진수로 바꿉니다.
-> 437674를 3진수로 바꿉니다.

두 번째 k: 10
두 번째 n을 두 번째 k진수로 바꿉니다.
-> 11001110진수로 바꿉니다.

 

3. 변환된 수 안에 아래 조건에 맞는 소수(Prime number)가 몇 개인지 봅니다.

  • 0P0처럼 소수 양쪽에 0이 있는 경우
  • P0처럼 소수 오른쪽에만 0이 있고 왼쪽에는 아무것도 없는 경우
  • 0P처럼 소수 왼쪽에만 0이 있고 오른쪽에는 아무것도 없는 경우
  • P처럼 소수 양쪽에 아무것도 없는 경우
  • 단, P는 각 자릿수에 0을 포함하지 않는 소수입니다.
    • 예를 들어, 101은 P가 될 수 없습니다.

0을 기준으로 숫자를 나눠서 해당 숫자가 소수인지 판별하는 방법입니다.

 

첫 번째 n인 437674를 3진수로 변환하면 211020101011입니다.
211020101011의 경우는 211020101011 0을 기준으로 211, 2, 1, 1, 11 총 5개의 수가 나옵니다.

첫 번째 211은 소수입니다.
두 번째 2는 소수입니다.
세 번째 1은 소수가 아닙니다.
네 번째 1은 소수가 아닙니다.
다섯 번째 11은 소수입니다.
그러므로 211020101011의 5개 의 숫자 중 3개의 소수가 있습니다.

위의 입출력 예와 같이 437674를 3진수로 변환 후 소수를 구했을 때 답은 3이 나옵니다.

두 번째 n인 110011를 10진수로 변환하면 110011입니다.
110011의 경우는 110011 양 쪽 11과 11이 조건에 맞는 수 입니다
첫 번째 11은 소수입니다.
두 번째 11은 소수입니다.
그러므로 110011의 양 쪽에 소수가 하나씩 있으므로 총 2개의 소수가 있습니다.

위의 입출력 예와 같이 110011를 10진수로 변환 후 소수를 구했을 때 답은 2가 나옵니다.

 


 

문제 풀이 방법은 위와 같은 순서로 진행될 것입니다.

1. 소수 합계를 반환해줄 answer가 있습니다.
2. 양의 정수 n을 k진수로 변환합니다.
3.k진수로 변환된 n의 소수 합계를 구합니다.
4. 소수 합계를 반환합니다.

import java.util.StringTokenizer;
class Solution {
    
    // 정수 n이 소수인지 판별하는 함수
    public boolean isPrime(Long n) {
        if (n < 2) return false;
        if (n == 2) return true;
        for (int i = 2; i <= Math.sqrt(n); i++) if(n % i == 0) return false;
        return true;
    }

    // 정수 n을 k진수로 변환하는 함수
    public Long toEverynary (int n, int k) {
        return Long.parseLong(Integer.toString(n,k));
    }
    
    public int solution(int n, int k) {
        int answer = 0;// 소수 합계
        
        // toEverynary 함수는 의 정수 n을 k진수로 변환합니다. 
        // StringTokenizer를 "0"으로 구분하여 생성하면 0 을 제외한 값으로만 값이 생성됩니다.
        // 만약 split("0")으로 처리한다면 0이 연속으로 나오는 0000 의 경우 빈 공백의 배열이 생성될 것입니다.
        StringTokenizer token = new StringTokenizer(Long.toString(toEverynary(n, k)), "0");
        
        // token안에 담긴 수 만큼 반복문을 실행하여 해당 수가 소수인지 판별 후 소수인 경우만 소수 합계에 더해줍니다.
        while (token.countTokens() > 0) {
            if (isPrime(Long.parseLong(token.nextToken()))) answer++;
        }
        return answer;// 소수 합계를 반환합니다.
    }
}

 

주석 없는 버전

import java.util.StringTokenizer;
class Solution {
    public boolean isPrime(Long n) {
        if (n < 2) return false;
        if (n == 2) return true;
        for (int i = 2; i <= Math.sqrt(n); i++) if (n % i == 0) return false;
        return true;
    }

    public Long toEverynary (int n, int k) {
        return Long.parseLong(Integer.toString(n,k));
    }
    
    public int solution(int n, int k) {
        int answer = 0;
        StringTokenizer token = new StringTokenizer(Long.toString(toEverynary(n, k)), "0");
        while (token.countTokens() > 0) {
            if (isPrime(Long.parseLong(token.nextToken()))) answer++;
        }
        return answer;
    }
}

 


 

후기

* 난이도 (5점 만점)

5 : 풀 줄 알면 기업 코딩 테스트는 문제없음.

4 : 평균적인 기업 코딩 테스트의 중간 이상.

3 : 평균적인 기업 코딩테스트의 쉬운 문제.

2 : 알고리즘 문제를 연습하고 있다면 풀 수 있는 문제.

1 : 시간이 오래 걸리지 않고, 누구나 풀 수 있는 문제.

 

이 문제는 "k진수"라는 단어와 "소수 판별"이라는 단어에 겁먹지 않는다면 충분히 풀 수 있는 문제입니다.
문제를 풀 때 한 번에 모든 것을 해결하려 하지 말고 단계 별로 풀이를 정해서 차근차근 풀어나간다면 어렵지 않은 문제입니다.

 

+ Recent posts