백준: 9012번 괄호 (자바, Java)
[백준] 9012번 괄호https://www.acmicpc.net/problem/9012     문제괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올바른 괄호 문자열(Valid PS, VPS)이라고 부른다. 한 쌍의 괄호 기호로 된 “( )” 문자열은 기본 VPS 이라고 부른다. 만일 x 가 VPS 라면 이것을 하나의 괄호에 넣은 새로운 문자열 “(x)”도 VPS 가 된다. 그리고 두 VPS x 와 y를 접합(concatenation)시킨 새로운 문자열 xy도 VPS 가 된다. 예를 들어 “(())()”와 “((()))” 는 VPS 이지만 “(()(”, “(())()))” ..
2024.05.21
백준: 2525번 오븐 시계 (자바, Java)
[백준] 2525번 오븐 시계https://www.acmicpc.net/problem/2525    문제KOI 전자에서는 건강에 좋고 맛있는 훈제오리구이 요리를 간편하게 만드는 인공지능 오븐을 개발하려고 한다. 인공지능 오븐을 사용하는 방법은 적당한 양의 오리 훈제 재료를 인공지능 오븐에 넣으면 된다. 그러면 인공지능 오븐은 오븐구이가 끝나는 시간을 분 단위로 자동적으로 계산한다. 또한, KOI 전자의 인공지능 오븐 앞면에는 사용자에게 훈제오리구이 요리가 끝나는 시각을 알려 주는 디지털 시계가 있다. 훈제오리구이를 시작하는 시각과 오븐구이를 하는 데 필요한 시간이 분단위로 주어졌을 때, 오븐구이가 끝나는 시각을 계산하는 프로그램을 작성하시오. 입력 :첫째 줄에는 현재 시각이 나온다. 현재 시각은 시 A ..
2024.05.20
no image
백준: 2588번 곱셈 (자바, Java)
[백준] 2388번 곱셈https://www.acmicpc.net/problem/2588   문제(세 자리 수) × (세 자리 수)는 다음과 같은 과정을 통하여 이루어진다.(1)과 (2)위치에 들어갈 세 자리 자연수가 주어질 때 (3), (4), (5), (6)위치에 들어갈 값을 구하는 프로그램을 작성하라 입력 : 첫째 줄에 (1)의 위치에 들어갈 세 자리 자연수가, 둘째 줄에 (2)의 위치에 들어갈 세자리 자연수가 주어진다. 출력 : 첫째 줄부터 넷째 줄까지 차례대로 (3), (4), (5), (6)에 들어갈 값을 출력한다. 나의 답안 일단 (6)은 그냥 A*B 해주면 되고.. 100의 자리 수는 100으로 나눠주면 몫이 그것이고, 1의 자리는 A를 10으로 나눈 나머지로 하면 되겠네? 생각했다. 그리..
2024.05.19
프로그래머스: 도둑질 (자바, Java)
[프로그래머스] 도둑https://school.programmers.co.kr/learn/courses/30/lessons/42897   문제도둑이 어느 마을을 털 계획을 하고 있습니다. 이 마을의 모든 집들은 동그란 형태로 배치되어 있다.각 집들은 서로 인접한 집들과 방범장치가 연결되어 있어 인접한 두 집을 연속으로 털면 경보가 울린다. 각 집에 있는 돈이 담긴 배열 money가 주어질 때, 도둑이 훔칠 수 있는 돈의 최댓값을 return 하는 메서드를 작성하라.   나의 답안몇 시간을 헤맨 끝에 겨우 풀었다. 아래 코드들처럼 이것저것 시도해 보았으나 테스트케이스 및 효율성 검사에서 탈락.   첫 번째 코드(오답)import java.util.*;class Solution {    public int[..
2024.05.09
프로그래머스: 배열 조각하기 (자바, Java)
[프로그래머스] 배열 조각하기https://school.programmers.co.kr/learn/courses/30/lessons/181893  문제정수 배열 arr와 query가 주어지며, query를 순회하면서 다음 작업을 반복한다. 짝수 인덱스에서는 arr에서 query[i]번 인덱스를 제외하고 배열의 query[i]번 인덱스 뒷부분을 잘라서 버림홀수 인덱스에서는 arr에서 query[i]번 인덱스는 제외하고 배열의 query[i]번 인덱스 앞부분을 잘라서 버림위 작업을 마친 후 남은 arr의 부분 배열을 return 하는 solution 함수를 완성하라   나의 답안나는 문제에서 말하는 알고리즘대로 remove 메서드를 이용하여 짝수 인덱스에서는 뒷부분을 자르고,홀수 인덱스에서는 앞부분을 잘라내..
2024.05.08
프로그래머스 풀이: 주사위게임 2(자바, Java)
[프로그래머스] Level 0 주사위게임2 문제 세 주사위를 던졌을 때 나온 숫자를 각각 a, b, c라고 할 때 얻는 점수는 다음과 같다. 세 숫자가 모두 다르면 a + b + c 점을 얻는다. 두 숫자는 같고 나머지 숫자는 다르다면 (a + b + c) × (a2 + b2 + c2 )점을 얻 는다. 세 숫자가 모두 같다면 (a + b + c) × (a2 + b2 + c2 ) × (a3 + b3 + c3 )점을 얻 는다. 세 정수 a, b, c가 매개변수로 주어질 때, 얻는 점수를 return 하는 solution 메서드를 작성하라. 나의 답안 주사위 4개인 문제의 경우처럼 배열을 활용하여 오름차순 정렬 후 if문을 작성했는데, 다른 답안들을 보니 굳이 배열을 사용할 필요 없이 훨씬 효율적이고 간결한 ..
2024.04.10
프로그래머스 풀이: 코드 처리하기 (자바, Java)
[프로그래머스] Level 0 코드 처리하기 문제 문자열 code가 주어집니다. code를 앞에서부터 읽으면서 만약 문자가 "1"이면 mode를 바꿉니다. mode에 따라 code를 읽어가면서 문자열 ret을 만들어냅니다. mode는 0과 1이 있으며, i를 0부터 code의 길이 - 1까지 1씩 키워나가면서 code[i] 값에 따라 다음과 같이 행동합니다. mode = 0일 때 code[i]가 "1"이 아니면 i가 짝수일 때만 ret의 맨 뒤에 code[i]를 추가합니다. code[i]가 "1"이면 mode를 0에서 1로 바꿉니다. mode = 1일 때 code[i]가 "1"이 아니면 i가 홀수일 때만 ret의 맨 뒤에 code[i]를 추가합니다. code[i]가 "1"이면 mode를 1에서 0으로 바..
2024.04.09
프로그래머스 풀이: 완주하지 못한 선수 (자바, Java)
[프로그래머스] Level 1 완주하지 못한 선수 문제 마라톤 경주에서 참가자들 중 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다. 마라톤 참가 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요. 마라톤 경기에 참여한 선수의 수는 1명 이상 100,000명 이하입니다. completion의 길이는 participant의 길이보다 1 작습니다. 참가자의 이름은 1개 이상 20개 이하의 알파벳 소문자로 이루어져 있습니다. 참가자 중에는 동명이인이 있을 수 있습니다. 나의 답안(효율성 테스트 탈락) 리스트로 변환한 후, 완주한 참가자의 이름..
2024.04.08
프로그래머스 풀이: 폰켓몬 (자바, Java)
[프로그래머스] Level 1 폰켓몬 문제 박사님은 당신에게 자신의 연구실에 있는 총 N 마리의 폰켓몬 중에서 N/2마리를 가져가도 좋다고 했습니다. 홍 박사님 연구실의 폰켓몬은 종류에 따라 번호를 붙여 구분합니다. 따라서 같은 종류의 폰켓몬은 같은 번호를 가지고 있습니다. 예를 들어 연구실에 총 4마리의 폰켓몬이 있고, 각 폰켓몬의 종류 번호가 [3번, 1번, 2번, 3번]이라면 이는 3번 폰켓몬 두 마리, 1번 폰켓몬 한 마리, 2번 폰켓몬 한 마리가 있음을 나타냅니다. 이때, 4마리의 폰켓몬 중 2마리를 고르는 방법은 다음과 같이 6가지가 있습니다. 첫 번째(3번), 두 번째(1번) 폰켓몬을 선택 첫 번째(3번), 세 번째(2번) 폰켓몬을 선택 첫 번째(3번), 네 번째(3번) 폰켓몬을 선택 두 번..
2024.04.07
프로그래머스 풀이: 주사위게임3 (자바, Java)
[프로그래머스] Level 0 주사위게임3 너무 어려웠다. 오랜 시간 머리를 쥐어짰지만 아직은 역부족인가보다. 결국 노가다에 가까운 코드를 만들어 억지로 정답을 맞췄다... 문제 1부터 6까지 숫자가 적힌 네 주사위를 굴렸을 때 나온 숫자에 따라 다음과 같은 점수를 얻는다. 네 주사위에서 나온 숫자가 모두 p로 같다면 1111 × p점 세 주사위에서 나온 숫자가 p로 같고 나머지 다른 주사위에서 나온 숫자가 q(p ≠ q)라면 (10 × p + q)2 점 주사위가 두 개씩 같은 값이 나오고, 나온 숫자를 각각 p, q(p ≠ q)라고 한다면 (p + q) × |p - q|점 어느 두 주사위에서 나온 숫자가 p로 같고 나머지 두 주사위에서 나온 숫자가 각각 p와 다른 q, r(q ≠ r)이라면 q × r점..
2024.04.05


