[TIL] Algorithm 12문제

Jay Mild Lee·2022년 11월 18일
0

TIL

목록 보기
5/7
post-thumbnail

I. Algorithm

1. 2016년(윤년 문제)

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

1) 문제 설명

2016년 1월 1일은 금요일입니다. 2016년 a월 b일은 무슨 요일일까요? 두 수 a ,b를 입력받아 2016년 a월 b일이 무슨 요일인지 리턴하는 함수, solution을 완성하세요. 요일의 이름은 일요일부터 토요일까지 각각 SUN,MON,TUE,WED,THU,FRI,SAT 입니다. 예를 들어 a=5, b=24라면 5월 24일은 화요일이므로 문자열 "TUE"를 반환하세요.

2) 제한 사항

  • 2016년은 윤년입니다.
  • 2016년 a월 b일은 실제로 있는 날입니다.

3) 풀이

요일은 일요일부터 월요일까지 반복되기 때문에, 나머지 연산자를 사용하는 것이 주요했다. 월 별로 1일이 무슨 요일인지 먼저 연산한 후, 입력 값으로 주어진 날짜에 맞는 요일을 찾아내는 것으로 방향을 잡았다.

결론적으로 다음과 같이 진행했다.
1) FRI ~ THU 순서로 요일을 저장한 배열을 만든다.(1월 1일이 목요일이기 때문)
2) 월 별로 일 수를 저장한 배열을 만든다.
3) 월 별로 1일의 요일을 저장한 배열을 만든다.
4) 입력으로 주어진 요일과 1일의 날짜 차이를 계산하고, 요일을 리턴한다.

4) 소스 코드

        String answer = "";
        String[] days = {"FRI", "SAT", "SUN", "MON", "TUE", "WED", "THU"};
        int[] count_days = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        int[] first_days = new int[12];
        first_days[0] = 0;
        for (int i = 1; i < first_days.length; i++) {
            first_days[i] = ((count_days[i-1]%7) + first_days[i-1])%7;
        }
        int distance = (b - 1) % 7;
        int answer_index = (distance + first_days[a-1])%7;
        answer = days[answer_index];

        return answer;

2. 나누어 떨어지는 숫자 배열

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

1) 문제 설명

array의 각 element 중 divisor로 나누어 떨어지는 값을 오름차순으로 정렬한 배열을 반환하는 함수, solution을 작성해주세요. divisor로 나누어 떨어지는 element가 하나도 없다면 배열에 -1을 담아 반환하세요.

2) 제한 사항

  • arr은 자연수를 담은 배열입니다.
  • 정수 i, j에 대해 i ≠ j 이면 arr[i] ≠ arr[j] 입니다.
  • divisor는 자연수입니다.
  • array는 길이 1 이상인 배열입니다.

3) 풀이

주어진 divisor로 나누어 떨어지는 원소들을 확인하고, 해당 원소들을 오름차순으로 정렬하는 간단한 문제였다. ArrayList 사용에 초점을 맞춰 풀었다.

결론적으로 다음과 같이 진행했다.
1) List<Integer> mallocArray = new ArrayList<>();을 통해 ArrayList 생성

  • *ArrayList는 배열의 크기를 동적으로 처리해준다.

2) 조건에 부합하는 원소들을 ArrayList mallocArray에 추가
3) mallocArray.sort(Comparator.naturalOrder());를 통해 정렬

  • 내림차순 정렬 : List.sort(Comparator.reverseOrder());

4) 소스 코드

    static public int[] solution(int[] arr, int divisor) {
        int[] answer = {};
        boolean flag = false;
        List<Integer> mallocArray = new ArrayList<>();

        for (int i = 0; i < arr.length; i++) {
            int tmp = arr[i] % divisor;
            if (tmp == 0){
                mallocArray.add(arr[i]);
                flag = true;
            }
        }
        if (flag == false){
            answer = new int[1];
            answer[0] = -1;
            return answer;
        }
        mallocArray.sort(Comparator.naturalOrder());

        answer = new int[mallocArray.size()];
        for (int i = 0; i < answer.length; i++) {
            answer[i] = mallocArray.get(i);
        }

        return answer;
    }

3. 수박수박수박수?

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

1) 문제 설명

길이가 n이고, "수박수박수박수...."와 같은 패턴을 유지하는 문자열을 리턴하는 함수, solution을 완성하세요. 예를들어 n이 4이면 "수박수박"을 리턴하고 3이라면 "수박수"를 리턴하면 됩니다.

2) 제한 사항

  • n은 길이 10,000이하인 자연수입니다.

