JAVA/해결한 문제 (10)

 

 

 

(이게 왜 레벨 2가 아닌 레벨 1일까요?..)

 

문제

 

문제링크

두 숫자 X, Y가 주어질 때 X와 Y에 공통으로 있는 숫자를 모두 찾아서 그 숫자들을 조합하여 만들수 있는 최댓값을 리턴하는 함수를 작성한다.

같은 숫자가 중복되어 있을 경우 중복된 개수만큼 붙인다.

 

 

해결과정

처음엔 문제를 잘못 이해하고 중복을 없애려고 Set을 사용했다가 문제를 잘못 이해한 것을 인지하고 List로 바꿔서 구현했었습니다. ㅎ

그러나 List를 사용 시 몇 가지 테스트에서 통과를 하지 못하여 갈아엎고 ㅎ 배열로 풀었습니다. 😂

입력받은 String을 각각 char형 배열로 변환한 후 오름차순으로 정렬을 했습니다.

오름차순으로 각각 정렬한 이유는 0번 인덱스부터 배열의 끝까지 비교하면서 공통으로 있는 수를 찾으려 했기 때문입니다.

우선은 두 개의 배열을 반복문에서 동시에 순회하면서 비교할 것이기 때문에 index를 담을 변수를 선언 후 0으로 초기화해줍니다.

저는 반복문으로 for문이 아닌 while문을 사용하였는데 따로 x, y 인덱스 변수가 있기 때문에 인덱스를 증가시켜줄 필요가 없어 조건만 넣은 while 문을 사용하였습니다.

while 문의 조건은 'x인덱스가 x배열의 길이 보다 작고 y인덱스가 y배열의 길이보다 작다'로 설정하였습니다.

이미 x배열과 y배열은 정렬이 되어 있기 때문에 앞에서부터 비교하면서 값이 더 작은 배열의 인덱스의 값을 올려주었습니다.

그리고 값이 같을 경우 해당 값을 StringBuffer에 붙여주고 두 배열의 index를 동시에 증가시켜주었습니다.

(StringBuffer를 사용한 이유는 오름차순을 내림차순으로 바꿔주기 위해 reverse()를 사용할 것이기 때문입니다!)

이렇게해서 하나의 배열이라도 맨 끝에 다다르면 반복을 중지합니다.

이렇게 되면 모든 공통값이 오름차순으로 들어가게 되서 reverse()를 해줍니다.

여기까지만 작성하고 리턴하게 되면 몇가지를 통과하지 못하게 되는데..

0만 있을 경우엔 (예를 들어 "000" 같은 경우) "0"으로 변환해주어야 합니다.

만약에 결과 문자열에 0만 있다면 내림차순이기 때문에 맨 앞에 0이 올 것입니다.

따라서 맨 앞의 문자가 0인지 조건문으로 확인하여 0이라면 "0"만 리턴하면 됩니다.

이렇게 배열로 하면 시간복잡도가 O(n)으로 나쁘진 않은 편? 입니다. (이보다 좋은 방법이 있겠지만 떠오르지 않았습니다.)

 

 

코드

import java.util.Arrays;
import java.lang.StringBuffer;

class Solution {
    public String solution(String x, String y) {
        StringBuffer answer = new StringBuffer("");
        char[] xArr = x.toCharArray();
        char[] yArr = y.toCharArray();
        Arrays.sort(xArr);
        Arrays.sort(yArr);
        int xIdx = 0;
        int yIdx = 0;
        while (xIdx < xArr.length && yIdx < yArr.length) {
            if (xArr[xIdx] == yArr[yIdx]) {
                answer.append(String.valueOf(xArr[xIdx]));
                xIdx++;
                yIdx++;
            } else if (xArr[xIdx] < yArr[yIdx]) {
                xIdx++;
            } else if (xArr[xIdx] > yArr[yIdx]) {
                yIdx++;
            }
        }
        if (answer.length() < 1)    return "-1";
        answer.reverse();
        String result = answer.toString();
        if (result.charAt(0) == '0') return "0";
        return result;
    }
}

 

 

실행 결과

✌️

 

 

 

깃허브 코드 보러가기

 

읽어주셔서 감사합니다. 🤗 좋은하루 되세요~

 

 

 

 

문제

Merge Sort를 이용하여 int 형 배열을 정렬하시오.