[백준] 9012번 괄호

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

 

 

 

 

 

문제

괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올바른 괄호 문자열(Valid PS, VPS)이라고 부른다. 한 쌍의 괄호 기호로 된 “( )” 문자열은 기본 VPS 이라고 부른다. 만일 x 가 VPS 라면 이것을 하나의 괄호에 넣은 새로운 문자열 “(x)”도 VPS 가 된다. 그리고 두 VPS x 와 y를 접합(concatenation)시킨 새로운 문자열 xy도 VPS 가 된다. 예를 들어 “(())()”와 “((()))” 는 VPS 이지만 “(()(”, “(())()))” , 그리고 “(()” 는 모두 VPS 가 아닌 문자열이다. 

여러분은 입력으로 주어진 괄호 문자열이 VPS 인지 아닌지를 판단해서 그 결과를 YES 와 NO 로 나타내어야 한다. 

입력 :

입력 데이터는 표준 입력을 사용한다. 입력은 T개의 테스트 데이터로 주어진다. 입력의 첫 번째 줄에는 입력 데이터의 수를 나타내는 정수 T가 주어진다. 각 테스트 데이터의 첫째 줄에는 괄호 문자열이 한 줄에 주어진다. 하나의 괄호 문자열의 길이는 2 이상 50 이하이다. 

출력 :

출력은 표준 출력을 사용한다. 만일 입력 괄호 문자열이 올바른 괄호 문자열(VPS)이면 “YES”, 아니면 “NO”를 한 줄에 하나씩 차례대로 출력해야 한다. 

 

나의 답안

 

1. counter=0 변수 선언

2. 맨 앞글자부터 '(' 일 때 counter + 1      ')' 일 때 counter - 1 해준다.

3. counter값이 0이면 YES, 아니면 NO 출력

4. 도중에 counter값이 음수가 될 경우 반복문 종료 후 NO 출력

import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
       
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());    // 입력 개수 입력

        for (int i=0; i<N; i++) {        
            String str = br.readLine(); 
            int counter = 0;
            for (int j=0; j<str.length(); j++){
                if (str.charAt(j) == '(') {
                    counter += 1;
                } else {
                    counter -= 1;
                    if (counter < 0) {
                        break;
                    }
                }
            }
            System.out.println(counter==0 ? "YES" : "NO");
        }
    }
}

 

