프로그래머스LV0_1

코딩테스트 스터디

목록 보기
16/39

목적

  • LV0 문제를 풀면서 자바 기초를 익히고 부족한 구현 연습을 하기 위한 시리즈
  • 해당 시리즈는 두서 없이 문제와 해결코드 및 회고를 간단히 기록

기록

  • String 비교 시 ‘==’ 사용 시 자바에서는 내용이 아니라 메모리 주소값을 비교함 따라서 .equals()를 사용해야 함
  • 배열 선언 시 new int[크기]를 해야 인덱스 삽입이 가능함
  • 문자열↔정수형
    • Integer.parseInt(str) : int 형 반환
    • Integer.valueOf(str) :Integer 객체 반환
    • String.valueOf(num)
    • Integer.toString(num)
  • 문자열 반전
    • StringBuffer : 스레드 안전성이 있어서 내부적으로 동기화 키워드가 적용

    • StringBuilder : 스레드 안전성이 없지만 속도가 빠름→메서드 안에서 객체를 생성하고 쓰고 버리는 지역 변수면 거의 무관

      // StringBuilder
      String answer = new StringBuilder(my_string).reverse().toString();
      
      // StringBuffer
      StringBuffer sb = new StringBuffer(my_string);
      String answer = sb.reverse().toString();
문자열 뒤집는 함수를 몰라서 서치해서 정리했다.

- Array sort ```java // 오름차순 import java.util.Arrays; int[] arr = {5, 2, 8, 1, 3}; Arrays.sort(arr); // 내림차순 import java.util.Arrays; import java.util.Collections; Integer[] arr = {5, 2, 8, 1, 3}; Arrays.sort(arr, Collections.reverseOrder()); // 일부 정렬 int[] arr = {5, 2, 8, 1, 3}; Arrays.sort(arr, 0, 3); // 인덱스 0, 1, 2만 정렬 ``` ##### 정렬하는 것은 일반 문제에서 자주 사용하는 것이기에 잘 기억하자!
  • 문자열 포함 여부 함수
    class Solution {
        public int solution(String str1, String str2) {
            int answer = (str1.contains(str2))? 1 : 2;
            return answer;
        }
    }
문자열 포함 여부를 판단하는 contains 함수 사용 방법

  • 문자열 foreach
    class Solution {
        public String solution(String my_string, int n) {
            String answer = "";
            for(char c : my_string.toCharArray()){
                for(int i = 0; i < n; i++){
                    answer += c;
                }
            }
            return answer;
        }
    }
문자열 foreach하는 방법, c++처럼 인덱스 접근은 charAt(idx)임

  • 문자열 대체
    class Solution {
        public String solution(String my_string, String letter) {
            String answer = my_string.replace(letter, "");
            return answer;
        }
    }
replace 함수로 문자가 있는 부분을 원하는 문자로 대체 가능

  • 문자열 대문자, 소문자 변환
    class Solution {
        public String solution(String my_string) {
            String answer = "";
            for(char c : my_string.toCharArray()){
                if(Character.isUpperCase(c)){
                    answer += Character.toLowerCase(c);
                }
                else{
                    answer += Character.toUpperCase(c);
                }
            }
            return answer;
        }
    }
Char 자료형의 대소문자 비교와 대소문자 변환 메소드 파악

  • 분수의 덧셈
    class Solution {
        public int[] solution(int numer1, int denom1, int numer2, int denom2) {
            int[] answer = new int[2];
            int num = numer1 * denom2 + numer2 * denom1;
            int den = denom1 * denom2;
            int g = gcd(num, den);
            answer[0] = num / g;
            answer[1] = den / g;
            return answer;
        }
        
        private int gcd(int a, int b){
            while(b != 0){
                int tmp = a % b;
                a = b;
                b = tmp;
            }
            return a;
        }
    }
