프로그래머스 Lv.1 (8)

21.01.21 ~ 21.01.26

📌 자릿수 더하기

초기 코드

import java.util.*;

public class Solution {
    public int solution(int n) {
        int answer = 0;
        answer;
    }
}

내가 작성한 코드

import java.util.*;

public class Solution {
    public int solution(int n) {
        int answer = 0;
        String str = Integer.toString(n);
        for (int i = 0; i < str.length(); i++) {
            answer += n % 10;
            n /= 10;
        }

        return answer;
    }
}

어제였나 풀어봤던 문제랑 비슷하게 각 자리수를 활용하는 문제라 마찬가지로 10으로 나눈 나머지와 몫을 활용해봤다. int는 string이랑 다르게 길이를 구할 수 없어서 저렇게 별도의 str에 담아서 length()를 사용했는데, 다른 사람의 풀이를 구경해서 더 좋은 방법을 찾았다.

다른 사람의 풀이

import java.util.*;

public class Solution {
    public int solution(int n) {
        int answer = 0;
        while (n != 0) {
            answer += n % 10;
            n /= 10;
        }
        return answer;
    }
}

n != 0 이니까 n을 계속 나누다가 1의 자리만 남는 순간까지 반복하고, 몫이 0이 되면 반복문을 멈춘다. 조건을 좀 더 영리하게 쓰면 되는 거였는데 아는 방법을 쓰려고 냅다 str에 담아버린 게 아쉬웠던 문제.. 엄청 쉬운 연습문제라고 편하게 풀고 싶었나보다 ㅋㅋ.


📌 비밀지도 (카카오 2018 블라인드 채용)

초기 코드

import java.util.*;
class Solution {
    public String[] solution(int n, int[] arr1, int[] arr2) {
        String[] answer = {};
        
        return answer;
        
    }
}

내가 작성한 코드

import java.util.*;
class Solution {
    public String[] solution(int n, int[] arr1, int[] arr2) {
        String[] answer = new String[n];
        String[] str1 = new String[n];
        String[] str2 = new String[n];
        
        for (int i = 0; i < n; i++) {
            str1[i] = Integer.toBinaryString(arr1[i]);
            str2[i] = Integer.toBinaryString(arr2[i]);
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (str1[i].charAt[j] == ' ' && str2[i].charAt[j] == ' ') {
                    answer[i] += " ";
                }
                else {
                    answer[i] += "#";
                }
            }
        }
        
        return answer;
        
    }
}

지도1과 지도2의 10진수를 2진수로 변환
-> 변환한 2진수는 str타입이니까 charAt(i)로 10110 이런 숫자에서 한 자리만 골라 공백인지 확인
-> 공백이면 answer[i]에 " "를, 아니라면 "#"을 삽입한다. 이때 answer[i]는 총 n자리의 문자열이 들어가야 하니까 str1[i]의 모든 자리수 j가 끝까지 돌아야 answer[i+1]로 넘어간다. 그 전까지는 계속 " "이든 "#"이든 추가되게 구성했다.

그리고 만난 이 인덱스 오류...
반복문 돌릴 때 쓴 인덱스에서 뭔가 잘못 된 것 같았다.

System.out.print(Arrays.toString(str1));
위 코드를 써써 출력을 해보니까 아래처럼 나왔다.
[1001, 10100, 11100, 10010, 1011]
이런 식이었다. 1로 시작하는 건 잘 담겼지만, 0으로 시작하는 건 떼어먹고 담겨서 뒤에 나올 반복문에서 인덱스 오류가 생겼나보다.
Integer.toBinaryString(str1[i]) 말고 다른 메소드를 사용하기로 했다.

for (int i = 0; i < n; i++) {
            for (int j = n-1; j > 0; j--) {
                str1[i][j] = arr1[i] % 2;
                arr1[i] /= 2;
                str2[i][j] = arr2[i] % 2;
                arr2[i] /= 2;
            }
        }