삼항연산자를 사용하여 작성해봤다.

 

짧지만 가독성은 좋지 않다.

 

 

다른 답안

import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int N = Integer.parseInt(br.readLine());
        Stack<Character> stack = new Stack<>();

        for(int i=0; i<N; i++) {
            String str = br.readLine();
            int length = str.length();

            for(int j=0; j<length; j++) {
                char ch = str.charAt(j);

                if(ch == '(') {
                    stack.push(ch);
                }
                else {
                    int size = stack.size();
                    if(size == 0) {
                        stack.push(ch);
                        break;
                    }
                    else {
                        stack.pop();
                    }
                }
            }

            if(stack.isEmpty()) {
                System.out.println("YES");
            }
            else {
                System.out.println("NO");
            }

            stack.clear();
        }
    }
}
  • stack구조를 사용해 좀 더 간단하게 구현했다.
  • '(' 일 때 stack.push()를, ')'일 때 stack.pop()을 사용
  • ')'일 때 stack에 요소가 없으면 반복문 빠져나와 NO 출력

stack 구조를 사용해야겠다는 생각을 하지 못했다.

stack을 사용하기에 아주 좋은 문제였던 것 같다...

 

다만, counter변수를 사용하는 것이  메모리 사용량이 더 적고 연산이 간단하며,

stack을 사용하는 것은  코드의 길이를 늘리고 복잡성을 증가시킬 수 있으므로 주의


[백준] 2525번 오븐 시계

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

 

 

 

 

문제

KOI 전자에서는 건강에 좋고 맛있는 훈제오리구이 요리를 간편하게 만드는 인공지능 오븐을 개발하려고 한다. 인공지능 오븐을 사용하는 방법은 적당한 양의 오리 훈제 재료를 인공지능 오븐에 넣으면 된다. 그러면 인공지능 오븐은 오븐구이가 끝나는 시간을 분 단위로 자동적으로 계산한다.

또한, KOI 전자의 인공지능 오븐 앞면에는 사용자에게 훈제오리구이 요리가 끝나는 시각을 알려 주는 디지털 시계가 있다.

훈제오리구이를 시작하는 시각과 오븐구이를 하는 데 필요한 시간이 분단위로 주어졌을 때, 오븐구이가 끝나는 시각을 계산하는 프로그램을 작성하시오.


입력 :

첫째 줄에는 현재 시각이 나온다. 현재 시각은 시 A (0 ≤ A ≤ 23) 와 분 B (0 ≤ B ≤ 59)가 정수로 빈칸을 사이에 두고 순서대로 주어진다. 두 번째 줄에는 요리하는 데 필요한 시간 C (0 ≤ C ≤ 1,000)가 분 단위로 주어진다.

출력 :

첫째 줄에 종료되는 시각의 시와 분을 공백을 사이에 두고 출력한다. (단, 시는 0부터 23까지의 정수, 분은 0부터 59까지의 정수이다. 디지털 시계는 23시 59분에서 1분이 지나면 0시 0분이 된다.)

 

 

나의 답안

 

분이 60분이 넘을 때, 60으로 나눈 몫만큼 '시' 부분을 높여주되,

'시' 부분이 24이상일 경우에는 0부터 표현해줘야 한다.

 

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();
        int c = sc.nextInt();

        System.out.println(a+(b+c)/60 > 23 ? a+(b+c)/60-24 + " " + (b+c)%60 : a+(b+c)/60 + " " + (b+c)%60);
    }
}

 

삼항연산자를 사용하여 작성해봤다.

 

짧지만 가독성은 좋지 않다.

 

 

모범 답안

import java.util.Scanner;

public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);

int A = sc.nextInt();
int B = sc.nextInt();
int C = sc.nextInt();

B += C;

A = (A + B/60)%24;
B = B%60;

System.out.println(A+" "+B);
}
}
  • B에 C를 더한 값으로 B에 다시 할당함
  • 나는 if문을 사용해 '시'가 24 이상일 경우 24를 빼도록 작성했지만,
    해당 답안에서는 if문 사용 없이 답을 도출할 수 있도록 작성되었다.

 

B에 바로 C값을 더해주는 부분과 A값을 if문 없이 표현했다는 점이 인상 깊다.

내 코드에 비해 가독성과 효율성 측면에서 더 좋은 코드라는 생각이 든다.


[백준] 2388번 곱셈

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

 

 

 

문제

(세 자리 수) × (세 자리 수)는 다음과 같은 과정을 통하여 이루어진다.

(1)과 (2)위치에 들어갈 세 자리 자연수가 주어질 때 (3), (4), (5), (6)위치에 들어갈 값을 구하는 프로그램을 작성하라

 

입력 :

첫째 줄에 (1)의 위치에 들어갈 세 자리 자연수가, 둘째 줄에 (2)의 위치에 들어갈 세자리 자연수가 주어진다.