처음에 최대공약수를 구하지 않고 구하려다가 실수가 나서 그냥 최대공약수를 구하는 것이 실수를 방지할 수 있을 것 같다.

  • 최빈값 구하기
    class Solution {
        public int solution(int[] array) {
            int answer = 0;
            int[] cnt = new int[1001];
            for(int num : array){
                cnt[num]++;
            }
            int maxCnt = 0;
            for(int i = 0; i < cnt.length; i++){
                if(maxCnt < cnt[i]){
                    maxCnt = cnt[i];
                    answer = i;
                }
                else if(maxCnt == cnt[i]){
                    answer = -1;
                }
            }
            return answer;
        }
    }
전체 수의 범위가 크지 않으므로 count 배열로 나온 개수를 세서 최빈값을 찾음

  • 옹알이(1)
    class Solution {
        public int solution(String[] babbling) {
            int answer = 0;
            String[] str = { "aya", "ye", "woo", "ma" };
            for(String s : babbling){
                for(String st : str){
                    if(s.contains(st)){
                        s = s.replace(st, " ");
                    }
                }
                s = s.replace(" ", "");
                if(s.equals("")) answer++;
            }
            return answer;
        }
    }
문자열 처리하는 것이 미숙하다. 처음에 replace를 띄워쓰기가 아닌 ""으로 대치하면 wayeoo같은 경우도 발음이 가능한 것으로 되어 띄워쓰기로 대치 후 반복문이 끝나면 빈 문자로 대치하여 해결

  • 평행
    class Solution {
        public int solution(int[][] dots) {
            if(comp(dots[0], dots[1], dots[2], dots[3]))
                return 1;
            if(comp(dots[0], dots[2], dots[1], dots[3]))
                return 1;
            if(comp(dots[0], dots[3], dots[1], dots[2]))
                return 1;
            return 0;
        }
        
        private boolean comp(int[] dot1, int[] dot2, int[] dot3, int[] dot4){
            int nx1 = dot1[0] - dot2[0];
            int ny1 = dot1[1] - dot2[1];
            int nx2 = dot3[0] - dot4[0];
            int ny2 = dot3[1] - dot4[1];
            return (ny1 * nx2) == (ny2 * nx1);
        }
    }
기울기로 구하는 것으로 접근했는데 나누는 수가 0이 될 수도 있고 세 점이 겹쳐지는 경우가 문제가 될 수 있어 기울기 =ny1nx1=ny2nx2= \frac{ny_1}{nx_1} = \frac{ny_2}{nx_2} 이 공식을 대각선으로 곱해서 ny1×nx2=ny2×nx1ny_1 \times nx_2 = ny_2 \times nx_1 로 바꾸어 나눗셈 없이 해결

  • 겹치는 선분의 길이
    class Solution {
        public int solution(int[][] lines) {
            int answer = 0;
            for(int i = -100; i <= 100; i++){
                int cnt = 0;
                for(int j = 0; j < lines.length; j++){
                    int a = lines[j][0], b = lines[j][1];
                    if(a <= i && b > i) cnt++;
                }
                if(cnt >= 2){
                    answer++;
                }
            }
            return answer;
        }
    }
해당 점이 포함되는지 체크할 때 a ≤ i && b > i 로 b ≥ i 가 아닌 이유는 점 기준이 아니라 구간으로 생각해야 하기 때문(ex. [0, 1] 이면 0과 1 모두 비교하지만 길이는 1임)

  • 정수를 나선형으로 배치하기
    class Solution {
        public int[][] solution(int n) {
            int[][] answer = new int[n][n];
            int[] dr = {0, 1, 0, -1};
            int[] dc = {1, 0, -1, 0};
            int dir = 0, r = 0, c = 0;
            for(int i = 1; i <= n * n; i++){
                answer[r][c] = i;
                int nr = r + dr[dir], nc = c + dc[dir];
                if(nr < 0 || nc < 0 || nr >= n || nc >= n || answer[nr][nc] != 0){
                    dir = (dir + 1) % 4;
                    nr = r + dr[dir];
                    nc = c + dc[dir];
                }
                r = nr;
                c = nc;
            }
            return answer;
        }
    }