3) 풀이

n까지 for문을 돌면서 i가 짝수일 때 수, 홀수일 때 박을 비어있는 String 값에 더했다.

1) if 문을 이용, 2로 나눈 나머지를 확인 해 짝수, 홀수를 구분
2) String.concat("Str")을 이용해 String을 구성

4) 소스 코드

public class Solution {
    static public String solution(int n) {
        String answer = "";
        for (int i = 0; i < n; i++) {
            if (i%2 == 1){
                answer = answer.concat("박");
            }
            else{
                answer = answer.concat("수");
            }
        }

        return answer;
    }
}

4. 💡 완주하지 못한 선수 💡

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

1) 문제 설명

수많은 마라톤 선수들이 마라톤에 참여하였습니다. 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.

마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.

2) 제한 사항

  • 마라톤 경기에 참여한 선수의 수는 1명 이상 100,000명 이하입니다.
  • completion의 길이는 participant의 길이보다 1 작습니다.
  • 참가자의 이름은 1개 이상 20개 이하의 알파벳 소문자로 이루어져 있습니다.
  • 참가자 중에는 동명이인이 있을 수 있습니다.

3) 풀이

처음에는 완전 탐색으로 풀이를 시도했다. 참여한 선수와 완주한 선수의 배열을 각각 만들고, 완주한 선수 배열을 기준으로 참여한 선수 배열과 일치 여부를 확인했다. 기능에는 문제가 없었지만, 시간 복잡도(효율성) 부분에서 부족했다. 확인 과정에서 2중 for문을 사용한 것이 원인이었고, 해쉬를 통해 다시 한번 풀어봤다.

<String, Integer>를 저장할 해쉬맵을 만들고, String에는 참가자의 이름을, Integer에는 1을 저장한다. 이 때 동명이인이 있을 경우에는, Integer에 +1이 더 되도록 한다. 모든 참가자의 정보를 저장한 이후에는, 완주한 선수의 이름과 일치하는 Key의 Value를 -1한다. 이후 해쉬맵에 value가 0이 아닌 선수가 있을 경우, 해당 선수가 완주하지 못한 인원이다.

결론적으로 다음과 같이 진행했다.
1) Hashmap check을 생성한다.
2) check의 Key에 배열participant에 담긴 참가 선수의 이름을 넣는다. 이 때, check.put(marathoner, check.getOrDefault(marathoner, 0) + 1);를 사용함으로써, Value에 1을 더해 넣는다. (default는 0)
3) check.put(marathoner, check.get(marathoner) -1);를 통해, 배열completion과 일치하는 Key들의 Value를 -1 한다.
4) Hashmap의 value에 따라, key 확인하기 위해 Set<Map.Entry<String, Integer>> entrySet = check.entrySet();를 통해 entrySet 객체를 리턴한다.
5) for 문에서 entry 객체 중, entry.getValue()를 통해 value가 0이 아닌 값을 확인한다.
6) entry.getKey()를 통해 해당 객체의 Key를 확인한다.

4) 소스 코드

    static public String solution(String[] participant, String[] completion) {
        String answer = "";
        HashMap<String, Integer> check =  new HashMap<>();
        for (String marathoner : participant){
            check.put(marathoner, check.getOrDefault(marathoner, 0) + 1);
        }
        for (String marathoner : completion){
            check.put(marathoner, check.get(marathoner) -1);
        }

        Set<Map.Entry<String, Integer>> entrySet = check.entrySet();
        for (Map.Entry<String, Integer> entry : entrySet) {
            if (entry.getValue() != 0) {
                answer = entry.getKey();
                break;
            }
        }
        return answer;
    }

5. 💡 이상한 문자 만들기 💡

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

1) 문제 설명

문자열 s는 한 개 이상의 단어로 구성되어 있습니다. 각 단어는 하나 이상의 공백문자로 구분되어 있습니다. 각 단어의 짝수번째 알파벳은 대문자로, 홀수번째 알파벳은 소문자로 바꾼 문자열을 리턴하는 함수, solution을 완성하세요.

2) 제한 사항

  • 문자열 전체의 짝/홀수 인덱스가 아니라, 단어(공백을 기준)별로 짝/홀수 인덱스를 판단해야합니다.
  • 첫 번째 글자는 0번째 인덱스로 보아 짝수번째 알파벳으로 처리해야 합니다.

3) 풀이