출력 :

첫째 줄부터 넷째 줄까지 차례대로 (3), (4), (5), (6)에 들어갈 값을 출력한다.

 

나의 답안

 

일단 (6)은 그냥 A*B 해주면 되고..

 

100의 자리 수는 100으로 나눠주면 몫이 그것이고,

 

1의 자리는 A를 10으로 나눈 나머지로 하면 되겠네? 생각했다.

 

그리고 10의 자리가 조금 고민이었다.

 

그러다 결국 10으로 나누면, 100의 자리와 10의 자리만 남을 것이고, 거기에 10을 나눈 나머지가

 

10의 자리 수가 되겠다는 생각을 하고 코드를 작성했다.

 

 

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int A = sc.nextInt();
        int B = sc.nextInt();


        System.out.println(A*(B%10));
        System.out.println(A*((B/10)%10));
        System.out.println(A*(B/100));
        System.out.println(A*B);
    }
}

 

 

모범 답안

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
         int a = sc.nextInt();
         int b = sc.nextInt();

         int c = (b % 10) * a;
         int d = ((b % 100) / 10) * a;
         int e = (b / 100) * a;
         System.out.println(c);
         System.out.println(d);
         System.out.println(e);
         System.out.println(a * b);
    }
}

 

 

  • 1의 자리 수와 100의 자리는 내 답안과 동일.
  • 10의 자리는 100을 나눈 나머지에 10을 나눈 몫으로 추출

 

[프로그래머스] 도둑

https://school.programmers.co.kr/learn/courses/30/lessons/42897

 

 

문제

도둑이 어느 마을을 털 계획을 하고 있습니다. 이 마을의 모든 집들은 동그란 형태로 배치되어 있다.

각 집들은 서로 인접한 집들과 방범장치가 연결되어 있어 인접한 두 집을 연속으로 털면 경보가 울린다.

각 집에 있는 돈이 담긴 배열 money가 주어질 때, 도둑이 훔칠 수 있는 돈의 최댓값을 return 하는 메서드를 작성하라.

 

 

 

나의 답안

몇 시간을 헤맨 끝에 겨우 풀었다.

 

아래 코드들처럼 이것저것 시도해 보았으나 테스트케이스 및 효율성 검사에서 탈락.

 

 

 

첫 번째 코드(오답)

import java.util.*;

class Solution {
    public int[] solution(int[] arr, int[] query) {
        int[] dp = new int[money.length];

        dp[0] = money[0];
        dp[1] = Math.max(money[0], money[1]);

        for (int i=2; i<money.length; i++) {
            dp[i] = Math.max(money[i]+dp[i-2], dp[i-1]);
        }

        int answer = dp[dp.length-1];
        return answer;
    }
}
  • n번째 집을 터는 경우와 털지 않는 경우 둘로 나누어 더 큰 값을 dp(n)의 값으로 결정하는 방법.
    집이 원형으로 배치되어 있다는 것을 망각하고 풀었다.
    따라서 맨 앞의 값과 뒤의 값을 둘 다 터는 경우가 발생하므로 오답이다.

 

두 번째 코드(오답)

class Solution {
    public int solution(int[] money) {
        int evenSum = 0, oddSum = 0;
        for (int i = 0; i < money.length; i++) {
            if (i % 2 == 0) {
                evenSum += money[i];
                System.out.println("evenSum :"+evenSum);
            } else {
                oddSum += money[i];
                System.out.println("oddSum :"+oddSum);
            }
        }

        if (money.length % 2 == 1) {
            evenSum -= Math.min(money[0], money[money.length - 1]);
        }

        return Math.max(evenSum, oddSum);
}
  • 한 칸 건너뛰면서 더하는 거니까, 홀수 인덱스 값들의 합과 짝수 인덱스 값들의 합을 비교하면 되겠네? 생각하고 작성.
    꼭 한 칸씩만 건너뛰면서 더해야 최대가 되는 것은 아니다. 예를 들어,
    [1000, 1, 1, 1000, 2] 의 경우 2000이 최댓값이지만, 위의 코드대로 수행하면 1003이 반환될 것이다.

 

 

세 번째 코드(오답)

class Solution {
    public int solution(int[] money) {
        int[] dp1 = new int[money.length];
        int[] dp2 = new int[money.length];

        dp1[0] = money[0];
        dp1[1] = Math.max(money[0], money[1]);
        dp2[money.length-1] = money [money.length-1];
        dp2[money.length-2] = Math.max(money[0], money[1]);

        int idx2 = money.length-3;
        for (int i=2; i<money.length-1; i++) {
            dp1[i] = Math.max(money[i]+dp![i-2], dp1[i-1]);
            dp2[idx2] = Math.max(money[idx2]+dp2[idx_r+2], dp2[idx_r+1]);
            
            idx2--;
        }

        return Math.max(dp1[money.length-2], dp2[1]);
}
  • 맨 앞과 뒤를 연속해서 털지 않도록  dp1과 dp2로 나누어
    dp1은 앞에서부터 n-1번째 값까지, dp2는 n번째 값부터 2번째 값까지 최댓값을 구하는 코드를 작성했다.
    이건 사실 왜 오답인지 아직도 모르겠다. 예외 케이스가 무엇인지 알려주실 선배님들 부탁드립니다..

 

 

모범 답안

