링크

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://school.programmers.co.kr/learn/courses/30/lessons/72410

 

프로그래머스

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

programmers.co.kr

 

문제

 

1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.
6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
     만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.
7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙입니다.

 

풀이

 

1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.
6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
     만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.
7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙입니다.

위의 내용을 하나씩 적용합니다.

1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.

public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();
       
        return new_id;
}

 

toLowerCase 함수는 모든 대문자를 대응되는 소문자로 치환해주는 함수입니다.
new_id에 toLowerCase 함수를 사용하여 모든 대문자를 대응되는 소문자로 치환해줍니다.

 

2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.

public String emptyWord(String str) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (47 < c && c < 58) {
                sb.append(c);
                continue;
            }
            if (96 < c && c < 123) {
                sb.append(c);
                continue;
            }
            if ('-' == c || '_' == c || '.' == c) {
                sb.append(c);
                continue;
            }
        }
        return sb.toString();
}

알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
필자는 replace, replaceAll 함수로 특정 문자를 제거하는 것이 아닌
반복문을 사용하여 조건에 해당하는 것만 선별 후 리턴하였습니다.
아스키코드 48 ~ 57은 0~9에 해당하는 값입니다.
아스키코드 97 ~ 122는 알파벳 소문자 a~z에 해당하는 값입니다.
그리고 빼기(-), 밑줄(_), 마침표(.)는 각 char형으로 비교하였습니다.

public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();

        //2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
        new_id = emptyWord(new_id);

        return new_id;
}

 

3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.

public String closeCheck(String str) {
        StringBuffer sb = new StringBuffer();
        boolean flag = false;
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if ('.' == c) {
                if (flag) {
                    continue;
                }
                sb.append(c);
                flag = true;
                continue;
            }
            sb.append(c);
            flag = false;
        }
        return sb.toString();
}

반복문을 사용했습니다.
마침표(.)가 나왔을 때는 flag = true 로 설정하여 바로 다음 문자가 마침표(.)일 경우 
문자를 담지 않고 현재 반복문을 종료 후 다음 반복문을 수행했습니다.
마침표(.) 외의 문자가 나왔을 때는 flag = false로 설정하고
문자를 담은 후 현재 반복문을 종료하고 다음 반복문을 수행했습니다.
결과적으로 마침표(.)가 중복되서 나오는 경우는 최초 1회만 담게 되고
나머지 문자들은 손실 없이 그대로 담기게 됩니다.

ex)  aa...bb  ->  aa.bb 

public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();

        //2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
        new_id = emptyWord(new_id);

        //3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
        new_id = closeCheck(new_id);

        return new_id;
}

 

4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.

public String startEndCheck(String str) {
        if (str.startsWith(".")) {
            str = str.substring(1);
        }
        if (str.endsWith(".")) {
            str = str.substring(0, str.length()-1);
        }
        return str;
}

startWith, endsWith 함수를 사용하여 처음이나 끝에 마침표(.)가 있다면 
substring을 이용하여 해당 위치의 문자를 잘라내었습니다.

ex)
String str = ".aaaa.";
str = str.substring(1); // "aaaa."
str = str.substring(0, str.length()-1); //"aaaa"

public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();

        //2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
        new_id = emptyWord(new_id);

        //3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
        new_id = closeCheck(new_id);

        //4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
        new_id = startEndCheck(new_id);

        return new_id;
}

 

5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.

new_id = ("".equals(new_id)) ? "a" : new_id;

필자는 삼항연산자를 이용하여 new_id가 빈 문자열이라면 "a"를 대입하고 아니라면 new_id를 그대로 사용하였습니다.

public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();

        //2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
        new_id = emptyWord(new_id);

        //3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
        new_id = closeCheck(new_id);

        //4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
        new_id = startEndCheck(new_id);

        //5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.
        new_id = ("".equals(new_id)) ? "a" : new_id;

        return new_id;
}

 

6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.