전체 문자열을 스페이스 단위로 자르고, 자른 문자열들을 char 배열 형태로 변경한다. 이후 배열의 index가 짝수인지 홀수인지에 따라 대문자 혹은 소문자로 변경해준다. 모든 문자열들을 변경한 이후에는 각 문자열들을 병합한다.

결론적으로, 다음과 같이 진행했다.
1) str.split()을 통해 단어 단위로 분리
2) str.toCharArray()를 통해 char 배열로 변경
3) Character.toUpperCase(char);를 통해 대문자로 변경
4) Character.toLowerCase(char);를 통해 소문자로 변경
5) str = new String(char[])를 통해 String으로 변경
6) 단어 String 간 병합

4) 소스 코드

    static public String solution(String s) {
        String answer = "";
        String[] words = s.split(" ");
        for (int i = 0; i < words.length; i++) {
            char[] tmp = words[i].toCharArray();
            for (int j = 0; j < tmp.length; j++) {
                if (j%2==0){
                    tmp[j] = Character.toUpperCase(tmp[j]);
                }
                else {
                    tmp[j] = Character.toLowerCase(tmp[j]);
                }
            }
            words[i] = new String(tmp); 

            if ( i== words.length -1 ){
                answer = answer + words[i];
            }
            else {
                answer = answer + words[i] + " ";
            }
        }
        while (answer.length() < s.length()){
            answer = answer + " ";
        }
        return answer;
    }

6. 💡 자릿수 더하기 💡

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

1) 문제 설명

자연수 N이 주어지면, N의 각 자릿수의 합을 구해서 return 하는 solution 함수를 만들어 주세요. 예를들어 N = 123이면 1 + 2 + 3 = 6을 return 하면 됩니다.

2) 제한 사항

  • N의 범위 : 100,000,000 이하의 자연수

3) 풀이

먼저 Int를 String 형태로 변환한다. 이후 String을 다시 한번 Char 배열로 변환한다. 이후 아스키 코드 연산을 통해 각 자리의 정수 값을 구해 전부 더한다.

결론적으로 다음과 같이 진행했다.
1) String str = String.valueOf(int)를 통해 int를 str로 변환
2) str.toCharArray()를 통해 str을 char 배열로 변환
3) char[i] - '0'을 통해 int 값 추출
4) answer에 더해서 리턴

4) 소스 코드

    static public int solution(int n) {
        int answer = 0;
        String tmp = String.valueOf(n);             // 입력된 int를 문자열로 변환
        char[] arr = tmp.toCharArray();             // 문자열을 char의 배열로 변환
        for (int i = 0; i < arr.length; i++) {
            answer = answer + arr[i] - '0';         // 아스키 코드 연산
        }
        return answer;
    }

7. 자연수 뒤집기

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

1) 문제 설명

자연수 n을 뒤집어 각 자리 숫자를 원소로 가지는 배열 형태로 리턴해주세요. 예를들어 n이 12345이면 [5,4,3,2,1]을 리턴합니다.

2) 제한 사항

  • n은 10,000,000,000이하인 자연수입니다.

3) 풀이

배열의 크기를 설정하기 위해 먼저 n에 log10을 취한다. 결과 값을 int로 변환하고 +1 한다. 이렇게 나온 값의 길이를 가진 배열을 만들고, 이후 n을 10으로 계속해서 나누어 가면서 나눌 때마다 발생한 나머지를 배열에 담는다.

결론적으로 다음과 같이 진행했다.
1) int[] answer = new int[(int)Math.log10(n)+1];을 통해 동일한 자리수를 가진 배열 생성
2) answer[i] = (int) (n % 10);을 통해 10으로 나눈 나머지를 배열에 삽입

4) 소스 코드

    static public int[] solution(long n) {
        int[] answer = new int[(int)Math.log10(n)+1];

        for (int i = 0; i < answer.length; i++) {
            answer[i] = (int) (n % 10);
            n = n / 10;
        }
        return answer;
    }

8. 내림차순으로 배치하기

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

1) 문제 설명

함수 solution은 정수 n을 매개변수로 입력받습니다. n의 각 자릿수를 큰것부터 작은 순으로 정렬한 새로운 정수를 리턴해주세요. 예를들어 n이 118372면 873211을 리턴하면 됩니다.

2) 제한 사항

n은 1이상 8000000000 이하인 자연수입니다.

3) 풀이

n의 각 자리수를 배열에 넣는다. 이후 선택정렬을 사용해 역으로 정렬하고, 각 자리마다 10을 곱해가며 더한다.