배열의 끝까지 도달하면 다음 방향으로 바꿔 채워가면 해결

  • 주사위 게임 3
    import java.util.HashMap;
    import java.util.Map;
    
    class Solution {
        public int solution(int a, int b, int c, int d) {
            int answer = 0;
            Map<Integer, Integer> map = new HashMap<>();
            int[] nums = {a, b, c, d};
            for(int num : nums){
                map.put(num, map.getOrDefault(num, 0) + 1);
            }
            if(map.size() == 1){
                answer = a * 1111;
            }
            else if(map.size() == 2){
                int p = 0, q = 0;
                for(Integer key : map.keySet()){
                    if(map.get(key) == 3){
                        p = key;
                        if(q != 0)
                            answer = (int)Math.pow((10 * p + q), 2);
                    }
                    else if(map.get(key) == 2){
                        if(p == 0) p = key;
                        else{
                            q = key;
                            answer = (p + q) * Math.abs(p - q);
                        }
                    }
                    else if((map.get(key) == 1)){
                        q = key;
                        if(p != 0)
                            answer = (int)Math.pow((10 * p + q), 2);
                    }
                }
            }
            else if(map.size() == 3){
                int p = 0, q = 0, r = 0;
                for(Integer key : map.keySet()){
                    if(map.get(key) == 2){
                        p = key;
                    }
                    else if((map.get(key) == 1)){
                        if(q == 0) q = key;
                        else{
                            r = key;
                            answer = q * r;
                        }
                    }
                }
            }
            else{
                answer = Math.min(a, Math.min(b, Math.min(c, d)));
            }
            return answer;
        }
    }
    
    // 개선
    import java.util.*;
    
    class Solution {
        public int solution(int a, int b, int c, int d) {
            Map<Integer, Integer> map = new HashMap<>();
            for (int n : new int[]{a, b, c, d}) map.put(n, map.getOrDefault(n, 0) + 1);
            List<Integer> keys = new ArrayList<>(map.keySet());
            keys.sort((k1, k2) -> map.get(k2) - map.get(k1)); 
    
            switch (map.size()) {
                case 1:
                    return 1111 * a;
                case 2:
                    int p = keys.get(0), q = keys.get(1);
                    if (map.get(p) == 3) {
                        return (int) Math.pow(10 * p + q, 2);
                    } else {
                        return (p + q) * Math.abs(p - q);
                    }
                case 3:
                    return keys.get(1) * keys.get(2);
                default:
                    return Collections.min(map.keySet());
            }
        }
    }
Map를 활용하여 해결했지만 내가 봐도 코드가 좀 너져분해서 개선을 시도했다. Map을 정렬하고 switch문을 활용하여 개선했다.

  • 안전지대
    class Solution {
        public int solution(int[][] board) {
            int answer = 0;
            int n = board.length;
            int[][] b = new int[n][n];
            int[] dx = {-1, 1, 0, 0, -1, 1, 1, -1}, dy = {0, 0, -1, 1, -1, 1, -1, 1};
            for(int i = 0; i < n; i++){
                for(int j = 0; j < n; j++){
                    if(board[i][j] == 1){
                        b[i][j] = 1;
                        for(int k = 0; k < 8; k++){
                            int nx = dx[k] + i;
                            int ny = dy[k] + j;
                            if(nx < 0 || ny < 0 || nx >= n || ny >= n) continue;
                            b[nx][ny] = 1;
                        }
                    }
                }
            }
            for(int i = 0; i < n; i++){
                for(int j = 0; j < n; j++){
                    if(b[i][j] == 0) answer++;
                }
                System.out.println();
            }
            return answer;
        }
    }
1인 해당 좌표에서 8방향으로 체크해야 하므로 dx, dy로 8방향을 체크하여 해결

  • 연속된 수의 합
    class Solution {
        public int[] solution(int num, int total) {
            int[] answer = new int[num];
            int mid = total / num;
            int mid_idx = (num % 2 == 0)? (num / 2 - 1) : (num / 2);
            for(int i = 0; i < num; i++){
                answer[i] = mid + (i - mid_idx);
            }
            return answer;
        }
    }