조건

  • Arrays.sort 사용 금지
  • 병합 정렬을 이용하여 정렬

 

병합 정렬이란??

우선 입력받은 배열을 길이가 1인 배열이 될 때까지 계속 반으로 나눈다.

나눈 배열을 2개씩 병합하여 정렬한다.

길이가 2인 배열 병합 -> 길이가 4인 배열 병합 -> 길이가 8인 배열 병합 ...

병합할 때마다 요소들을 정렬한다.

 

출처 : GeeksforGeeks merge Algorithm

 

 

해결 방법

'반으로 나눈다 -> 병합한다' 라는 반복과정이 있기 때문에 반복, 재귀 중에 한가지로 해결할 수 있습니다.

저는 재귀를 활용하여 풀었습니다.

배열을 중간을 기준으로 나눠야 하기 때문에 length / 2 를 기준으로 배열을 left, right 두부분으로 분리하였습니다.

배열의 길이가 1이 될 때까지 이과정을 반복해야 하기 때문에 left, right 배열을 초기화하는 과정에서 바로 재귀를 호출하였습니다.

브레이크 포인트로 길이가 1이하가 될 경우 멈추도록 했습니다.

이제 쪼개진 배열을 오름차순으로 병합하면 됩니다.

이때 left 배열과 right 배열은 각각 이미 정렬이 된 상태이기 때문에 두 배열을 앞에서부터 비교하면서 더 작은 쪽의 요소를 넣어주고 인덱스 카운트를 올려줍니다.

그럼 각각의 인덱스를 기억해야하기 때문에 각각 인덱스를 담을 leftIdx, rightIdx를 선언합니다.

그리고 반복문으로 정렬할 배열의 길이만큼 반복해주면서 두 배열 중 작은 요소를 결과 배열에 넣고 해당 배열의 인덱스를 +1 시켜줍니다.

여기서 배열의 길이를 넘어버리면 안되기 때문에 배열의 길이를 넘을 경우 반대쪽 배열의 남은 요소를 모두 붙여넣고 반복을 종료시키도록 합니다.

 

 

코드

 

import java.util.Arrays;

public class MergeSort {
    public int[] mergeSort(int[] arr) {
        if (arr.length < 2) {
            return arr;
        }
        int middle = arr.length / 2;
        int[] left = mergeSort(Arrays.copyOfRange(arr, 0, middle));
        int[] right = mergeSort(Arrays.copyOfRange(arr, middle, arr.length));

        arr = new int[left.length + right.length];
        int leftIdx = 0;
        int rightIdx = 0;
        for (int i = 0; i < arr.length; i++) {
            if (leftIdx >= left.length) {
                System.arraycopy(right, rightIdx, arr, i, right.length - rightIdx);
                break;
            } else if (rightIdx >= right.length) {
                System.arraycopy(left, leftIdx, arr, i, left.length - leftIdx);
                break;
            } else if(left[leftIdx] > right[rightIdx]) {
                arr[i] = right[rightIdx];
                rightIdx++;
            } else {
                arr[i] = left[leftIdx];
                leftIdx++;
            }
        }
        return arr;
    }
}

 

 

 

깃허브 코드 보러가기

 

감사합니다. 좋은 하루 되세요. 🤗

 

 

 

 

 

문제

 

문제 링크

카카오 성격 유형 검사지를 만들려고 합니다.

성격 유형은 아래와 같습니다.

지표 번호 성격 유형
1번 지표 라이언형(R), 튜브형(T)
2번 지표 콘형(C), 프로도형(F)
3번 지표 제이지형(J), 무지형(M)
4번 지표 어피치형(A), 네오형(N)

각각의 지표에 대해서 점수가 높은 알파벳을 조합하여 성격 유형 결과가 나옵니다. -> mbti를 생각하면 됨

ex) RCMA

 

검사지에는 총 n개의 질문이 있고 선택지 총 7개 입니다.

  • 매우 비동의
  • 비동의
  • 약간 비동의
  • 모르겠음
  • 약간 동의
  • 동의
  • 매우 동의

 

검사자의 선택에 따라(동의/비동의) 한가지 지표의 한 개의 성격 유형에 대한 점수를 얻습니다. (1번 지표일 경우 비동의가 R, 동의가 T일 수도 있고, 동의가 R, 비동의가 T일 수 있음)