결론적으로 다음과 같이 진행했다.
1) int[] answer = new int[(int)Math.log10(n)+1];을 통해 동일한 자리수를 가진 배열 생성
2) answer[i] = (int) (n % 10);을 통해 10으로 나눈 나머지를 배열에 삽입
3) 선택 정렬을 사용해 배열을 역순으로 정렬
4) answer = answer*10 + tmp[i];을 각 자리마다 반복

4) 소스 코드

    static public int[] InsertionSortD(int[] arr){
        for(int i = 0; i<arr.length; i++){
            int key = arr[i];
            int j;
            for(j = i-1; j>=0 && arr[j]<key; j--){
                arr[j+1] = arr[j];
            }
            arr[j+1] = key;
        }
        return arr;
    }

    static public long solution(long n) {
        long answer = 0;
        int tmp[] = new int[(int) Math.log10(n) + 1];
        for (int i = 0; i < tmp.length; i++) {
            tmp[i] = (int) (n % 10);
            n = n / 10;
        }
        tmp = InsertionSortD(tmp);
        for (int i = 0; i < tmp.length; i++) {
            answer = answer*10 + tmp[i];
        }
        return answer;
    }

9. 정수 제곱근 판별

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

1) 문제 설명

임의의 양의 정수 n에 대해, n이 어떤 양의 정수 x의 제곱인지 아닌지 판단하려 합니다.
n이 양의 정수 x의 제곱이라면 x+1의 제곱을 리턴하고, n이 양의 정수 x의 제곱이 아니라면 -1을 리턴하는 함수를 완성하세요.

2) 제한 사항

  • n은 1이상, 50000000000000 이하인 양의 정수입니다.

3) 풀이

Math.sqrt()를 이용해 제곱근을 구하고, 이를 1로 나눴을 때 나누어 떨어지는지 확인한다. 나누어 떨어질 경우 x+1의 제곱을 리턴하고, 나누어 떨어지지 않을 경우 -1을 리턴한다.

4) 소스 코드

class Solution {
    public long solution(long n) {
        long answer = 0;
        double tmp = Math.sqrt(n);
        if(tmp%1 == 0){
            return (long)((tmp+1) * (tmp+1));
        }
        else{
            return -1;
        }
    }
}

10. 💡 제일 작은 수 제거하기 💡

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

1) 문제 설명

정수를 저장한 배열, arr 에서 가장 작은 수를 제거한 배열을 리턴하는 함수, solution을 완성해주세요. 단, 리턴하려는 배열이 빈 배열인 경우엔 배열에 -1을 채워 리턴하세요. 예를들어 arr이 [4,3,2,1]인 경우는 [4,3,2]를 리턴 하고, [10]면 [-1]을 리턴 합니다.

2) 제한 사항

  • arr은 길이 1 이상인 배열입니다.
  • 인덱스 i, j에 대해 i ≠ j이면 arr[i] ≠ arr[j] 입니다

3) 풀이

ArrayList를 활용해 풀고자 했다. for문을 통해 List에 배열에 있는 값을 전부 넣었다. 이후 Collections.min(list)를 통해 최솟값을 찾았고, 이후 최솟값이 전부 없어질 때 까지 list.contains(min)으로 while문을 돌면서 삭제했다.

결론적으로, 다음과 같이 진행했다.
1) List 생성 및 배열의 값 넣어주기
2) int min = Collections.min(list_arr);을 통해 최솟값 찾기
3) while(list_arr.contains(min))으로 최솟값이 list에 남았나 확인
4) list_arr.remove(list_arr.indexOf(min))을 통해 삭제

4) 소스 코드

import java.util.*;
class Solution {
    public int[] solution(int[] arr) {
        // 에러 처리
        if (arr.length < 2){
            int[] err = {-1};
            return err;
        }

        List<Integer> list_arr = new ArrayList<>();
        for (int i : arr) {
            list_arr.add(i);
        }
        int min = Collections.min(list_arr);

        while(list_arr.contains(min)){
            list_arr.remove(list_arr.indexOf(min));
        }

        int[] answer = new int[list_arr.size()];
        for (int i = 0; i < answer.length; i++) {
            answer[i] = list_arr.get(i);
        }

        return answer;
    }
}

11. 콜라츠 추측

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

1) 문제 설명

1937년 Collatz란 사람에 의해 제기된 이 추측은, 주어진 수가 1이 될 때까지 다음 작업을 반복하면, 모든 수를 1로 만들 수 있다는 추측입니다. 작업은 다음과 같습니다.

