[항해99] 알고리즘 5일차 TIL - 그의 손에 쥐어지는 불합격 목걸이?🥺

LIHA·2023년 2월 1일
0

항해99

목록 보기
31/54
post-thumbnail
package mok_test.q00;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Solution sol = new Solution();
        Scanner sc = new Scanner(System.in);
        int price = sc.nextInt();
        System.out.println(sol.solution(price));
    }
}

class Solution {
    public int solution(int price) {
        int answer = 0;
        int tsuri = 1000 - price;
        int leng = (int)Math.log10(price);

        int i;

        answer += tsuri / 500;
        tsuri %= 500;

        answer += tsuri / 100;
        tsuri %= 100;

        answer += tsuri / 50;
        tsuri %= 50;

        answer += tsuri / 10;
        tsuri %= 10;

        answer += tsuri / 5;
        tsuri %= 5;

        answer += tsuri;

위 코드로 문제는 해결했지만, for문으로 좀더 간단하게 표현할 수 없을까? 라는 생각이 들었다.
그래서 고쳐본게 아래.


        int i;
        for(i = leng; i >= 0; i--) {
            answer += tsuri / 5 * Math.pow(10, i);
            tsuri %= (5 * Math.pow(10, i));

            answer += tsuri / Math.pow(10, i);
            tsuri %= Math.pow(10, i);
        }

그런데 이 코드를 돌리니 값이 이상하게 나와서, 내가 생각을 잘못했나? 하고 계속 고민했었다.😫
그래서 여원님과 함께 살펴보면서 디버거를 돌려본 결과, 원인을 찾았다.

tsuri / 5 * Math.pow(10, i)

이 부분의 분모에 괄호를 쳐놓지 않아서, tsuri / 5를 한 값에 Math.pow를 곱해버려서 그런 것.
페어라고 해도 될지 모르겠지만, 개발공부 유경험자 여원님의 리뷰 덕분에 찾아내서 고칠 수 있었다.🥰


작은 수 제거하기도 힘들어😫😫😫 왜 안풀려!🤯🤯🤯🤯🤯

int[]를 String으로 바꿨다면, 각괄호와 쉼표까지 모두 문자열로 들어왔다! replaceAll로 숫자만 남기자

        Integer[] conv = Arrays.stream(arr).boxed().toArray(Integer[]::new);
        Arrays.sort(conv , Collections.reverseOrder());
        arr = Arrays.stream(conv).mapToInt(Integer::intValue).toArray();

int배열에서 제일 작은 수를 제거한 배열을 리턴하라길래, 정렬해놓고 제일 작은것만 빼서 복사하면 되겠구나 했는데 웬걸!
테스트는 성공했었는데 제출한건 모조리 틀렸다. 왜지😫😫😫

질문하기를 살펴보니, 배열이 있다고 무조건 sort를 쓰는 습관은 지양하라고 한다.
데이터가 순서를 지켜야 하는 경우가 있어서(예를 들면 월별 수치), 가능하면 쓰지 말라고.


        int[] answer = new int[leng - 1];
        int min = arr[0];
        for (i = 0; i < leng - 1; i++) {


            if (arr[i] < min) {
                min = arr[i]; //최소로 설정한 값보다 뒤에 나오는 값이 더 작다면, 뒷값을 새 최소값으로 바꿔줘 (최소값 갱신수식)
                System.out.println("제일 작은수는: " + min);
                String str = Arrays.toString(arr); //최소값이 있는 곳 인덱스 보려고 string으로 변환
                String minstr = Integer.toString(min); //String 관련을 보려고 min값도 String으로 변환

                 // arr2는 최솟값이 항상 맨끝에 오는 배열이다. 즉, 최솟값이 arr[i]번째와 똑같다면 그 i로 보자.

                str = str.replaceAll("[^0-9]", "");

                if(arr[i] == arr2[arr.length-1]) {
                    System.out.println("인덱스의 위치는: " + i);
                    index = i;
                    // 내가 구하고 싶은건: 배열도 String으로, 최소숫자도 String으로 바꿔서,
                    // 배열의 i번째 요소 중 최솟값인 곳의 인덱스를 구한다. (sort 안하면 몇번째에 있는지 모르니까)
                    //그리고 그 인덱스 번호를 통해서, arr의 인덱스번째 요소에다 remove 명령어 쓰고싶음.

                    System.out.println("제일 작은 수를 string으로 바꾸면: " + minstr);
                    System.out.println("str은: " + str);
                    System.out.println("제일 작은 수가 있는 인덱스는: " + str.indexOf(minstr));

                    str = str.replace(minstr, "");
                    System.out.println(str);
                }
                answer[i] = str.charAt(i);
                System.out.println(Arrays.toString(answer));
            }
        }

        if (leng == 1) {
            answer = new int[]{-1};
        }

그래서 이렇게 하려고 했는데, 뭔가 answer[i]에 값도 잘 안 들어가고, 끝도 없이 복잡해진다.
으아ㅏ알너링너라ㅣ 🤯🤯🤯🤯🤯🤯🤯 모르겠어!!!

두시간이 지나도 문제를 못 고쳐서 결국 풀이법을 보았다.

        int countIndex = 0;
        for (i = 0; i < leng; i++) {
            if (arr[i] == min) {
                continue;
            }
            answer[countIndex++] = arr[i];
        }
        if (leng == 1) {
            answer = new int[]{-1};
        }

참고한 블로그

이 부분이 문제였다!
내가 하고싶었던 건,

  • 일단 arr[i] 중에서 최솟값을 찾아서 min에 넣어주고 싶었고,
    -> 첫번째는 성공했다.

  • 최솟값의 위치인 인덱스 i를 찾아서, 배열에서 그 요소만 빼주고 싶었다.
    -> i는 구했는데, 배열에서 그 요소만 빼주는건 실패했다. 아무리 생각해도 구현불가!

-> 그래서 다른 방법인 알고리즘을 참고 블로그에서 데려왔다!
이 방법은 처음 ~ 최솟값 위치 전, 최솟값 위치 후~ 끝 까지를 복사하는걸로,
최솟값인 인덱스만 쏙 빼고 복사하겠다는 얘기다.


디버거 쓸땐 F8을 쓰자! 그러면 시작점 - 종점만 찍어도 그 사이를 한줄한줄 다 돌아가준다.

F9로 고통받던 나날이여 안녕...!! 🥺 가은 매니저님 감사해요 🥺🥺🥺


  • 반복을 시켜야 하는데, 반드시 길이가 중요한게 아닐 때라면 for가 아니라 while을 써보는 것도 좋다!

  • 나중에 런타임 에러가 나는 경우라면, for문의 갯수를 줄일 수는 없는지 고민해보자.

  • 하지만 그게 생각보다 어렵다면, continue나 break를 사용해보자


sout를 쓰면 부끄러움은 나의 몫...

sout 대신 log를 쓰는게 좋다. 나중 가면 정말 디버깅만 써야해!!

콜라츠 추측이 왜이리 어려워 - 후위연산자의 위치는 항상 조심!!!

          cnt++;
            answer = cnt;

            if (num == 1) {
                break;
            }

여기서 if절과 증감연산자의 위치에 따라서 횟수가 1씩 차이난다!!

class Solution {
    public int solution(int num) {
        int answer = 0;
        int cnt = 0;
        int i;

        long longn = (long) num;

        for (i = 0; i < 500; i++) {
            if (longn == 1) {
                break;
            }
            if (longn % 2 == 0) {
                longn = longn / 2;
            } else if (longn % 2 != 0) {
                longn = (longn * 3) + 1;
            }

            cnt++;
            answer = cnt;

            if (cnt >= 500) {
                answer = -1;
            }
        }
        return answer;
    }
}

계속 안되다가 되었는데 num이 바로 1을 받았을 때도 계속 for문을 도는게 문제였다.
break를 걸어서 해결했다!


아니 하샤드 수가 대체 뭔데? 미치겠어요🤯🤯🤯🤯🤯

class Solution {
    public boolean solution(int x) {
        int q = 0;
        int div;

        int i;
        int fisrtx = x;
        for (i =  (int) Math.log10(x) ; i >= 0; i--) {
            div = (int) Math.pow(10, i); //10의 거듭제곱으로 나눠서 각 자리를 돌아보자
            q += x / div;

            if (fisrtx != (int) Math.pow(10, i)) {
                x = x - (q * div);
            }

             // 몫으로 해당 자리 숫자(한자릿수)만 뽑고 싶어서 -> n에서 몫 * 해당 자릿수만큼을 통채로 빼줬다!

            System.out.println("자릿수합: " + q);
            System.out.println("나머지는: " + fisrtx % q);
        }
        return  ((fisrtx >= 1 && fisrtx <= 10000) && fisrtx % q == 0);
    }
}
  • 위와같이 했더니 와장창창창 틀렸다! 대체 div에 -가 붙어 나오는 이유가 뭐란 말인가!?
    -> 이유는 내가 몫을 '뺄셈으로 구하려고 했기 때문' 이었다!

  • 다음 계산의 피젯수를 이전 계산의 나머지로 설정하는 식으로 해야 탈이 없었다!
    -> 도연님의 병정개미 코드가 정말 도움이 많이 됐다!
    도연님 천재... 천사... 에인절... 빛나는 전공자의 클린코드 8ㅅ8...♥♥♥

아래는 정답코드!

class Solution {
    public boolean solution(int x) {
        int q = 0;
        int div;

        int i;
        int fisrtx = x;
        for (i = (int) Math.log10(x); i >= 0; i--) {
            div = (int) Math.pow(10, i); 
            q += x / div;
            x %= div;
            
            if (div <= 0) {
                break;
            }
        }
        return ((fisrtx >= 1 && fisrtx <= 10000) && fisrtx % q == 0);
    }
}

테스트 통과했으니 답도 맞겠지 했는데, 제출시에 계속 틀려서 엄청 고생.

101이나 10의 거듭제곱수 처럼 중간 자리가 0인 경우도 핸들링하는 수식이 아니면,
/ by zero가 되거나 괴상하게 음수가 되어 버리더라.

중간 자릿수들에 0이 있는데 각 자릿수인 x를 뺄셈으로 구하려고 했더니 이렇게 나와버려서,
변수를 하나 선언해서 몫만 다 더하고, 그 아래에는 나머지를 새 피젯수로 사용하는 변수를 선언.

그리고 혹시나 / zero나 음수 문제가 없도록, div <= 0 이면 break 로 for문 탈출!

새벽까지 함께 해주신 동진님께 감사의 말씀을 드린다. 어찌저찌 내 힘으로 풀어냈구나. 🥰🥰


JAVA 알고리즘 풀이를 너무 못해서 도망가고 싶다는 생각을 정말 많이 하는 중.
이대로 괜찮은건지. 좀더 다른 분들처럼 속도를 내고 싶은데. 이해도 구현도 너무 느려 속상🥺🥺🥺🥺
건호님의 자신이 ㅃㄷㄱ이라는 말씀은 기만이야. 진짜 ㅃㄷㄱ 여기있어요😭😭😭😭

매니저님이 진도율이 좋은 걷기반을 경보반 이라고 부르는 경우도 있다고 하셨는데,
어... 음... 결국 경보는커녕 경고수준의 속도로 겨우겨우 걷기반 문제만 꾸역꾸역 끝.

그렇지만 10년 전 교양 찍먹때라면 못했을 걸 지금은 하고 있으니까,
부끄럽지 않게 개발자 커플이 될 수 있도록 어떻게든 달려야 할것.
어차피 원하던 업계에 남으려면 피할 수 없어😤😤😤😤

원빈 멘토님의 몸을 세개로 나누라는 말씀을 이제 실행해야 할 때가 오는구나...🤔

profile
갑자기 왜 춤춰?

0개의 댓글