R(라이언형)이 비동의, T(튜브형)이 동의일 경우 점수는 아래와 같습니다.

답변 점수
매우 비동의 라이언형 3점
비동의 라이언형 2점
약간 비동의 라이언형 1점
모르겠음 어떤 성격 유형도 점수를 얻지 않음
약간 동의 튜브형 1점
동의 튜브형 2점
매우 동의 튜브형 3점

 

점수가 높은 지표를 조합하여 성격유형 검사 결과를 출력합니다.

 

입력

  • survey : survey[i] 번째 문자열은 i+1 번째 문제의 성격유형을 의미 (2글자로 1번째 문자는 비동의, 2번째 문자는 동의에 해당하는 성격유형)
    • ex) "RT", "MJ"
  • choices : choices[i]는 검사자가 선택한 i+1번째 질문의 선택지

 

 

해결 과정

 

처음에는 Map을 이용하여 풀려고 했으나 Map으로 푸는 건 너무 흔할 것 같아 새로운 시도를 해보고 싶어 배열로 풀었습니다.

 

 

코드

 

public String solution(String[] survey, int[] choices) {
    String answer = "";
    // 설문자의 점수를 담을 정수형 배열 선언, 차례대로 R, C, J, A 형의 점수, 반대 점수는 음수로 더한다.
    int[] scores = new int[4];

    // 설문지 점수표를 담을 정수형 배열 선언, i번째 인덱스의 숫자가 i점의 점수
    int[] scoreTable = {0, 3, 2, 1, 0, 1, 2, 3};

    // 계산할 점수 지표를 담을 캐릭터형 선언
    char indicator;

    // 질문지의 길이만큼 순회하여 choices의 i번째 요소를 꺼낸다.
    for(int i = 0; i < choices.length; i++) {
        int choice = choices[i];
        // 꺼낸 점수가 4일 경우 continue
        if (choice == 4) continue;
        // 꺼낸 점수가 1~3일 경우
        if (choice < 4) {
            // survey[i]의 0번째 캐릭터형이 점수 지표
            indicator = survey[i].charAt(0);
        } else {  // 꺼낸 점수가 5~7일 경우
            // survey[i]의 1번째 캐릭터형이 점수 지표
            indicator = survey[i].charAt(1);
        }
        // indicator 에 따라 점수를 계산
        switch(indicator) {
            case 'R':
                scores[0] += scoreTable[choice];
                break;
            case 'T':
                scores[0] -= scoreTable[choice];
                break;
            case 'C':
                scores[1] += scoreTable[choice];
                break;
            case 'F':
                scores[1] -= scoreTable[choice];
                break;
            case 'J':
                scores[2] += scoreTable[choice];
                break;
            case 'M':
                scores[2] -= scoreTable[choice];
                break;
            case 'A':
                scores[3] += scoreTable[choice];
                break;
            case 'N':
                scores[3] -= scoreTable[choice];
                break;
            default: break;
        }
    }
    // 점수 배열의 0번째 인덱스가 0이상인 경우 결과 문자열에 R, 음수일경우 T를 붙인다.
    if (scores[0] >= 0) {
        answer += "R";
    } else answer += "T";
    // 점수 배열의 1번째 인덱스가 0이상인 경우 결과 문자열에 C, 음수일경우 F를 붙인다.
    if (scores[1] >= 0) {
        answer += "C";
    } else answer += "F";
    // 점수 배열의 2번째 인덱스가 0이상인 경우 결과 문자열에 J, 음수일 경우 M을 붙인다.
    if (scores[2] >= 0) {
        answer += "J";
    } else answer += "M";
    // 점수 배열의 3번째 인덱스가 0이상인 경우 결과 문자열에 A, 음수일 경우 N을 붙인다.
    if (scores[3] >= 0) {
        answer += "A";
    } else answer += "N";
    return answer;
}

 

 

 

깃허브 코드 보러가기

 

 

 

 

 

문제

정수를 요소로 갖는 배열을 입력받아 오름차순으로 정렬하여 리턴합니다.

조건

  • sort 메서드 사용 금지
  • 퀵 정렬을 구현
  • 오름차순으로 정렬

 

 

해결과정

퀵 정렬을 정확하게 모르기 때문에 구현할 수가 없어 퀵 정렬 방법만 검색하여 참고한 후 코드는 직접 구현하였습니다.

