📑 문1) 두 문자열 s와 skip, 그리고 자연수 index가 주어질 때, 다음 규칙에 따라 문자열을 만들려 합니다. 암호의 규칙은 다음과 같습니다.
예를 들어 s = "aukks", skip = "wbqd", index = 5일 때, a에서 5만큼 뒤에 있는 알파벳은 f지만 [b, c, d, e, f]에서 'b'와 'd'는 skip에 포함되므로 세지 않습니다. 따라서 'b', 'd'를 제외하고 'a'에서 5만큼 뒤에 있는 알파벳은 [c, e, f, g, h] 순서에 의해 'h'가 됩니다. 나머지 "ukks" 또한 위 규칙대로 바꾸면 "appy"가 되며 결과는 "happy"가 됩니다.
두 문자열 s와 skip, 그리고 자연수 index가 매개변수로 주어질 때 위 규칙대로 s를 변환한 결과를 return하도록 solution 함수를 완성해주세요.
제한사항
입출력 예
s | skip | index | result |
---|---|---|---|
aukks | wbqd | 5 | happy |
나의 풀이
package programmers;
import java.util.ArrayList;
public class TwoPasswords {
public static String solution(String s, String skip, int index) {
String answer = "";
ArrayList<String> alphabet = new ArrayList<>();
for(char c = 'a'; c <= 'z'; c++) {
alphabet.add(String.valueOf(c));
}
for(char c : skip.toCharArray()) {
alphabet.remove(String.valueOf(c));
}
for(char c : s.toCharArray()) {
if(alphabet.contains(String.valueOf(c))) {
int i = alphabet.indexOf(String.valueOf(c));
int targetIndex = (i + index) % alphabet.size();
answer += alphabet.get(targetIndex);
}
}
return answer;
}
public static void main(String[] args) {
solution("aukks", "wbqd", 5);
}
}
나의 생각
문제를 보고 가장 먼저 했던 생각은 "알파벳을 넣을 수 있는 배열을 만들어서, skip문자열에 포함된 글자 하나씩을 제거하면 되겠다"
라고 생각하였다.
for(char c = 'a'; c <= 'z'; c++) {
alphabet.add(String.valueOf(c));
}
ArrayList<String> alphabet = new ArrayList<>();
를 선언하고, 알파벳 a ~ z 까지 alphabet 리스트에 포함시킨다.
for(char c : skip.toCharArray()) {
alphabet.remove(String.valueOf(c));
}
반복을 추가하여, alphabet
리스트에서 skip에 포함된 char c
를 remove(String.valueOf(c))
메서드로 제거시킨다. (즉, skip에 포함된 글자를 List에서 제거한다)
for(char c : s.toCharArray()) {
if(alphabet.contains(String.valueOf(c))) {
int i = alphabet.indexOf(String.valueOf(c));
int targetIndex = (i + index) % alphabet.size();
answer += alphabet.get(targetIndex);
}
}
skip 문자가 제거된 alphabet
리스트에서 매개변수 s에 포함된 글자가 존재하면, 매개변수 index
값 만큼 건너뛰고 answer
문자에 포함시키는데, 즉, a라는 문자에 index (5)
라면 a,b,c,d,e,f
a+index = f
인 f를 answer에 포함시키는것이다. 여기서 주의할 점은 z+index(5) 라고 하면 범위를 넘어가기 때문에, int targetIndex = (i + index) % alphabet.size();
를 활용하여, a ~ z
알파벳을 반복하게끔 로직을 구현하였다.
📑 문2) 휴대폰의 자판은 컴퓨터 키보드 자판과는 다르게 하나의 키에 여러 개의 문자가 할당될 수 있습니다. 키 하나에 여러 문자가 할당된 경우, 동일한 키를 연속해서 빠르게 누르면 할당된 순서대로 문자가 바뀝니다.
예를 들어, 1번 키에 "A", "B", "C" 순서대로 문자가 할당되어 있다면 1번 키를 한 번 누르면 "A", 두 번 누르면 "B", 세 번 누르면 "C"가 되는 식입니다.
같은 규칙을 적용해 아무렇게나 만든 휴대폰 자판이 있습니다. 이 휴대폰 자판은 키의 개수가 1개부터 최대 100개까지 있을 수 있으며, 특정 키를 눌렀을 때 입력되는 문자들도 무작위로 배열되어 있습니다. 또, 같은 문자가 자판 전체에 여러 번 할당된 경우도 있고, 키 하나에 같은 문자가 여러 번 할당된 경우도 있습니다. 심지어 아예 할당되지 않은 경우도 있습니다. 따라서 몇몇 문자열은 작성할 수 없을 수도 있습니다.
이 휴대폰 자판을 이용해 특정 문자열을 작성할 때, 키를 최소 몇 번 눌러야 그 문자열을 작성할 수 있는지 알아보고자 합니다.
1번 키부터 차례대로 할당된 문자들이 순서대로 담긴 문자열배열 keymap과 입력하려는 문자열들이 담긴 문자열 배열 targets가 주어질 때, 각 문자열을 작성하기 위해 키를 최소 몇 번씩 눌러야 하는지 순서대로 배열에 담아 return 하는 solution 함수를 완성해 주세요.
단, 목표 문자열을 작성할 수 없을 때는 -1을 저장합니다.
제한사항
입출력 예
keymap | targets | result |
---|---|---|
["ABACD","BCEFD"] | ["ABCD","AABB"] | [9,4] |
["AA"] | ["B"] | [-1] |
["AGZ","BSSS"] | ["ASA","BGZ"] | [4,6] |
입출력 예 설명
입출력 예 #1
입출력 예 #2
입출력 예 #3
나의 풀이
package programmers;
import java.util.Arrays;
import java.util.HashMap;
public class ARoughKeyboard {
public static int[] solution(String[] keymap, String[] targets) {
int[] answer = new int[targets.length];
HashMap<Character, Integer> map = new HashMap<>();
for(String key : keymap) {
for(int i = 0; i < key.length(); i++) {
char ch = key.charAt(i);
if(map.containsKey(ch)) {
if(map.get(ch) > i) {
map.replace(ch, i+1);
}
}else {
map.put(ch, i+1);
}
}
}
for(int i = 0; i < targets.length; i++) {
int sum = 0;
for(int j = 0; j < targets[i].length(); j++) {
char ch = targets[i].charAt(j);
if(map.containsKey(ch)) {
sum += map.get(ch);
}else {
sum = -1;
break;
}
}
answer[i] = sum;
}
System.out.println(map);
System.out.println(Arrays.toString(answer));
return answer ;
}
public static void main(String[] args) {
solution(new String[] {"ABACD","BCEFD"}, new String[] {"ABCD","AABB"});
}
}
📑 문3) 머쓱이는 태어난 지 11개월 된 조카를 돌보고 있습니다. 조카는 아직 "aya", "ye", "woo", "ma" 네 가지 발음과 네 가지 발음을 조합해서 만들 수 있는 발음밖에 하지 못하고 연속해서 같은 발음을 하는 것을 어려워합니다. 문자열 배열 babbling이 매개변수로 주어질 때, 머쓱이의 조카가 발음할 수 있는 단어의 개수를 return하도록 solution 함수를 완성해주세요.
제한사항
입출력 예
babbling | result |
---|---|
["aya", "yee", "u", "maa"] | 1 |
["ayaye", "uuu", "yeye", "yemawoo", "ayaayaa"] | 2 |
입출력 예 설명
입출력 예 #1
입출력 예 #2
₩["ayaye", "uuuma", "yeye", "yemawoo", "ayaayaa"]`에서 발음할 수 있는 것은 "aya" + "ye" = "ayaye", "ye" + "ma" + "woo" = "yemawoo"로 2개입니다. "yeye"는 같은 발음이 연속되므로 발음할 수 없습니다. 따라서 2를 return합니다.
유의사항
네 가지를 붙여 만들 수 있는 발음 이외에는 어떤 발음도 할 수 없는 것으로 규정합니다. 예를 들어 "woowo"는 "woo"는 발음할 수 있지만 "wo"를 발음할 수 없기 때문에 할 수 없는 발음입니다.
나의 풀이
package programmers;
import java.util.Arrays;
public class BabblingTwo {
public static int solution(String[] babblings) {
int answer = 0;
for(int i = 0; i < babblings.length; i++) {
if(babblings[i].contains("ayaaya") || babblings[i].contains("yeye") || babblings[i].contains("woowoo") || babblings[i].contains("mama")) {
continue;
}
babblings[i] = babblings[i].replace("aya", " ");
babblings[i] = babblings[i].replace("ye", " ");
babblings[i] = babblings[i].replace("woo", " ");
babblings[i] = babblings[i].replace("ma", " ");
babblings[i] = babblings[i].replace(" ", "");
if(babblings[i].length() == 0) answer++;
}
return answer ;
}
public static void main(String[] args) {
solution(new String[] {"ayaye", "uuu", "yeye", "yemawoo", "ayaayaa"});
}
}
나의 생각
"aya", "ye", "woo", "ma"
네가지 단어만 발음 할 수 있고, ayaaya, yeye, woowoo, mama
와 같이 연속된 발음을 할 수 없기때문에, String[] babblings
안에 해당 글자가 포함돼있으면 continue
로 로직을 빠져나오고, aya, ye, woo, ma
가 있으면 해당 글자를 " "
로 변환한 뒤, " "
글자를 다시한번 ''
으로 변환하여 babblings
길이를 체크하여 길이가 0
이면 answer ++를 하는 방법을 사용하였다.
📑 문4) 로또 6/45(이하 '로또'로 표기)는 1부터 45까지의 숫자 중 6개를 찍어서 맞히는 대표적인 복권입니다. 아래는 로또의 순위를 정하는 방식입니다.
순위 | 당첨 내용 |
---|---|
1 | 6개 번호가 모두 일치 |
2 | 5개 번호가 일치 |
3 | 4개 번호가 일치 |
4 | 3개 번호가 일치 |
5 | 2개 번호가 일치 |
6 (낙첨) | 그 외 |
로또를 구매한 민우는 당첨 번호 발표일을 학수고대하고 있었습니다. 하지만, 민우의 동생이 로또에 낙서를 하여, 일부 번호를 알아볼 수 없게 되었습니다. 당첨 번호 발표 후, 민우는 자신이 구매했던 로또로 당첨이 가능했던 최고 순위와 최저 순위를 알아보고 싶어 졌습니다.
알아볼 수 없는 번호를 0으로 표기하기로 하고, 민우가 구매한 로또 번호 6개가 44, 1, 0, 0, 31 25라고 가정해보겠습니다. 당첨 번호 6개가 31, 10, 45, 1, 6, 19라면, 당첨 가능한 최고 순위와 최저 순위의 한 예는 아래와 같습니다.
당첨번호 | 31 | 10 | 45 | 1 | 6 | 19 | 결과 |
---|---|---|---|---|---|---|---|
최고 순위 번호 | 31 | 0→10 | 44 | 1 | 0→6 | 25 | 4개 번호 일치, 3등 |
최저 순위 번호 | 31 | 0→11 | 44 | 1 | 0→7 | 25 | 2개 번호 일치, 5등 |
민우가 구매한 로또 번호를 담은 배열 lottos, 당첨 번호를 담은 배열 win_nums가 매개변수로 주어집니다. 이때, 당첨 가능한 최고 순위와 최저 순위를 차례대로 배열에 담아서 return 하도록 solution 함수를 완성해주세요.
제한사항
입출력 예
lottos | win_nums | result |
---|---|---|
[44, 1, 0, 0, 31, 25] | [31, 10, 45, 1, 6, 19] | [3,5] |
[0, 0, 0, 0, 0, 0] | [38, 19, 20, 40, 15, 25] | [1, 6] |
[45, 4, 35, 20, 3, 9] | [20, 9, 3, 45, 4, 35] | [1, 1] |
입출력 예 설명
입출력 예 #2
알아볼 수 없는 번호들이 아래와 같았다면, 1등과 6등에 당첨될 수 있습니다.
당첨번호 | 38 | 19 | 20 | 40 | 15 | 25 | 결과 |
---|---|---|---|---|---|---|---|
최고 순위 번호 | 0→38 | 0→19 | 0→20 | 0→40 | 0→15 | 0→25 | 6개 번호 일치, 1등 |
최저 순위 번호 | 0→21 | 0→22 | 0→23 | 0→24 | 0→25 | 0→26 | 0개 번호 일치, 6등 |
나의 풀이
package programmers;
import java.util.Arrays;
public class LottosHighestRanking {
public static int[] solution(int[] lottos, int[] win_nums) {
int[] answer = new int[2];
int cnt = 0;
int zeroCnt = 0;
for(int i = 0; i < lottos.length; i++) {
if(lottos[i] == 0) {
zeroCnt++;
}
}
for(int i = 0; i < win_nums.length; i++) {
for(int j = 0; j < lottos.length; j++) {
if(win_nums[i] == lottos[j]) {
cnt++;
}
}
}
answer[0] = cnt + zeroCnt;
answer[1] = cnt;
for(int i = 0; i < answer.length; i++) {
switch(answer[i]) {
case 6:
answer[i] = 1;
break;
case 5:
answer[i] = 2;
break;
case 4:
answer[i] = 3;
break;
case 3:
answer[i] = 4;
break;
case 2:
answer[i] = 5;
break;
default:
answer[i] = 6;
break;
}
}
System.out.println(Arrays.toString(answer));
return answer;
}
public static void main(String[] args) {
solution(new int[] {45, 4, 35, 20, 3, 9}, new int[] {20, 9, 3, 45, 4, 35});
}
}
나의 생각
문제를 보자마자 들었던 생각이 매개변수로 주어지는 lottos
에 알아볼 수 없는 문자는 0으로 표기되고, int[] win_nums
과 비교하여, 최고 등수와, 최저 등수를 찾는 문제였다. 여기서 0으로 표기되는 문자는 몇개인가를 중점으로 생각했는데, 최고 등수라면, 0을 int[] win_nums
에서 원하는 숫자로 바꿔야하고, 최저점일 경우, int[] win_nums
에 없는 숫자로 변경하면 간단하게 나타낼수 있겠다는 생각을 하였다.
for(int i = 0; i < lottos.length; i++) {
if(lottos[i] == 0) {
zeroCnt++;
}
}
현재의 로직에서 int[] lottos
에서 0이 몇개인지를 체크하고,
for(int i = 0; i < win_nums.length; i++) {
for(int j = 0; j < lottos.length; j++) {
if(win_nums[i] == lottos[j]) {
cnt++;
}
}
}
현재의 로직에서 int[] win_nums
와 int[] lottos
에서 같은 수가 몇개인지를 체크하여, cnt + zeroCnt = 최고점수
, cnt = 최저점수
라는 식이 성립한다.
예를 보면, lottos {45,4,35,20,3,9}
와 win_nums {20, 9,3,45,4,35}
는 숫자의 자리 위치만 다르지, 모든 수가 일치하기 때문에(6개 수가 일치) answer = {6,6}
이 된다. 그렇다면, int[] answer
에 든 값을 어떻게 다시, 등수로 나타낼 것인가? 위 과정으로 answer = {}
값은 6부터 0까지 값이 한정돼있기때문에, switch, case
문을 활용하면, 이 값에 따라, 등수를 조절할 수 있다.
for(int i = 0; i < answer.length; i++) {
switch(answer[i]) {
case 6:
answer[i] = 1;
break;
case 5:
answer[i] = 2;
break;
case 4:
answer[i] = 3;
break;
case 3:
answer[i] = 4;
break;
case 2:
answer[i] = 5;
break;
default:
answer[i] = 6;
break;
}
}
위의 과정을 통해, 초기 answer = {cnt + cntZero
, cnt
} 값은 등수값으로 변환이 되어 리턴된다.
📑 문5) 게임개발자인 "죠르디"는 크레인 인형뽑기 기계를 모바일 게임으로 만들려고 합니다.
"죠르디"는 게임의 재미를 높이기 위해 화면 구성과 규칙을 다음과 같이 게임 로직에 반영하려고 합니다.
게임 화면은 "1 x 1" 크기의 칸들로 이루어진 "N x N" 크기의 정사각 격자이며 위쪽에는 크레인이 있고 오른쪽에는 바구니가 있습니다. (위 그림은 "5 x 5" 크기의 예시입니다). 각 격자 칸에는 다양한 인형이 들어 있으며 인형이 없는 칸은 빈칸입니다. 모든 인형은 "1 x 1" 크기의 격자 한 칸을 차지하며 격자의 가장 아래 칸부터 차곡차곡 쌓여 있습니다. 게임 사용자는 크레인을 좌우로 움직여서 멈춘 위치에서 가장 위에 있는 인형을 집어 올릴 수 있습니다. 집어 올린 인형은 바구니에 쌓이게 되는 데, 이때 바구니의 가장 아래 칸부터 인형이 순서대로 쌓이게 됩니다. 다음 그림은 [1번, 5번, 3번] 위치에서 순서대로 인형을 집어 올려 바구니에 담은 모습입니다.
만약 같은 모양의 인형 두 개가 바구니에 연속해서 쌓이게 되면 두 인형은 터뜨려지면서 바구니에서 사라지게 됩니다. 위 상태에서 이어서 [5번] 위치에서 인형을 집어 바구니에 쌓으면 같은 모양 인형 두 개가 없어집니다.
크레인 작동 시 인형이 집어지지 않는 경우는 없으나 만약 인형이 없는 곳에서 크레인을 작동시키는 경우에는 아무런 일도 일어나지 않습니다. 또한 바구니는 모든 인형이 들어갈 수 있을 만큼 충분히 크다고 가정합니다. (그림에서는 화면표시 제약으로 5칸만으로 표현하였음)
게임 화면의 격자의 상태가 담긴 2차원 배열 board와 인형을 집기 위해 크레인을 작동시킨 위치가 담긴 배열 moves가 매개변수로 주어질 때, 크레인을 모두 작동시킨 후 터트려져 사라진 인형의 개수를 return 하도록 solution 함수를 완성해주세요.
제한사항
입출력 예
board | moves | result |
---|---|---|
[[0,0,0,0,0],[0,0,1,0,3],[0,2,5,0,1],[4,2,4,4,2],[3,5,1,3,1]] | [1,5,3,5,1,2,1,4] | 4 |
나의 풀이
package programmers;
import java.util.Stack;
public class DollDrawing {
public static int solution(int[][] board, int[] moves) {
int answer = 0;
Stack<Integer> stack = new Stack<>();
int[][] newBoard = new int[board.length][board[0].length];
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[i].length; j++) {
newBoard[i][j] = board[j][i];
}
}
for (int move : moves) {
for (int j = 0; j < newBoard[move - 1].length; j++) {
if (newBoard[move - 1][j] != 0) {
if (!stack.isEmpty() && stack.peek() == newBoard[move - 1][j]) {
stack.pop();
answer += 2;
} else {
stack.push(newBoard[move - 1][j]);
}
newBoard[move - 1][j] = 0;
break;
}
}
}
return answer;
}
public static void main(String[] args) {
solution(new int[][] {{0,0,0,0,0},{0,0,1,0,3},{0,2,5,0,1},{4,2,4,4,2},{3,5,1,3,1}},
new int[] {1,5,3,5,1,2,1,4});
}
}
나의 생각
매개변수로 주어지는 int[][] board
의 값 new int[][] {{0,0,0,0,0},{0,0,1,0,3},{0,2,5,0,1},{4,2,4,4,2},{3,5,1,3,1}}
를 배열을 전치 (Transpose)
하여 newBoard를 새롭게 생성하였다.
int[][] newBoard = new int[board.length][board[0].length];
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[i].length; j++) {
newBoard[i][j] = board[j][i];
}
}
위 그림에서 알 수 있듯이, moves의 값(index)을 보고 0이 아닌값이 나올때의 그 값을 추출하기 위해서 Stack
을 사용하였다.
Stack<Integer> stack = new Stack<>();
for (int move : moves) {
for (int j = 0; j < newBoard[move - 1].length; j++) {
if (newBoard[move - 1][j] != 0) {
if (!stack.isEmpty() && stack.peek() == newBoard[move - 1][j]) {
stack.pop();
answer += 2;
} else {
stack.push(newBoard[move - 1][j]);
}
newBoard[move - 1][j] = 0;
break;
}
}
}
if (newBoard[move - 1][j]
는 move의 값에 따라 newBoard의 index가 결정되는데, 이때 0이 아닌값이 나오면 그 값을 stack에 저장하고, 스택의 최상단의 값과 newBoard[move -1][j]이 일치하면, 인형이 사라지기 때문에, 이를 stack.pop()
메서드를 사용하여 중복으로 나오는 값을 제거해준다. 이때의 사라지는 인형을 카운팅하여 최종값으로 리턴하며, 해당 if, else
문이 끝나면, 해당 글자 값을 0으로 변경해주어, 반복을 다시 진행한다.