1-1. 입력된 수가 짝수라면 2로 나눕니다.
1-2. 입력된 수가 홀수라면 3을 곱하고 1을 더합니다.
2. 결과로 나온 수에 같은 작업을 1이 될 때까지 반복합니다.

예를 들어, 주어진 수가 6이라면 6 → 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1 이 되어 총 8번 만에 1이 됩니다. 위 작업을 몇 번이나 반복해야 하는지 반환하는 함수, solution을 완성해 주세요. 단, 주어진 수가 1인 경우에는 0을, 작업을 500번 반복할 때까지 1이 되지 않는다면 –1을 반환해 주세요.

2) 제한 사항

  • 입력된 수, num은 1 이상 8,000,000 미만인 정수입니다.

3) 풀이

문제 설명을 단순히 따라가기만 하면 되는 문제였다. 하지만 연산 과정에서 int의 범위를 벗어나는 경우 에러가 발생했다. 이를 방지하기 위해 연산 과정에서는 long을 사용하고, 연산 과정이 끝난 이후에 int로 typecast 해주었다.

4) 소스 코드

class Solution {
    public int solution(int num_input) {
        int answer = 0;
        long num = num_input;
        while( answer<501 && num != 1){
            answer++;
            if(num%2 == 0){
                num = num/2;
            }
            else {
                num = num*3 + 1;
            }
            System.out.println(num);
        }
        if (answer>=500){
            return -1;
        }
        return answer;
    }
}

12. 💡 하샤드 수 💡

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

1) 문제 설명

양의 정수 x가 하샤드 수이려면 x의 자릿수의 합으로 x가 나누어져야 합니다. 예를 들어 18의 자릿수 합은 1+8=9이고, 18은 9로 나누어 떨어지므로 18은 하샤드 수입니다. 자연수 x를 입력받아 x가 하샤드 수인지 아닌지 검사하는 함수, solution을 완성해주세요.

2) 제한 사항

  • x는 1 이상, 10000 이하인 정수입니다.

3) 풀이

Math.log10()을 통해 자릿수를 확인한다. 자릿수의 길이만큼 x를 10으로 나누면서 나머지들의 총합을 구했다. 이후 해당 총합을 기준으로 하샤드 수인지 아닌지 확인했다.

4) 소스 코드

class Solution {
    public boolean solution(int x) {
        boolean answer = false;
        int digits = (int) Math.log10(x) + 1;
        int tmp = x;
        int sum = 0;
        for (int i = 0; i < digits; i++) {
            sum = sum + tmp%10;
            tmp = tmp/10;
        }
        if (x%sum == 0){
            answer = true;
        }


        return answer;
    }
}

II. 과제

1. 코드 수정 문제

다음 코드를 실행하면 출력 결과로 5를 기대했는데 4가 출력되었습니다. 어디에서 잘못 작성된 것일까요?

int var1=5;
int var2=2;
double var3=var1/var2;
int var4=(int)(var3*var2);
System.out.println(var4);

1) 풀이

3번째 줄 double var3=var1/var2;에서 var1/var2이 int값으로, 즉 2.5가 아닌 2로 계산된 뒤에, var3의 타입(double)에 맞춰 2.0으로 변환되었기 때문이다. 이를 해결하기 위해선 연산 전에 var1과 var2를 double로 바꿔줘야 한다.

다음과 같이 변경하면 된다.
double var3= double(var1/var2);

2. 출력 결과 확인 문제

int x=10;
int y=20;
int z = (++x) + (y--); // x는 먼저 더해지고, y는 해당 라인 이후에 감소
System.out.println(z);

결과 : 31

3. 코드 작성 문제

while문과 Math.random() 메소드를 이용해서 2개의 주사위를 던졌을 때 나오는 눈을 (눈1, 눈2) 형태로 출력하고, 눈의 합이 5가 아니면 계속 주사위를 던지고, 눈의 합이 5이면 실행을 멈추는 코드를 작성해보세요. 눈의 합이 5가 되는 조합은 (1,4), (4,1), (2,3), (3,2)입니다.

1) 출력 예시

시작!
(3,6)
(2,6)
(1,4)!

2) 풀이

        public static void main(String[] args) {
            boolean run = true;
			System.out.println("시작");
            for(int i = 0; i<=10; i++) {
                while (run) {
                    int dice1 = (int)(Math.random()*6) + 1;
                    int dice2 = (int)(Math.random()*6) + 1;
                    if (dice1 + dice2 == 5) {
                        System.out.println("(" + dice1 + ", " + dice2 + ")");
                        run = false;
                    }
                }
            }
            System.out.println("끝");
        }

0개의 댓글