  1. 원형으로 되어있으므로 맨 앞집을 터는 경우와 털지 않는 경우로 나누어 dp1, dp2로 각각 분류
  2. dp1에서는 맨 앞집부터 맨 끝집 직전 집까지 털 경우의 최대값을 구함
  3. dp2에서는 두 번째 집부터 맨 끝집까지 털 경우의 최대값을 구함
  4. dp1, dp2 중 최대값을 반환
class Solution {
    public int solution(int[] money) {
        int[] dp1 = new int[money.length];
        int[] dp2 = new int[money.length];

        dp1[0] = money[0];
        dp1[1] = Math.max(money[0], money[1]);
        dp2[0] = money[1];
        dp2[1] = Math.max(money[1], money[2]);

        for (int i = 2; i < money.length - 1; i++) {
            dp1[i] = Math.max(money[i] + dp1[i - 2], dp1[i - 1]);
            dp2[i] = Math.max(money[i+1] + dp2[i - 2], dp2[i - 1]);
        }

        return Math.max(dp1[money.length - 2], dp2[money.length - 2]);
    }
}

 

 

 

저녁시간 내내 이것만 고민하다가 끝났지만, 어느 정도 모범답안에 가까운 답을 도출해서 아주 뿌듯했다..

 

점점 발전하고 있는 것이 보인다!

[프로그래머스] 배열 조각하기

https://school.programmers.co.kr/learn/courses/30/lessons/181893

 

 

문제

정수 배열 arr와 query가 주어지며, query를 순회하면서 다음 작업을 반복한다.

  • 짝수 인덱스에서는 arr에서 query[i]번 인덱스를 제외하고 배열의 query[i]번 인덱스 뒷부분을 잘라서 버림
  • 홀수 인덱스에서는 arr에서 query[i]번 인덱스는 제외하고 배열의 query[i]번 인덱스 앞부분을 잘라서 버림


위 작업을 마친 후 남은 arr의 부분 배열을 return 하는 solution 함수를 완성하라

 

 

 

나의 답안

나는 문제에서 말하는 알고리즘대로 remove 메서드를 이용하여

 

짝수 인덱스에서는 뒷부분을 자르고,

홀수 인덱스에서는 앞부분을 잘라내고

 

배열로 변환하도록 코드를 작성했다.

 

import java.util.*;

class Solution {
    public int[] solution(int[] arr, int[] query) {
        ArrayList <Integer> list = new ArrayList<>();

        for(int i=0; i<arr.length; i++)
            list.add(arr[i]);

        for(int i=0; i<query.length; i++) {
            if(i%2 == 0) {
                int size = list.size() - query[i]-1;
                for(int j=0; j<size; j++)
                    list.remove(query[i]+1);
            }
            else {
                for(int j=0; j<query[i]; j++)
                    list.remove(0);
            }
        }

        int[] answer = new int [list.size()];
        for(int i=0; i<list.size(); i++)
            answer[i] = list.get(i);
        return answer;
    }
}

 

 

 

모범 답안

  1. 실제로 배열 내 값을 제거하는 과정을 생략
  2. start, end 변수를 이용하여 최종적으로 불러올 인덱스 범위를 조절
  3. copyOfRange변수를 사용하여 변수 불러옴
import java.util.*;

class Solution {
    public int[] solution(int[] arr, int[] query) {
        int start = 0;
        int end = arr.length - 1;
        for (int i = 0; i < query.length; i++) {
            if (i % 2 == 0) {
                end = start + query[i] - 1;
            } else {
                start += query[i];
            }
        }

        return Arrays.copyOfRange(arr, start, end + 2);
    }
}

 

 

 

시작점과 끝점만 조정해가며 값을 불러올 수 있다는 생각을 못했다.

 

순진하게(?) 문제에서 얘기하는 대로 코드를 짰는데,

 

훨씬 효율적인 처리가 가능한 방법이 있었다.

 

더 효율적인 방법이 있다는 것을 항상 생각하자!

 

 

 

 

 

 

복습

 

Arrays.copyOfRange(arr, 시작인덱스, 끝인덱스):

arr배열의 시작인덱스부터 끝인덱스(미포함)의 앞까지 복사하여 반환

 

 

[프로그래머스] Level 0 주사위게임2

 

 

 

문제

세 주사위를 던졌을 때 나온 숫자를 각각 a, b, c라고 할 때 얻는 점수는 다음과 같다.

 

  • 세 숫자가 모두 다르면 a + b + c 점을 얻는다.
  • 두 숫자는 같고 나머지 숫자는 다르다면 (a + b + c) × (a2 + b2 + c2 )점을 얻 는다.
  • 세 숫자가 모두 같다면 (a + b + c) × (a2 + b2 + c2 ) × (a3 + b3 + c3 )점을 얻 는다.

세 정수 a, b, c가 매개변수로 주어질 때, 얻는 점수를 return 하는 solution 메서드를 작성하라.

 

 

 

 

나의 답안

 

주사위 4개인 문제의 경우처럼

 

배열을 활용하여 오름차순 정렬 후 if문을 작성했는데,

 

다른 답안들을 보니 굳이 배열을 사용할 필요 없이

 

훨씬 효율적이고 간결한 코드가 많이 존재했다..

 

import java.util.Arrays;

class Solution {
    public int solution(int a, int b, int c) {
        int[] dice = {a, b, c};
        Arrays.sort(dice);

        if (dice[0] != dice[1] && dice[1] != dice[2]) {
            return dice[0]+dice[1]+dice[2];
        } else if (dice[0] != dice[2]) {
            return (dice[0] + dice[1] + dice[2]) * (dice[0]*dice[0] + dice[1]*dice[1] + dice[2]*dice[2]);
        } else {
            return (dice[0] + dice[1] + dice[2]) * (dice[0]*dice[0] + dice[1]*dice[1] + dice[2]*dice[2]) * (dice[0]*dice[0]*dic
e[0] + dice[1]*dice[1]*dice[1] + dice[2]*dice[2]*dice[2]);
        }
    }
}

 

 

 

 

모범 답안

class Solution {
    public int solution(int a, int b, int c) {
        int answer = 1;

        int count = 1;
        if(a == b || a == c || b == c) {
            count++;
        }

        if(a == b && b == c) {
            count++;
        }

        for(int i = 1; i <= count; i++) {
            answer *= (pow(a,i)+pow(b,i)+pow(c,i));
        }

        return answer;
    }