new_id = (new_id.length() >= 16) ? new_id.substring(0, 15) : new_id;

new_id = startEndCheck(new_id);

new_id의 길이가 16자 이상이라면, new_id 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거하는 부분은
삼항연산자로 처리하였습니다.
그리고 만약 제거 후 마침표(.)가 new_id의 끝에 위치했을 때 제거하는 기능은
4단계에서 만들어 놓은 startEndCheck(); 함수를 사용하였습니다.
마침표를 제거한다 라는 역할과 책임을 분리하여 기능을 만들었기 때문에 재사용이 가능했습니다.

public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();

        //2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
        new_id = emptyWord(new_id);

        //3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
        new_id = closeCheck(new_id);

        //4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
        new_id = startEndCheck(new_id);

        //5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.
        new_id = ("".equals(new_id)) ? "a" : new_id;

        //6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
        new_id = (new_id.length() >= 16) ? new_id.substring(0, 15) : new_id;

        //만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.
        new_id = startEndCheck(new_id);

        return new_id;
}

 

7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙입니다.

public String treeWordCheck(String str) {
        if (str.length() > 2) return str;

        str = str + str.substring(str.length()-1);

        return (str.length() > 2) ? str : str + str.substring(str.length()-1);
}

new_id 길이가 3이 될 때까지가 조건이니 길이 3이상인 문자는 바로 리턴했습니다.
길이 3이상이 아닌 문자의 경우 마지막 글자를 더한 후
다시 길이가 3이상인 문자인지 체크하였고
3이 아니면 마지막 글자를 다시 더한 후 리턴했습니다.

ex)
1. 길이가 3 이상인 경우
바로 리턴.

2. 길이가 2인 경우
"ab" -> 마지막 글자 더하기 -> "abb" -> 길이가 3이상 -> 리턴

3. 길이가 1인 경우
"a" -> 마지막 글자 더하기 -> "aa" -> 마지막 글자 더하기 -> "aaa" -> 길이가 3이상 -> 리턴

4. 길이가 0인 경우
없음 (해당 단계는 7단계입니다. 빈 문자열의 경우 5단계에서 "a"로 치환해줍니다.)

마지막 글자를 더해야 하는 경우는 길이가 1이나 2의 경우입니다.
반복문을 사용하여 처리해도 되지만
최대 2회까지만 마지막 글자를 더해주면 돼서
복잡하게 반복문을 사용하지 않고 처리하였습니다.

public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();

        //2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
        new_id = emptyWord(new_id);

        //3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
        new_id = closeCheck(new_id);

        //4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
        new_id = startEndCheck(new_id);

        //5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.
        new_id = ("".equals(new_id)) ? "a" : new_id;

        //6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
        new_id = (new_id.length() >= 16) ? new_id.substring(0, 15) : new_id;

        //만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.
        new_id = startEndCheck(new_id);

        //7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙입니다.
        new_id = treeWordCheck(new_id);

        return new_id;
}

 

전체 코드

    public String emptyWord(String str) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (47 < c && c < 58) {
                sb.append(c);
                continue;
            }
            if (96 < c && c < 123) {
                sb.append(c);
                continue;
            }
            if ('-' == c || '_' == c || '.' == c) {
                sb.append(c);
                continue;
            }
        }
        return sb.toString();
    }

    public String closeCheck(String str) {
        StringBuffer sb = new StringBuffer();
        boolean flag = false;
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if ('.' == c) {
                if (flag) {
                    continue;
                }
                sb.append(c);
                flag = true;
                continue;
            }
            sb.append(c);
            flag = false;
        }
        return sb.toString();
    }

    public String startEndCheck(String str) {
        if (str.startsWith(".")) {
            str = str.substring(1);
        }
        if (str.endsWith(".")) {
            str = str.substring(0, str.length()-1);
        }
        return str;
    }

    public String treeWordCheck(String str) {
        if (str.length() > 2) return str;

        str = str + str.substring(str.length()-1);

        return (str.length() > 2) ? str : str + str.substring(str.length()-1);
    }

    public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();

        //2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
        new_id = emptyWord(new_id);

        //3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
        new_id = closeCheck(new_id);

        //4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
        new_id = startEndCheck(new_id);

        //5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.
        new_id = ("".equals(new_id)) ? "a" : new_id;

        //6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
        new_id = (new_id.length() >= 16) ? new_id.substring(0, 15) : new_id;

        //만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.
        new_id = startEndCheck(new_id);

        //7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙입니다.
        new_id = treeWordCheck(new_id);

        return new_id;
    }

 