퀵 정렬은 pivot을 기준으로 작은 수들, 큰 수들을 각각 새로운 배열에 넣는 과정을 반복하여 정렬하는 방식입니다.

시간복잡도는 O(nlog n) 에서 최악의 경우 O(n^2) 입니다.

검색한 퀵 정렬의 개념을 토대로 재귀를 이용하여 간단하게 로직을 구현했습니다.

pivot은 주로 맨 끝 요소를 기준으로 하는 것으로 보여서 입력받은 맨끝요소를 pivot으로 하고

배열의 나머지 요소를 순회하면서 작은 수와 큰 수를 각각 나눠 리스트에 집어넣습니다.

(배열이 아닌 리스트를 사용한 이유는?

배열은 사이즈를 알고 있어야 생성할 수 있는데 pivot을 기준으로 큰 수가 몇 개이고 작은 수가 몇 개인지 순회하기 전까진 알 수 없어

번거롭더라도 사이즈가 가변하는 리스트에 넣은 후 순회를 마치면 toArray로 배열로 변환해주었습니다.)

그 후에 작은 수 배열을 재귀로 집어넣고 큰 수 배열도 마찬가지로 재귀에 집어넣습니다.

재귀 브레이크 포인트로 입력받은 배열의 길이가 1이하일 경우는 그대로 리턴하고 2일 경우는 정렬 후 리턴하도록 했습니다.

마지막으로 배열을 작은 수 배열 + pivot + 큰 수 배열 순으로 붙여서 결과 배열을 만든 후 리턴하였습니다.

 

 

코드

public int[] quickSort(int[] arr) {
    if (arr.length <= 1) {
        return arr;
    }
    if (arr.length == 2) {
        if (arr[0] > arr[1]) {
            int a = arr[0];
            arr[0] = arr[1];
            arr[1] = a;
        }
        return arr;
    }

    int[] answer = new int[arr.length];
    List<Integer> smallNums = new ArrayList<>();
    List<Integer> bigNums = new ArrayList<>();

    int pivot = arr[arr.length - 1];
    for (int i = 0; i < arr.length - 1; i++) {
        if (arr[i] < pivot) {
            smallNums.add(arr[i]);
        } else bigNums.add(arr[i]);
    }
    int[] smallArr = quickSort(smallNums.stream().mapToInt(Integer::intValue).toArray());
    int[] bigArr = quickSort(bigNums.stream().mapToInt(Integer::intValue).toArray());
    System.arraycopy(smallArr, 0, answer, 0, smallArr.length);
    answer[smallArr.length] = pivot;
    System.arraycopy(bigArr, 0, answer, smallArr.length + 1, bigArr.length);
    return answer;
}

 

 

 

깃허브 코드 보러가기

 

 

 

감사합니다. 좋은하루 되세요. 😄

 

 

자연수에서 소수(prime number)는 1보다 큰 수 중에 1과 자기자신만을 약수로 가지는 수이다.

따라서 자신보다 작은 수(1 제외)로 나눴을 때 항상 나누어 떨어지지 않아서 나머지가 존재한다는 의미다.

소수를 구하는 함수를 자바 언어를 사용하여 구현해보았다.

 

복잡하지 않게 작성하면 이렇게 구현할 수 있다.

public boolean prime (int num) {
	if(num == 0 || num == 1) return false;
	if(num == 2) return true;
    for(int i = 2; i < num; i++){
       if(num % i == 0) return false;
    }
    return true;
}

 

함수의 형식은 매개변수로 소수인지 구할 숫자를 입력받고 소수인지 여부를 true/false로 반환하는 모양으로 만들었다.

소수인지 구하기 전에 0과 1은 일단 소수가 아니므로 false를 리턴하고 2는 소수이므로 true를 리턴한다.

그리고 1보다 큰 수인 2부터 num보다 작은 num - 1까지 나누어떨어지는지 확인한다.

중간에 한번이라도 나누어떨어지면 소수가 아니므로 false를 리턴하고

num - 1 까지 확인을 마치면 true를 리턴한다.

 

여기서 더 효율적으로 코드를 짤 수는 없을까?

 

약수를 확인할 때 항상 2개씩 짝이 지어진다.

예를 들어 40의 약수를 구해보면

1, 2, 4, 5, 8, 10, 20, 40 이다.