    private int pow(int a, int b) {
        if(b == 0) return 1;
        return a * pow(a, b-1);
    }
}
  • count변수를 생성하여, 단계별로 제곱 수를 결정하도록 함
  • pow메서드를 재귀함수로 별도로 선언하여 간결성 및 효율성 제고

 

상황에 따라 제곱과 세제곱이 사용된다는 점을 이용하여

정말 영리하게 작성된 코드라는 생각이 든다.

나는 언제쯤 저렇게 생각할 수 있을까..

 

 

복습

      재귀함수

  • 자신의 함수 내에서 자기 자신을 호출하는 함수
  • 반복적 연산 시 효율성을 위해 주로 사용
// 팩토리얼 구하는 메서드 작성

public int factorial(int n) {

    if (n == 0 || n == 1) {       // 종료 조건(Base Case)
        return 1;
    }
    
    return n * factorial(n - 1);     // 자기 자신 호출(Recursive Call)
}

 

[프로그래머스] Level 0 코드 처리하기

 

 

 

문제

문자열 code가 주어집니다. code를 앞에서부터 읽으면서 만약 문자가 "1"이면 mode를 바꿉니다. mode에 따라 code를 읽어가면서 문자열 ret을 만들어냅니다. mode는 0과 1이 있으며, i를 0부터 code의 길이 - 1까지 1씩 키워나가면서 code[i] 값에 따라 다음과 같이 행동합니다.

 

  • mode = 0일 때
    code[i]가 "1"이 아니면 i가 짝수일 때만 ret의 맨 뒤에 code[i]를 추가합니다.
    code[i]가 "1"이면 mode를 0에서 1로 바꿉니다.
  • mode = 1일 때
    code[i]가 "1"이 아니면 i가 홀수일 때만 ret의 맨 뒤에 code[i]를 추가합니다.
    code[i]가 "1"이면 mode를 1에서 0으로 바꿉니다.


문자열 code를 통해 만들어진 문자열 ret를 return 하는 solution 함수를 완성해 주세요.
단, 시작할 때 mode는 0이며, return 하려는 ret가 만약 빈 문자열이라면 대신 "EMPTY"를 return 합니다.

 

 

 

 

나의 답안

 

조건에 맞게 mode가 1일 때와 0일 때, code[i]가 1일 때 등 if 조건문을 달아 작성하였으며,

StringBulider 변수를 선언하여 문자를 추가하도록 하였다.

 

 

class Solution {
    public String solution(String code) {
        StringBuilder temp = new StringBuilder();
        int mode = 0;

        for (int i=0; i<code.length(); i++) {
            if (mode == 0) {
                if (code.charAt(i) == '1') {
                    mode += 1;
                } else if (code.charAt(i) != '1') {
                    if (i%2 == 0) {
                        temp.append(code.charAt(i));
                    }
                }
            } else if (mode == 1) {
                if (code.charAt(i) == '1') {
                    mode -= 1;
                } else if (code.charAt(i) != '1') {
                    if (i%2 != 0) {
                        temp.append(code.charAt(i));
                    }
                }
            }
        }
        String ret = temp.toString();
        return ret.isEmpty() ? "EMPTY" : ret;
    }
}

 

 

 

 

 

모범 답안

class Solution {
    public String solution(String code) {
        StringBuilder answer = new StringBuilder();
        int mode = 0;
        for (int i = 0; i < code.length(); i++) {
            char current = code.charAt(i);
            if (current == '1') {
                mode = mode == 0 ? 1 : 0;
                continue;
            }

            if (i % 2 == mode) {
                answer.append(current);
            }
        }
        return answer.length() == 0 ? "EMPTY" : answer.toString();
    }
}
  • 홀수와 짝수 구분을 mode를 이용해 작성함으로써 중첩 if문 사용 방지
  • 문자가 '1'일 때, mode 전환 또한 삼항연산자를 사용하여 한번에 작성
  • 마지막 return 시 새로운 변수 선언 없이 바로 toString을 통해 StringBulider 변수를 리턴 

 

 

중첩 if문을 사용하지 않음으로써 훨씬 코드가 간결하고 가독성이 좋아졌다.

더 가독성을 높이고 효율성을 높일 수 있는 코딩이 있을지 항상 생각하며 코딩하면 좋을 듯하다.

 

 

복습

      문자열(String)

  • String.charAt(인덱스) : 해당 인덱스에 위치한 문자값을 리턴
  • String.isEmpty(): 해당 문자열이 비어있는지 확인

 

      StringBuilder