이렇게 해도 인덱스 오류가 뜬다.. 역순으로 삽입하는 게 내 생각이랑은 다르게 돌아가나보다. 이쯤 되면 내가 어마어마한 삽질을 하고 있는 건 아닐까?하는 생각이 드는 순간이다. 다른 사람의 풀이로 공부를 하는 게 더 빠르고 생산적이라는 판단이 들면 얼른 다른 사람의 풀이를 찾아본다. ㅠㅠ...

다른 사람의 풀이 1

class Solution {
    public String decoding(int n1, int n2, int n){
        String zero = "";
        String s = Integer.toBinaryString(n1 | n2); //(1)
        
        if(s.length() < n) { //(2)
            for(int i = s.length(); i < n; i++){
                zero += "0";
            }
        }
        return zero + s;
    }
    
    public String[] solution(int n, int[] arr1, int[] arr2) {
        String[] answer = new String[n];
        for(int i = 0; i < n; i++){
            answer[i] = decoding(arr1[i], arr2[i], n);
            answer[i] = answer[i].replaceAll("[1]", "#"); //(3)
            answer[i] = answer[i].replaceAll("[0]", " "); //(4)
        }
        return answer;
    }
}

(1) java 강의 들을 때 배웠던 비트 연산자를 잊고 있었다..... or와 같은 역할을 하니까, 1 | 0 -> 1이고 0 | 0 -> 0이다. 이 문제에서 요구하는 " "과 "#"의 or을 정확하게 반영한 비트 연산자.... 이걸 활용한다면 굳이 나처럼 이중배열에 담고 뒤집고 난리가 날 필요가 없었다. 연산자 하나로 이렇게 간단하게 풀리다니! 무조건 str 또는 char로 비교하려고 했던 걸 반성한다..
(2) 맨 앞이 0일 때 잘리지 않게 출력하도록 길이를 조건으로 걸어서 별도로 0을 붙여주는 방법을 택했다.
(3) 1을 #으로, 0을 공백으로 바꿀 때에는 함수 replaceAll을 사용했다. 이런 좋은 방법이 있는 지 몰랐네ㅠ

다른 사람의 풀이 2

class Solution {
  public String[] solution(int n, int[] arr1, int[] arr2) {
        String[] result = new String[n];
        for (int i = 0; i < n; i++) {
            result[i] = Integer.toBinaryString(arr1[i] | arr2[i]);
        }

        for (int i = 0; i < n; i++) {
            result[i] = String.format("%" + n + "s", result[i]); //(1)
            result[i] = result[i].replaceAll("1", "#");
            result[i] = result[i].replaceAll("0", " ");
        }

        return result;
    }
}

(1) 문자열의 길이를 n으로 맞춰줘야 한다. 풀이 1에서는 if문을 써 n보다 짧으면 맨 앞에 0을 추가했지만, 여기서는 String.format("%" + n + "s", result[i])으로 resutl[i]의 길이를 n으로 지정한다.
str에서 형 변환 없이도 이런 방법을 생각하다니,,


📌 나머지가 1이 되는 수 찾기

초기 코드

class Solution {
    public int solution(int n) {
        int answer = 0;
        return answer;
    }
}

내가 작성한 코드

class Solution {
    public int solution(int n) {
        int answer = 0;
        for (int i = 2; i < n; i++) {
        	if (n % i == 1) {
            	answer = i;
                break;
            }
        }
        return answer;
    }
}

원리도 간단하고 주어진 조건도 명확해서 보자마자 바로 풀 수 있었던 문제였다.


📌 예산

초기 코드

class Solution {
    public int solution(int[] d, int budget) {
        int answer = 0;
        return answer;
    }
}

이 날은 무슨 날이었는지 머리가 하나도 안 돌아가고 ㅋㅋ 무조건 그룹을 지어서 sum을 내서 budget이랑 비교하려고 하니 절대로 안 풀릴 거라는 게 느껴졌다. 괜히 시간 많이 쓰느니 얼른 공부하고 다음에 돌아오겠다는 마음으로 다른 사람 풀이를 먼저 공부했다.

다른 사람의 풀이