이때 1과 40, 2와 20, 4와 10, 5와 8 이렇게 2개씩 짝이 지어진다.

그렇다면 맨 끝까지 일일이 나눠서 확인할 필요없이 중간 수 까지만 확인하면 끝까지(num - 1) 확인한 것과 같은 결과 일 것이다.

중간 수는 어떻게 구하는가?

2 x 20, 4 x 10, 5 x 8 = 40

중간 수는 자기자신을 곱했을 때 40이 나오는 수이다!

다시 말해 40의 제곱근이다.

자바에서 제곱근을 구하려면 Math.sqrt() 를 사용하면 된다.

다음은 제곱근까지만 확인하도록 구현해보았다.

 

    public boolean prime (int num) {
        if(num == 0 || num == 1) return false;
        if(num == 2) return true;
        if(num % 2 == 0) return false;
        for(int i = 3; i <= Math.sqrt(num); i++)
            if(num % i == 0) return false;
        return true;
    }

 

이 함수가 맨 처음에 만든 함수보다 반복문에서 num의 제곱근 까지만 반복하므로 더 효율적이다.

 

 

여기서 추가로 이웃이신 닉님의 도움으로 더 간단하게 작성했습니다!

짝수는 2로 나눠서 확인했기 때문에 3부터 +2하면서 확인하면 됩니다.

    public boolean prime (int num) {
        if(num == 0 || num == 1) return false;
        if(num == 2) return true;
        if(num % 2 == 0) return false;
        for(int i = 3; i <= Math.sqrt(num); i += 2)
            if(num % i == 0) return false;
        return true;
    }

 

 

 

 

읽어주셔서 감사합니다.

좋은 하루 되세요 ^^

+닉님 감사합니다😃

 

 

 

문제

 

동전 종류를 담은 int형 배열과 목표 액수를 매개변수로 전달받았을 때

가지고 있는 동전 종류로 목표 액수를 만들 수 있는 모든 가짓수를 구하시오.

(배열로 받은 동전 종류는 각각 개수에 제한이 없다고 가정)

 

 

 

 

해결

코드보기

더보기
public class Dp {
    public long ocean(int target, int[] type) {
        // 가짓수를 담을(반환할) 결과값 0으로 초기화
        long result = 0;
        long[][] arr = new long[type.length][target + 1];
        for(int i = 0; i < type.length; i++) {
            arr[i][0] = 1;
        }
        // type(동전)의 최소 단위로 나누어 떨어지면 교환 가능하기 때문에 방법수 1 저장
        for (int i = type[0]; i <= target; i++) {
            if (i % type[0] == 0) arr[0][i] = 1;
        }

        for (int i = 1; i < type.length; i++) {
            for (int j = 0; j <= target; j++) {
                if(type[i] > j) {
                    arr[i][j] = arr[i-1][j];
                }
                else {
                    arr[i][j] = arr[i][j-type[i]] + arr[i-1][j];
                }
            }
        }
        result = arr[type.length - 1][target];
        return result;
    }
}

 

 

 

 

문제

 

박스에 짐을 담으려고 하는데 짐에는 무게가 있고 박스는 용량 제한이 있다.

박스에 짐을 2개까지만 담을 수 있다

이때 탐욕 알고리즘을 이용해서 짐을 박스에 담을 수 있는 최적의 선택을 했을 때 박스가 몇개 필요한가?

 

 

해결

 

import java.util.ArrayList;
import java.util.List;