  • sb.append(문자열): 해당 문자열을 새로 추
  • sb.insert(인덱스, 문자열): 해당 위치에 문자열을 삽입 (해당 위치의 문자열을 뒤로 밀어 삽입)
  • sb.toString(): 문자열 자료형으로 변환

[프로그래머스] Level 1 완주하지 못한 선수

 

 

 

문제

마라톤 경주에서 참가자들 중 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.

마라톤 참가 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 

 

완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.

 

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

 

 

 

 

 

나의 답안(효율성 테스트 탈락)

 

리스트로 변환한 후, 완주한 참가자의 이름을 하나씩 대조하여 제거한 후

 

최종적으로 리스트에 남은 1명의 참가자의 이름을 return하도록 작성하였으나,

 

효율성 테스트에서 시간 초과로 오답 처리되었다.

 

 

import java.util.ArrayList;
import java.util.Arrays;

class Solution {
    public String solution(String[] participant, String[] completion) {
        ArrayList<String> part = new ArrayList<>(Arrays.asList(participant));

        for (int i=0; i<completion.length; i++) {
            part.remove(completion[i]);
        }

        return part.get(0);
    }

 

 

 

 

 

다른 유저의 답안

import java.util.HashMap;

class Solution {
    public String solution(String[] participant, String[] completion) {
        String answer = "";
        HashMap<String, Integer> hm = new HashMap<>();
        for (String player : participant) hm.put(player, hm.getOrDefault(player, 0) + 1);
        for (String player : completion) hm.put(player, hm.get(player) - 1);

        for (String key : hm.keySet()) {
            if (hm.get(key) != 0){
                answer = key;
            }
        }
        return answer;
    }
}

 

  • HashMap을 생성, 참가자 value값 +1, 완주자 value값 -1
  • getOrDefault 메서드를 사용하여 동명이인 있을 경우 오류에도 대비
    (HashMap에서는 같은 key값이 선언될 경우 value값이 변경되어 등록됨)

 

 

 

getOrDefault를 사용하는 부분에서 감탄했다.

이런 메서드들을 적재적소에 잘 활용할 수 있는 개발자가 되어야지..

 

 

복습

       리스트(List)

  • a.add(요솟값) : 해당 리스트에 원하는 요솟값을 추가
  • a.remove(인덱스): 해당위치 항목 삭제, 그 요솟값 리턴
  • a.remove(요솟값): 해당 요솟값을 삭제, true/false리턴
  • a.get(인덱스): 해당위치 요솟값 리턴

 

      맵(Map)

  • a.put(key값, value값): key와 value 추가
  • a.get(key값): key에 해당하는 value값 반환
  • a.getOrDefault(key값,얻을값): key에 해당하는 value값이 없을 때, null대신 얻을값을 반환
  • a.keySet(): 모든 key값을 모아 집합 자료형으로 리턴

[프로그래머스] Level 1 폰켓몬

 

 

 

문제

 박사님은 당신에게 자신의 연구실에 있는 총 N 마리의 폰켓몬 중에서 N/2마리를 가져가도 좋다고 했습니다.
홍 박사님 연구실의 폰켓몬은 종류에 따라 번호를 붙여 구분합니다. 따라서 같은 종류의 폰켓몬은 같은 번호를 가지고 있습니다. 예를 들어 연구실에 총 4마리의 폰켓몬이 있고, 각 폰켓몬의 종류 번호가 [3번, 1번, 2번, 3번]이라면 이는 3번 폰켓몬 두 마리, 1번 폰켓몬 한 마리, 2번 폰켓몬 한 마리가 있음을 나타냅니다. 이때, 4마리의 폰켓몬 중 2마리를 고르는 방법은 다음과 같이 6가지가 있습니다.

 

  • 첫 번째(3번), 두 번째(1번) 폰켓몬을 선택
  • 첫 번째(3번), 세 번째(2번) 폰켓몬을 선택
  • 첫 번째(3번), 네 번째(3번) 폰켓몬을 선택
  • 두 번째(1번), 세 번째(2번) 폰켓몬을 선택
  • 두 번째(1번), 네 번째(3번) 폰켓몬을 선택
  • 세 번째(2번), 네 번째(3번) 폰켓몬을 선택

이때, 첫 번째(3번) 폰켓몬과 네 번째(3번) 폰켓몬을 선택하는 방법은 한 종류(3번 폰켓몬 두 마리)의 폰켓몬만 가질 수 있지만, 다른 방법들은 모두 두 종류의 폰켓몬을 가질 수 있습니다. 따라서 위 예시에서 가질 수 있는 폰켓몬 종류 수의 최댓값은 2가 됩니다.


당신은 최대한 다양한 종류의 폰켓몬을 가지길 원하기 때문에, 최대한 많은 종류의 폰켓몬을 포함해서 N/2마리를 선택하려 합니다. N마리 폰켓몬의 종류 번호가 담긴 배열 nums가 매개변수로 주어질 때, N/2마리의 폰켓몬을 선택하는 방법 중, 가장 많은 종류의 폰켓몬을 선택하는 방법을 찾아, 그때의 폰켓몬 종류 번호의 개수를 return 하는 함수를 완성하세요

 

 

 

 

 

나의 답안

 

리스트를 만들어, 입력받은 배열의 요소들을 중복되는 값을 제외하여 값을 추가하였고,

 

N/2와 리스트 요소의 개수 중 더 작은 값을 반환하도록 작성하였다.

 

 

import java.util.*;

class Solution {
    public int solution(int[] nums) {     
        ArrayList<Integer> types = new ArrayList<>();
        
        for (int i=0; i<nums.length; i++) {            
            if (types.contains(nums[i]) == false) {                
                types.add(nums[i]);
            }
        }
        
        return Math.min(types.size(), nums.length/2);
    }
}

 

 

 

 

다른 유저의 답안

import java.util.HashSet;

class Solution {
    public int solution(int[] nums) {

            HashSet<Integer> hs = new HashSet<>();

            for(int i =0; i<nums.length;i++) {
                hs.add(nums[i]);
            }

            if(hs.size()>nums.length/2)
                return nums.length/2;

            return hs.size();
    }
}
  • 리스트 대신 Set 타입으로 값을 담아, 자동으로 중복을 제외하도록 작성
  • 그래서인지 코드 읽을 때 더 간결해 보임

 

 

HashSet을 많이 사용해보지 않아 Set자료형을 활용할 생각을 못했다.

다음에 중복을 제거해야 할 경우에는 Set자료형을 활용하자!

 

 

복습