실행결과

 

후기

* 난이도 (5점 만점)

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

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

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

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

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

 

정답률 57.50% 에 비해 문제가 어렵지 않았다.
이미 문제에서 1~7단계 설명으로 답을 해설해주었기 때문에 쉽게 풀 수 있었다.
단계별로 하나씩 적용하면 코딩테스트 입문자도 풀 수 있는 문제입니다.
감사합니다.

 

링크

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

 

 

링크

 

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

 

코딩테스트 연습 - [1차] 캐시

3 ["Jeju", "Pangyo", "Seoul", "NewYork", "LA", "Jeju", "Pangyo", "Seoul", "NewYork", "LA"] 50 3 ["Jeju", "Pangyo", "Seoul", "Jeju", "Pangyo", "Seoul", "Jeju", "Pangyo", "Seoul"] 21 2 ["Jeju", "Pangyo", "Seoul", "NewYork", "LA", "SanFrancisco", "Seoul", "Ro

programmers.co.kr

 

문제

 


 

풀이

 

  • 캐시 교체 알고리즘은 LRU(Least Recently Used)를 사용한다.
  • cache hit일 경우 실행시간은 1이다.
  • cache miss일 경우 실행시간은 5이다.

 

1. 캐시 교체 알고리즘은 LRU(Least Recently Used)를 사용한다.

LRU 알고리즘은 사용된 데이터의 경우 제거 후 순위로 변경해준다.

A, B, C, D 라는 문자가 차례대로 들어온 후

캐시에서 제거될 때 A, B, C, D 순서로 제거된다.

E 문자열 삽입

A는 제거되고 그 뒤에 있던 B가 다음 제거 타겟이다. 

 

여기에서 중간에 있는 C를 요청받으면

이미 C가 존재하기 때문에 제거되는 데이터는 없다.

하지만 순서가 바뀐다.

B 다음으로 C가 제거 타겟이였지만 

C가 새로 들어온 신입처럼 후순위로 배치된다.

이것이 LRU 알고리즘이다.

 

2. cache hit일 경우 실행시간은 1이다.

데이터가 들어왔을 때 캐시에 존재하는 데이터면 +1

 

3. cache miss일 경우 실행시간은 5이다.

데이터가 들어왔을 때 캐시에 없는 데이터면 +5


 

캐시 사이즈 : 3

*대소문자를 구분하지 않기 때문에 일괄적으로 대문자로 변환하여 비교하였습니다.

 

데이터 ["Jeju", "Pangyo", "Seoul", "NewYork", "LA"]

JEJU 는 캐시에 없는 데이터 

캐시 [JEJU]

수행 시간(0) : +5

 

데이터 ["Pangyo", "Seoul", "NewYork", "LA"]

PANGYO 는 캐시에 없는 데이터

캐시 [JEJU, PANGYO]

수행 시간(5) : +5

 

데이터 ["Seoul", "NewYork", "LA"]

SEOUL 은 캐시에 없는 데이터

캐시 [JEJU, PANGYO, SEOUL]

수행 시간(10) : +5

 

데이터 ["NewYork", "LA"]

NEWYORK 은 캐시에 없는 데이터

캐시 사이즈에 자리가 없기 때문에 제일 먼저 들어온 데이터 제거 후 삽입

[JEJU, PANGYO, SEOUL] 

[PANGYO, SEOUL] 

[PANGYO, SEOUL, NEWYORK

수행 시간(15) : +5

 

데이터 ["LA"]

LA 는 캐시에 없는 데이터

캐시 사이즈에 자리가 없기 때문에 제일 먼저 들어온 데이터 제거 후 삽입

[PANGYO, SEOUL, NEWYORK] 

[SEOUL, NEWYORK] 

[SEOUL, NEWYORK, LA

수행 시간(20) : +5

 

총 수행 시간 : 25초

 


 

위의 로직 구현

 

import java.util.LinkedList;
import java.util.Queue;

class Solution {
	
	/**
	 * 카카오 캐시
	 * @param cacheSize
	 * @param cities
	 * @return
	*/
	public int solution(int cacheSize, String[] cities) {
		int answer 		= 0;
		int count 		= cities.length;
		Queue<String> qu	= new LinkedList<>();
		
		for (int i = 0; i < count; ++i) {
			String str = cities[i].toLowerCase();
			
			// 캐시 사이즈가 0일 경우 밑의 로직 수행 X -> 수행 시간 +5
			if (0 == cacheSize) {
				answer += 5;
				continue;
			}
            
			// 캐시에 존재하는 데이터면 순서 변경 후 수행 시간 +1
			if (qu.contains(str)) {
				qu.remove(str);
				qu.add(str);
				++answer;
				continue;
			}
			
			// 캐시 사이즈에 자리가 없을 경우 먼저 들어온 데이터 제거 후 삽입 수행 시간 +5
			if (qu.size() >= cacheSize) {
				qu.poll();
				qu.add(str);
				answer += 5;
				continue;
			}
            
			// 그 외 캐시에 삽입 후 수행 시간 +5
			qu.add(str);
			answer += 5;
		}
		return answer;
	}
}

 


 

후기

* 난이도 (5점 만점)

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

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

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

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

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

 

난이도는 생각보다 쉬운 편이었으며 LRU 알고리즘을 이해한다면 충분히 풀 수 있다.

LRU 알고리즘을 풀기 위해 자료구조 Queue 를 사용했고 어려운 기술은 없었다.

 

 

링크

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

 

코딩테스트 연습 - [1차] 다트 게임

 

programmers.co.kr


 

문제

 


풀이
  1. 다트 게임은 총 3번의 기회로 구성된다.
  2. 각 기회마다 얻을 수 있는 점수는 0점에서 10점까지이다.
  3. 점수와 함께 Single(S), Double(D), Triple(T) 영역이 존재하고 각 영역 당첨 시 점수에서 1제곱, 2제곱, 3제곱 (점수1 , 점수2 , 점수3 )으로 계산된다.
  4. 옵션으로 스타상(*) , 아차상(#)이 존재하며 스타상(*) 당첨 시 해당 점수와 바로 전에 얻은 점수를 각 2배로 만든다. 아차상(#) 당첨 시 해당 점수는 마이너스된다.
  5. 스타상(*)은 첫 번째 기회에서도 나올 수 있다. 이 경우 첫 번째 스타상(*)의 점수만 2배가 된다. (예제 4번 참고)
  6. 스타상(*)의 효과는 다른 스타상(*)의 효과와 중첩될 수 있다. 이 경우 중첩된 스타상(*) 점수는 4배가 된다. (예제 4번 참고)
  7. 스타상(*)의 효과는 아차상(#)의 효과와 중첩될 수 있다. 이 경우 중첩된 아차상(#)의 점수는 -2배가 된다. (예제 5번 참고)
  8. Single(S), Double(D), Triple(T)은 점수마다 하나씩 존재한다.
  9. 스타상(*), 아차상(#)은 점수마다 둘 중 하나만 존재할 수 있으며, 존재하지 않을 수도 있다.

 

조건을 하나씩 적용하겠습니다.

1. 다트 게임은 총 3번의 기회로 구성된다.

총 3개의 값을 구합니다.

 

2. 각 기회마다 얻을 수 있는 점수는 0점에서 10점까지이다.

입력 받는 점수 범위는 0~10 입니다.

 

3. 점수와 함께 Single(S), Double(D), Triple(T) 영역이 존재하고 각 영역 당첨 시 점수에서 1제곱, 2제곱, 3제곱 (점수1 , 점수2 , 점수3 )으로 계산된다.

S : 1제곱 

D : 2제곱

T : 3제곱

 

4. 옵션으로 스타상(*) , 아차상(#)이 존재하며 스타상(*) 당첨 시 해당 점수와 바로 전에 얻은 점수를 각 2배로 만든다. 아차상(#) 당첨 시 해당 점수는 마이너스된다.

* : 현재 점수, 이전 점수 X 2

# : 현재 점수 X (-1)

 

5. 스타상(*)은 첫 번째 기회에서도 나올 수 있다. 이 경우 첫 번째 스타상(*)의 점수만 2배가 된다.

* : 이전 점수가 없다면 현재 점수만 X 2

 

6. 스타상(*)의 효과는 다른 스타상(*)의 효과와 중첩될 수 있다. 이 경우 중첩된 스타상(*) 점수는 4배가 된다.

4, 5번 조건을 적용해주면 6번도 해결됩니다.

 

7. 스타상(*)의 효과는 아차상(#)의 효과와 중첩될 수 있다. 이 경우 중첩된 아차상(#)의 점수는 -2배가 된다.

4, 5번 조건을 적용해주면 7번도 해결됩니다.

 

8. Single(S), Double(D), Triple(T)은 점수마다 하나씩 존재한다.

3번의 다트 점수 중 S, D, T 은 하나씩 존재하므로 중복 체크 없이 구현하면 됩니다.

 

9. 스타상(*), 아차상(#)은 점수마다 둘 중 하나만 존재할 수 있으며, 존재하지 않을 수도 있다.

3번의 다트 점수 중 *, # 조건이 있을때 적용하면 됩니다.


위의 설명대로 하나씩 구현하면 됩니다.

dartResult : 1S2D*3T

받은 dart 값을 나눠보면

1S

2D* (현재 점수와 이전 점수 X 2) -> 위의 1S도 X 2 

3T

이렇게 볼 수 있고

1^1 * 2

2^2 * 2

3^3

이렇게 완성됩니다.

반환은 3개 점수 합 입니다.


 

위의 로직 구현

class Solution {
	
	/**
	 * 카카오 다트 게임
	 * @param dartResult
	 * @return
	*/
	public int solution(String dartResult) {

		int count	= dartResult.length();
		int bonus 	= 0;
 		int[] arr 	= new int[3];
		int arrCnt 	= 0;
		for (int i = 0; i < count; ++i) {
			char ch =  dartResult.charAt(i);
			if (ch == 49) {
 				if (dartResult.charAt(i+1) == 48) {
					ch = 58;
					++i;
				}
			}
    		
			//옵션 로직
			switch(ch) {
			case '*':
				arr[arrCnt-1] *= 2;
				if (arrCnt-1 > 0) arr[arrCnt-2] *= 2;
				continue;
			case '#':
				arr[arrCnt-1] *= (-1);
				continue;
			}
    		
			//제곱 로직
			switch(dartResult.charAt(i+1)) {
			case 'S':
				bonus = 1;
				break;
			case 'D':
				bonus = 2;
				break;
			case 'T':
				bonus = 3;
				break;
			}
    		
			arr[arrCnt] = (int) Math.round(Math.pow(ch-'0', bonus));
			++arrCnt;
			++i;
		}
		return arr[0]+arr[1]+arr[2];
	}  
}


후기

* 난이도 (5점 만점)

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

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

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

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

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

 

난이도는 생각보다 쉬운 편이었으며 문제를 이해하고 천천히 풀면 충분히 풀 수 있다.

어려운 기술이 들어간 것은 없고, 말 그대로 문제 내용을 하나씩 구현한 것이다.

 

 

링크

 

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

 

코딩테스트 연습 - [1차] 비밀지도

비밀지도 네오는 평소 프로도가 비상금을 숨겨놓는 장소를 알려줄 비밀지도를 손에 넣었다. 그런데 이 비밀지도는 숫자로 암호화되어 있어 위치를 확인하기 위해서는 암호를 해독해야 한다. 다

programmers.co.kr


 

문제

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

풀이

 

n = 5

arr1 = [9, 20, 28, 18, 11]

arr2 = [30, 1, 21, 17, 28]

배열의 값을 2진수로 변환 후 지도에 표시

2진수는 1과 0으로 구성.

1과 0은 각각 지도 표기 방법으로 바꿔준다.

1 = "#"

0 = " "  (공백)

 

9를 2진수로 변환하면 1001 라는 값이 나온다.

 

20을 2진수로 변환하면 10100

 

위의 9와 20을 2진수로 변환한 값을 보면 자릿수가 다르다.

자릿수를 맞춰주기 위해서는 처음에 받은 n 만큼 자릿수를 채워준다.

그럼 밑의 내용처럼 9를 2진수로 변환한 내용도 바뀐다. 

1001 -> 01001

위의 내용대로 arr1 의 값을 2진수로 모두 변환시키면

arr1 = [9, 20, 28, 18, 11]

이렇게 된다.

이 것을 지도로 변환시키면

이렇게 표기가 된다.

 

 

arr2도 2진수로 변환

arr2 = [30, 1, 21, 17, 28]

이렇게 된다.

이 것을 지도로 변환시키면

이렇게 표기된다.

 

그럼 arr1 지도와 arr2 지도의 # 부분을 합집합으로 보여주면 된다.

비밀지도가 완성되었다.

return 방식은 String 배열에 담아서 해준다.

["#####","# # #", "### #", "# ##", "#####"]

 

 


 

위의 로직 구현

 

class Solution {
    
	/**
	 * 각 배열의 지도 합치기
	 * @param str1
	 * @param str2
	 * @param n
	 * @return
	*/
	public String sumArr(String str1, String str2, int n) {
		StringBuilder sb = new StringBuilder(); 
		for (int i = 0; i < n; ++i) {
			sb.append(((str1.charAt(i) + str2.charAt(i)) == 96)? " ":"#");
		}
		return sb.toString();
	}
	
	/**
	 * 각 배열의 자릿수 채워주기
	 * @param str
	 * @param n
	 * @return
	*/
	public String lpad(String str, int n) {
		int size		= n - str.length();
		StringBuilder sb	= new StringBuilder();
		for (int i = 0; i < size; ++i) {
			sb.append("0");
		}
		return sb.toString()+str;
	}
    
	/**
	 * 카카오 비밀지도
	 * @param n
	 * @param arr1
	 * @param arr2
	 * @return
	*/
	public String[] solution(int n, int[] arr1, int[] arr2) {
		int arrCount	= arr1.length;
		String[] arrStr	= new String[arrCount];
		String[] answer	= new String[arrCount];
        
		for (int i = 0; i < arrCount; ++i) {
			String str		= lpad(Integer.toBinaryString(arr1[i]), n);
			StringBuilder sb	= new StringBuilder();
			for (int j = 0; j < str.length(); ++j) {
				sb.append(str.charAt(j));
			}
			arrStr[i] = sb.toString();
		}
		
		for (int i = 0; i < arrCount; ++i) {
			String str	= lpad(Integer.toBinaryString(arr2[i]), n);
			answer[i]	= sumArr(arrStr[i], str, n);
		}
		return answer;
	}
}


 

후기

* 난이도 (5점 만점)

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

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

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

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

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

 

난이도는 생각보다 쉬운 편이었으며 문제를 이해하고 천천히 풀면 충분히 풀 수 있다.

어려운 기술이 들어간 것은 없고, 말 그대로 문제 내용을 하나씩 구현한 것이다.

+ Recent posts