public class movingStuff {
    public int movingStuff(int[] stuff, int limit) {
        int box = 0; // 박스에 넣은 짐 수(최대 2)
        int bstuff = 0; // 박스에 담은 짐 무게
        int result = 1; // 필요한 박수 수
        int max = 0;  // 남은 짐의 최댓값
        int maxIndex = 0; // 짐 최댓값의 인덱스
        List<Boolean> boo = new ArrayList<>();  // 짐을 확인했는지 확인할 배열 (모두 false)
        // 배열을 리스트로 변경
        ArrayList<Integer> slist = new ArrayList<Integer>();
        // 배열을 값을 리스트에 추가
        for (int i = 0; i < stuff.length; i++) {
            slist.add(stuff[i]);
            boo.add(false);
        }
        // 짐 리스트를 모두 포장할 때까지 반복
        while (!slist.isEmpty()) {
            // 한 번 확인한 max는 초기화
            max = 0;
            // 만약 다음 최대값을 가져오는데
            for (int i = 0; i < slist.size(); i++) {
                if (max < slist.get(i) && boo.get(i) == false) {
                    max = slist.get(i);
                    maxIndex = i;
                }
            }
            // 확인한 가장 무거운 짐은 true로 변경
            boo.set(maxIndex, true);
            // 짐 배열에서 가장 큰 값 가져옴
            // 가져온 제일 무거운 짐을 넣었을 때 limit가 넘지 않을 지 확인
            if (bstuff + max <= limit) {
                // 안넘으면 박스에 추가
                bstuff += max;
                box++;
                // 넣은 짐은 리스트에서 제거
                slist.remove(maxIndex);
                boo.remove(maxIndex);
                if(slist.isEmpty()) break;
                // 추가한 후에 박스안의 짐이 2개가 되면
                if (box == 2) {
                    // 박스 변수를 비움
                    box = 0;
                    bstuff = 0;
                    // 아직 담을 짐이 있다면 박스 새로 추가
                    result++;
                    // boo 초기화
                    for (int k = 0; k < boo.size(); k++) {
                        boo.set(k, false);
                    }
                }
            } else if (!boo.contains(false)) {
                // 새로운 박스 가져옴
                box = 0;
                bstuff = 0;
                // 아직 담을 짐이 있다면 박스 새로 추가
                result++;
                // boo 초기화
                for (int k = 0; k < boo.size(); k++) {
                    boo.set(k, false);
                }
            }
        }
        return result;
    }
}

 

 

 

 

 

 

 

<문제 링크>

 

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

 

1018번: 체스판 다시 칠하기

첫째 줄에 N과 M이 주어진다. N과 M은 8보다 크거나 같고, 50보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에는 보드의 각 행의 상태가 주어진다. B는 검은색이며, W는 흰색이다.

www.acmicpc.net

 

 

 

<헤맨 과정>

더보기

먼저 직사각형의 크기를 입력받고

입력받은 크기만큼의 char형 2차원 배열을 만들어주었다.

그리고 그 안에 W또는 B을 2차원 크기만큼 입력받게 작성했다.

배열에서 입력받는 과정에 Scanner는 char형으로 받는 메소드가 따로 없어서

한 줄(한 행) 씩 String형으로 입력받고 그것을 2차원 배열의 안쪽 배열에 하나씩 대입하도록 만들어주었다.

그렇게 완성된 직사각형에서 자른 후 색을 바꿔서 8x8의 체스판을 만들도록 할 때 최소로 색을 바꾸는 경우를 찾아주기 위해서

배열안에서 만들 수 있는 모든 8x8을 조사하는 코드를 짜고 그 안에서 1행1열의 색이  B일 경우와 W일 경우로 나눠주었다.

그리고 B경우와 W경우에서 몇 개의 색깔을 바꿔야하는지 각각 카운트 해주고

한개의 체스판을 다 확인하면 더 작은 값을 최솟값을 구할 변수에 넣어주었다.

그리고 계속 이 과정을 반복하면서 이전의 최솟값, B경우, W경우 중 더 작은 값을 찾아주었다.

 

논리적으로는 정상적으로 잘 동작하는 코드를 짰는데

백준에서 돌려보니까 런타임 에러가 났다..

그래서 고민하다가 나중에 풀어야지 하고 두고 어제 다시 잡아봤다.

오랜만에 푹자고 맑은 정신에서 코드를 보니까

바로바로 틀린 부분이 눈에 보였다.

한시간씩 이거만 봐도 안보이더니 나중에 보니까 바로 에러를 찾아내다니...

직사각형의 크기를 입력받는 순서를 잘못 알고 있었고,

체스판의 한 줄이 바뀔 때마다 B와 W가 바뀌는 것을 안짰다.

이것만 고치니까 바로 맞았습니다! 가 떴다.

 

전에 암만해도 못 찾던 에러도 나중에 찾을 수도 있다는 경험을 했다.

코딩할 때 아무리 안 풀려도 포기하지 말자..!

 

 

 

 

<내 최종 코드>

 