문제를 생각해보니 중앙값은 전체 합에서 개수로 나눈 값인 것을 파악하여 해결

  • 다음에 올 숫자
    class Solution {
        public int solution(int[] common) {
            int answer = 0;
            if(common[1] - common[0] == common[2] - common[1]){
                int d = common[1] - common[0];
                answer = common[common.length - 1] + d;
            }
            else{
                int r = common[1] / common[0];
                answer = common[common.length - 1] * r;
            }
            return answer;
        }
    }
배열 크기가 최소 3이므로 0, 1, 2의 차이를 비교하여 등차인지 등비인지 파악하고 마지막 값을 구함

  • OX 퀴즈
    class Solution {
        public String[] solution(String[] quiz) {
            String[] answer = new String[quiz.length];
            int idx = 0;
            for(String str : quiz){
                String[] parts = str.split(" ");
                int x = Integer.parseInt(parts[0]);
                int y = Integer.parseInt(parts[2]);
                int z = Integer.parseInt(parts[4]);
                String op = parts[1];
                if(op.equals("+")){
                    if(x + y == z) answer[idx++] = "O";
                    else answer[idx++] = "X";
                }
                else{
                   if(x - y == z) answer[idx++] = "O";
                    else answer[idx++] = "X"; 
                }
            }
            return answer;
        }
    }
문자열 처리가 아직 미숙하다. 처음에 인덱스 접근으로 해결하려다가 실패...문제를 보니 띄워쓰기를 두고 숫자와 연산자가 있어 split으로 문자를 쪼개면 쉽게 해결이 된다.

  • 특이한 정렬
    import java.util.*;
    
    class Solution {
        public int[] solution(int[] numlist, int n) {
            int[] answer = new int[numlist.length];
            ArrayList<Integer> list = new ArrayList<>();
            for(int num : numlist) {
                list.add(num);
            }
            Collections.sort(list, (a, b) -> {
                int distA = Math.abs(a - n);
                int distB = Math.abs(b - n);
                if (distA == distB) return b - a;
                return distA - distB;
            });
            for(int i = 0; i < list.size(); i++) {
                answer[i] = list.get(i);
            }
            return answer;
        }
    }
사용자 지정 조건 정렬 방법으로 람다 함수를 사용하려고 했는데 계속 c++ 방식으로 시도한다. 자바는 람다 함수 반환값이 boolean이 아니라 int를 반환해야 한다. 또한 기본 배열을 람다 함수를 사용하지 못한다.

  • 코드 처리하기
    class Solution {
        public String solution(String code) {
            String answer = "";
            int mode = 0;
            for(int i = 0; i < code.length(); i++){
                if(code.charAt(i) == '1'){
                    if(mode == 1) mode = 0;
                    else mode = 1;
                }
                else if(mode == 1 && i % 2 == 1){
                    answer += code.charAt(i);
                }
                else if(mode == 0 && i % 2 == 0){
                    answer += code.charAt(i);
                }
            }
            if(answer.equals("")) answer = "EMPTY";
            return answer;
        }
    }
    
    // 개선
    class Solution {
        public String solution(String code) {
            StringBuilder answer = new StringBuilder();
            int mode = 0;
            for(int i = 0; i < code.length(); i++){
                if(code.charAt(i) == '1'){
                    mode = 1 - mode;
                }
                else if(mode == 1 && i % 2 == 1){
                    answer.append(code.charAt(i));
                }
                else if(mode == 0 && i % 2 == 0){
                    answer.append(code.charAt(i));
                }
            }
            String ans = answer.toString();
            if(ans.equals("")) ans = "EMPTY";
            return ans;
        }
    }
문제를 해결하였지만 개선할 수 있을 것 같아 시도해보았다. mode를 한 줄로 바꿨으며 answer += code.charAt(i) 부분은 매번 새로운 문자를 생성하는 것으로 문자열이 길어지면 성능상 문제가 생길 수 있다는 것을 알아내어 StringBuilder의 append를 활용하여 개선했다.

profile
개발자가 되기 위해 열심히 춤추는 중이에요 🕺

0개의 댓글