  • a.add(요소값) : 해당 리스트에 원하는 요 솟값을 추가함
  • a.size() : 해당 리스트의 요소 개수를 리턴
  • a.contains(요솟값) : 해당 리스트에 해당 요솟값이 있는지 확인
  • 리스트 선언 방법
    1) ArrayList<Integer> a = new ArrrayList<>();
    2) ArrayList<Integer> a = new ArrrayList<>(Arrays.asList(1, 2, 3, 4));

 

[프로그래머스] Level 0 주사위게임3

 

너무 어려웠다.

오랜 시간 머리를 쥐어짰지만 아직은 역부족인가보다.

결국 노가다에 가까운 코드를 만들어

억지로 정답을 맞췄다...

 

 

 

문제

1부터 6까지 숫자가 적힌 네 주사위를 굴렸을 때 나온 숫자에 따라 다음과 같은 점수를 얻는다.

 

  • 네 주사위에서 나온 숫자가 모두 p로 같다면 1111 × p점
  • 세 주사위에서 나온 숫자가 p로 같고 나머지 다른 주사위에서 나온 숫자가 q(p ≠ q)라면 (10 × p + q)2 점
  • 주사위가 두 개씩 같은 값이 나오고, 나온 숫자를 각각 p, q(p ≠ q)라고 한다면 (p + q) × |p - q|점
  • 어느 두 주사위에서 나온 숫자가 p로 같고 나머지 두 주사위에서 나온 숫자가 각각 p와 다른 q, r(q ≠ r)이라면 q × r점
  • 네 주사위에 적힌 숫자가 모두 다르다면 나온 숫자 중 가장 작은 숫자 만큼의 점수를 얻습니다.

네 주사위를 굴렸을 때 나온 숫자가 정수 매개변수 a, b, c, d로 주어질 때, 얻는 점수를 return 하는 메서드를 작성하라

 

 

 

 

 

나의 답안

 

공개하기 부끄럽다...

import java.util.*;

class Solution {
    public int solution(int a, int b, int c, int d) {
        
        int ab = a==b ? 1 : 0;
        int ac = a==c ? 1 : 0;
        int ad = a==d ? 1 : 0;
        int bc = b==c ? 1 : 0;
        int bd = b==d ? 1 : 0;
        int cd = c==d ? 1 : 0;
        String result = ""+ab+ac+ad+bc+bd+cd;
        
        switch (result) {
            case "111111":
                return 1111 * a;
            case "110100":
                return (10 * a + d) * (10 * a + d);
            case "101010":
                return (10 * a + c) * (10 * a + c);
            case "011001":
                return (10 * a + b) * (10 * a + b);
            case "000111":
                return (10 * b + a) * (10 * b + a);
            case "100001":
                return (a + c) * (a - c) > 0 ? (a + c) * (a - c) : (a + c) * (a - c) * -1;
            case "010010":
                return (a + b) * (a - b) > 0 ? (a + b) * (a - b) : (a + b) * (a - b) * -1;
            case "001100":
                return (a + b) * (a - b) > 0 ? (a + b) * (a - b) : (a + b) * (a - b) * -1;
            case "100000":
                return c * d;
            case "010000":
                return b * d;
            case "001000":
                return b * c;
            case "000100":
                return a * d;
            case "000010":
                return a * c;
            case "000001":
                return a * b;
            default:
                ArrayList<Integer> numbers = new ArrayList<>(Arrays.asList(a, b, c, d));
                return Collections.min(numbers);
        }
    }
}
        

 

 

 

다른 유저의 답안

import java.util.Arrays;

class Solution {
    public int solution(int a, int b, int c, int d) {

        int[] dice = { a, b, c, d };
        Arrays.sort(dice);             //배열로 저장 후 오름차순정렬

        int ans = 0;

        if (dice[0] == dice[3]) { 
            ans = 1111 * dice[3];         //4개 모두 같을 때
        } else if (dice[0] == dice[2] || dice[1] == dice[3]) { 
            ans = (int) Math.pow(dice[1] * 10 + (dice[0] + dice[3] - dice[1]), 2);     // 3개만 같을 때
        } else if (dice[0] == dice[1] && dice[2] == dice[3]) {     
            ans = (dice[0] + dice[3]) * (dice[3] - dice[0]);       // 2개씩 같을 때
        } else if (dice[0] == dice[1]) {         
            ans = dice[2] * dice[3];
        } else if (dice[1] == dice[2]) {
            ans = dice[0] * dice[3];
        } else if (dice[2] == dice[3]) {
            ans = dice[0] * dice[1];                // 2개만 같을 때
        } else {
            ans = dice[0];            // 모두 다를 때
        }

        return ans;
    }
}
  • 정렬을 이용하여 케이스를 나누기 용이하게 함
  • 가장 작은 수를 추출하기에도 용이함

 

복습

  • 배열 오름차순 정렬 :  Arrays.sort(배열)
  • 배열 선언과 동시에 값 입력 : int[] arr = {1, 2, 3, 4, 5};