https://github.com/WiseJade/Baekjoon-Auto-Push/blob/main/%EB%B0%B1%EC%A4%80/Silver/1018.%E2%80%85%EC%B2%B4%EC%8A%A4%ED%8C%90%E2%80%85%EB%8B%A4%EC%8B%9C%E2%80%85%EC%B9%A0%ED%95%98%EA%B8%B0/%EC%B2%B4%EC%8A%A4%ED%8C%90%E2%80%85%EB%8B%A4%EC%8B%9C%E2%80%85%EC%B9%A0%ED%95%98%EA%B8%B0.java

 

GitHub - WiseJade/Baekjoon-Auto-Push: This is a auto push repository for Baekjoon Online Judge created with [BaekjoonHub](https:

This is a auto push repository for Baekjoon Online Judge created with [BaekjoonHub](https://github.com/BaekjoonHub/BaekjoonHub). - GitHub - WiseJade/Baekjoon-Auto-Push: This is a auto push reposito...

github.com

 

 

 

밑의 글의 가장 하단에 백준과 깃헙을 연동할 수 있 유용한 정보를 작성해놨습니다. 도움이 되길 바랍니다.❤️

 

2022.05.25 - [JAVA/해결한 문제] - baekjoon-1085번 "직사각형 탈출" 회고

 

baekjoon-1085번 "직사각형 탈출" 회고

코딩 독학할 때 백준 가입해놨다가 난이도가 있는 것 같아서 한두문제 풀고 손을 안댔었다. 그러다가 오늘 알고리즘시간에 너무 헤맸어서 알고리즘 연습의 중요성을 느꼈다ㅠㅠ 백준으로 알고

wjcodding.tistory.com

 

 

 

 

 

 

코딩 독학할 때 백준 가입해놨다가

난이도가 있는 것 같아서 한두문제 풀고 손을 안댔었다.

그러다가 오늘 알고리즘시간에 너무 헤맸어서

알고리즘 연습의 중요성을 느꼈다ㅠㅠ

백준으로 알고리즘 연습해서 알고리즘 뇌를 발달시켜야 겠다..🧠

일단 오늘 풀었지만 틀린 문제를 기록으로 남겨놓는다.

 

 

<문제 링크>

 

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

 

1085번: 직사각형에서 탈출

한수는 지금 (x, y)에 있다. 직사각형은 각 변이 좌표축에 평행하고, 왼쪽 아래 꼭짓점은 (0, 0), 오른쪽 위 꼭짓점은 (w, h)에 있다. 직사각형의 경계선까지 가는 거리의 최솟값을 구하는 프로그램

www.acmicpc.net

 

 

 

<헤맨 과정>

더보기

문제만 보면 직사각형에 좌표 있고 복잡하게 풀어야할 것 같지만

쉽게 접근할 수 있다.

일단 각각 전체 가로세로 길이의 절반보다 (x, y)좌표가 같거나 클 경우를 변수에 담아두었다가 담은 가로, 세로 변수 2개중 더 작은 것을 출력하면 된다.

        if(x >= w / 2) {
            horizon = w - x;
        }
        else horizon = x;

        if(y >= h / 2) {
            length = h - y;
        }
        else length = y;

 

이렇게 조건문을 작성하면 예제의 코드는 잘 돌아가지만

틀렸다.

인텔리제이에서는 잘 돌아가는데 풀이를 제출할 때마다 자꾸 틀렸다고 해서 꽤나 고민했다..

그러다가 혹시 나누기 2 하는 과정에서 int 형이기 때문에 소수점은 버려져서 그런가?

싶어서 테스트 해보니까 그것 때문이었다.

2 3 5 9

이런식으로 입력하면

세로의 변수 length에는 3이 9의 절반인 4.5 보다 작기 때문에 3이 들어가지만

가로는 5의 절반인 2.5와 2를 비교해서 horizon에 2가 들어갈 줄 알았는데

int 형을 나누기 2 했기 때문에 2.5의 소수점을 버린 2와 2를 비교해서 horizon에 5 - 2인 3이 들어간다.

그래서 horizon과 length를 비교한 출력값이 3이 나오게 된다.

 

이럴 때 해결 방법이 2가지가 떠올랐다.

 

1. if문안의 조건문을 double로 형변환한 숫자끼리 비교

        if((double)x >= (double)w / 2) {
            horizon = w - x;
        }
        else horizon = x;

        if((double)y >= (double)h / 2) {
            length = h - y;
        }
        else length = y;

 

 

2. 등호를 없애준다

        if(x > w / 2) {
            horizon = w - x;
        }
        else horizon = x;

        if(y > h / 2) {
            length = h - y;
        }
        else length = y;

 

 

 

<내 최종 코드>

더보기
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int x = sc.nextInt();
        int y = sc.nextInt();
        int w = sc.nextInt();
        int h = sc.nextInt();

        int horizon, length;

        if((double)x < (double)w / 2) {
            horizon = x;
        }
        else horizon = w - x;

        if((double)y < (double)h / 2) {
            length = y;
        }
        else length = h - y;

        System.out.print(Math.min(horizon, length));
    }
}

 

 

 

 

 