import java.util.Arrays;
class Solution {
    public int solution(int[] d, int budget) {
        int answer = 0;
        Arrays.sort(d); //(1)
        for (int i = 0; i < d.length; i++) {
            if (d[i] <= budget) {
                budget -= d[i]; //(2)
                answer++;
            }
            else {
                break;
            }
        }
        return answer;
    }
}

(1) 우선 sort를 해주면 각 부서의 금액이 오름차순 정렬되니까,
(2) 제일 작은 값부터 budget에서 빼줄 수 있게 반복문을 구성한다.
최대한 많은 부서를 지원하는 것이 목표이므로 작은 금액이 여러 개인 조합이 최선이라는 점을 반영한 것 같다.
나는 무조건 둘, 셋 이렇게 묶어서 예산과 비교하려고 했으니 저렇게 sort부터 하는 방법은 고려하지 않았다.. 이렇게 간단히 풀릴 줄은 몰라서 좀 어이없었다. 다음엔 이렇게 풀어주겠어 하는 마음으로 두고 넘어간다...ㅠ


📌 2016년

초기 코드

class Solution {
    public String solution(int a, int b) {
        String answer = "";
        return answer;
    }
}

내가 작성한 코드

import java.util.Arrays;
class Solution {
    public String solution(int a, int b) {
        String answer = "";
        Integer[] big = {1, 3, 5, 7, 8, 10, 12};
        Integer[] small = {4, 6, 9, 11};
        //1월이면 일자 - 일자만 해서 구함
        // 2월이면 29일이 마지막 날
        String[] days = {"FRI", "SAT", "SUN", "MON", "TUE", "WED", "THU"};
        
        if (a == 1) { //(1)
            answer = days[(b-1) % 7];
        }
        else {
            for (int i = 1; i < a; i++) { 
                if (Arrays.asList(big).contains(i)) { //(2)
                    b += 31;
                }
                else if (Arrays.asList(small).contains(i)) { //(3)
                    b += 30;
                }
                else { //(4)
                    b += 29;
                } 
            }
            answer = days[(b-1) % 7];
        }
        return answer;
    }
}

예전에 대소문자에 따라 다른 작업을 수행해야 했던 문제에서 저렇게 샘플로 리스트를 만들어놓고 가져다 썼던 기억이 나서 비슷하게 작성했다. 29일짜리인 2월은 따로 빼고, 30일 짜리인 달과 31일 짜리인 달을 각각 묶어놨다. 그리고 리턴할 요일이름은 str 타입으로 배열에 담아뒀다. 첫 요일이 "FRI"인 건 경과한 일자수를 7로 나눴을 때 나머지에 따라 요일이 달라지는데 1월1일이 금요일이라고 주어졌기 때문이다.

(1) 주어진 날짜가 1월 중이라면 일자만 빼서 요일을 바로 구한다. b-1은 1월 1일 기준 얼마나 경과했는지를 따지기 위한 경과 일수다.
(2) a월에 도달하기 전까지 반복하는데, i월을 가지고 반복한다. 31일짜리 달이라면 경과일수(b)에 30일을 누적한다.
(3) 마찬가지로 30일짜리 달이면 30을 누적한다.
(4) 혼자만 29일짜리인 2월이라면 29를 누적한다.
마지막에 answer에는 총 경과일수를 7로 나눈 나머지를 가지고 요일을 담아둔 days 배열에서 정답 요일을 골라 반환한다.
그나마 제일 내 힘으로 한 문제였다. 아, integer 배열에서 특정 원소의 포함 여부를 확인할 때 어떤 메소드를 쓸지는 잘 모르겠어서 검색해봤다. 내가 아는 단순히 indexOf > 0 나 contains는 문자열 대상이라서 쓸 수 없어서 찾아봤다. Arrays 클래스에서 지원하는 저런 메소드를 쓰면 int 배열에서도 원하는 원소의 포함 여부를 trur, false로 반환해준다.
스스로 풀어서 보람차다 ^_^.

좋은 웹페이지 즐겨찾기