🔎 백준의 유용한 기능

 

 

백준과 깃헙 연동하기(백준허브 확장자)

 

크롬 확장자 중에 백준허브를 추가(Add to Chrome)

깃헙 아이디와 Authenticate

Repository 추가 또는 기존 Repository 주소 입력해서 연동

백준에서 문제를 풀고 제출하면 자동으로 내 깃헙 repository에 commit이 됩니다!⭐️

 

 

 

백준 티어 보기

 

백준에는 티어가 존재하는줄 몰랐는데

브론즈, 실버, 골드,... 등 티어가 존재한다.

solved를 이용하면 백준에서 문제의 티어를 볼 수 있다.

 

 

이외에도 백준 티어를 깃헙 프로필에 보이게 할 수도 있다. ㅋㅋ

근데 아직 백준 티어가 브론즈 바닥이라서 나중에 당당하게 티어를 보여줄 만큼 올라갔을 때 깃허브 프로필에 올려야 겠다..

 

 

읽어주셔서 감사합니다.😍

 

 

 

문제

 

문자열을  입력받아 문자열을 구성하는 각 문자를 key로 갖는 hashMap을 리턴하는 메소드 만들기

 

 

해결

 

public HashMap<Character, Integer> countAllCharacter(String str) {
        // 문자열이 비어있을 경우 null 리턴
        if (str.isEmpty()) {
            return null;
        }
        
        // 반환할 hashMap 생성
        HashMap<Character, Integer> result = new HashMap<>();
        // 매개변수의 문자열을 char형 배열로 변환
        char[] charArray = str.toCharArray();
        // Arrays.sort()를 이용하여 char 배열을 알파벳 순으로 정렬
        Arrays.sort(charArray);
        
        // char형 배열의 요소를 하나씩 꺼내기
        // 향상된 for문 이용
        for (char c : charArray) {
        	// 중복될 경우 해당 key의 value 값에 +1
            if (result.containsKey(c)) {
                result.put(c, result.get(c) + 1);
            } else {
            	// 중복되지 않을 경우 key와 value 1을 hashMap에 추가
                result.put(c, 1);
            }
        }
        return result;
}

 

 

 

해결하기 전까지의 과정

 

처음에는 String을 char형 배열로 만든 다음 배열 내에서 중복을 체크하고

중복되면 value에 +1 해준 후 배열의 해당 중복된 문자 하나를 지운 후 한 칸씩 왼쪽으로 이동해주는 코드를 작성했다.

하지만 오류가 많고 문제가 배열의 길이를 축소할 방법이 없었다.

 

그 다음에 생각한 방법이 char형 배열을 ArrayList<Character> 형으로 만드는 방법이었다.

중복된 문자를 ArrayList의 메소드인 remove()를 이용해서 하나 제거하고 value에 +1 해주는 방법으로 했다.

이렇게 해도 함수에서 반환받은 hashMap이 index 초과 오류가 발생했다.

 

전부 지우고 빈 화면에서 곰곰히 생각하다가 겨우 생각났다. 😔

char형 배열로 옮긴 다음에

문자를 하나씩

hashMap의 containsKey() 메소드를 이용해서 hashMap안에 중복되 있는지 확인하고

중복되면 해당 문자 key에 value 값을 +1 하고

중복되지 않으면 map안에 없는 것이니까 새로 맵에 붙여 주면 된다.

고민하고 헤맨 것에 비해 너무 간단하고 한순간에 해결됐다.. 

계속 방법이 생각이 안나다가 머리속에 벼락맞은 것처럼 한순간에 생각났다. ㅋㅋㅋ

 

 

 

 

 

1