Level 1
달리기 경주
얀에서는 매년 달리기 경주가 열립니다.
해설진들은 선수들이 자기 바로 앞의 선수를 추월할 때 추월한 선수의 이름을 부릅니다.
선수들의 이름이 1등부터 현재 등수 순서대로 담긴 문자열 배열 players와 해설진이 부른 이름을 담은 문자열 배열 callings가 매개변수로 주어질 때, 경주가 끝났을 때 선수들의 이름을 1등부터 등수 순서대로 배열에 담아 return 하는 solution 함수를 완성해주세요.
틀린 풀이
forEach 반복문 안에 indexOf() 메서드를 사용하므로 시간복잡도가 O(n^2)가 되어 시간 초과로 실패하였습니다.
1
2
3
4
5
6
7
8
function solution(players, callings) {
callings.forEach((x) => {
let index = players.indexOf(x);
players.splice(index - 1, 2, x, players[index - 1]);
});
return players;
}
풀이
O(n)이 되도록 Map 객체를 이용했습니다.
경기가 진행되는 동안 바뀌는 순위를 저장하는 데이터로 Map을 사용했습니다.
순위가 변동되면 Map의 value값을 변경하였고 value값을 index로 활용해 players 배열을 정렬하였습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function solution(players, callings) {
let map = new Map();
players.forEach((x, index) => {
map.set(x, index);
});
callings.forEach((x) => {
let rank = map.get(x);
map.set(players[rank - 1], rank);
map.set(x, rank - 1);
[players[rank - 1], players[rank]] = [players[rank], players[rank - 1]];
});
return players;
}
공원 산책
- 주어진 방향으로 이동할 때 공원을 벗어나는지 확인합니다.
- 주어진 방향으로 이동 중 장애물을 만나는지 확인합니다.
위 두 가지중 어느 하나라도 해당된다면, 로봇 강아지는 해당 명령을 무시하고 다음 명령을 수행합니다.
공원을 나타내는 문자열 배열 park, 로봇 강아지가 수행할 명령이 담긴 문자열 배열 routes가 매개변수로 주어질 때, 로봇 강아지가 모든 명령을 수행 후 놓인 위치를 [세로 방향 좌표, 가로 방향 좌표] 순으로 배열에 담아 return 하도록 solution 함수를 완성해주세요.
풀이
2차원 배열에서 방향은 객체나 Map 객체를 활용하자.
이동을 방향을 객체로 지정하고 횟수를 반복하며 조건을 확인해보자.
조건에 따라 취소 기능은 위의 [nx, ny]와 같은 tmp에 담았다가 만족하면 넘겨주자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
function solution(park, routes) {
let position = [];
//방향에 대한 객체 생성
let dict = {
E: [0, 1],
W: [0, -1],
N: [-1, 0],
S: [1, 0],
};
// for문으로 break || find 메서드
park.find((x, i) => {
if (x.includes("S")) {
position = [i, x.indexOf("S")];
return 1;
}
});
routes.forEach((x) => {
let [op, n] = x.split(" ");
// tmp 배열
let [nx, ny] = position;
// 조건에 맞는 지 확인할 데이터
let cnt = 0;
// 장애물, 범위 벗어나는 조건 확인
while (cnt < n) {
nx += dict[op][0];
ny += dict[op][1];
if (!park[nx] || !park[nx][ny] || park[nx][ny] == "X") break;
cnt++;
}
// 조건에 모든 만족할 때 실제 위치를 옮김
if (cnt == n) position = [nx, ny];
});
return position;
}
[1차] 비밀지도
arr1, arr2 두 배열의 같은 인덱스 값을 2진수로 변환했을 때 0은 ‘ ‘으로 0이 아니면 ‘#’으로 변환한 문자열로 이루어진 배열을 반환하자.
- 문자열의 길이는 n이며, 공백이 앞에 올 수도 있습니다.
- 2진수를 n 길이에 맞춰 앞에 0을 붙여주어야합니다.
풀이
- 십진 수를 2진수로 변환 :
toString(2)
두 값을 더한 후 앞 자리 0 채우기
(+arr1[i] + +arr2[i]).toString().padStart(n, "0").split('')
해당 값들 중 0이면 공백 아니면 #으로 변환해 answer 배열에 push
String.prototype.padStart
현재 문자열의 시작을 다른 문자열로 채워, 주어진 길이를 만족하는 새로운 문자열을 반환합니다.
str.padStart(Length [, padString])
- Length : 목표 문자열 길이 지정
- padString : 현재 문자열을 목표 문자열의 길이까지 앞에 채워 넣을 문자열 (기본값은 공백 “ “)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function solution(n, arr1, arr2) {
var answer = [];
arr1 = arr1.map((x) => x.toString(2));
arr2 = arr2.map((x) => x.toString(2));
for (let i = 0; i < n; i++) {
let arr = (+arr1[i] + +arr2[i]).toString().padStart(n, "0").split("");
let str = "";
arr.forEach((x) => {
if (x > 0) str += "#";
else str += " ";
});
answer.push(str);
}
return answer;
}
다른 풀이
- (v | arr2[i])
- arr1 배열과 arr2 배열의 같은 인덱스 값을
OR 비트연산
합니다.
OR 비트연산은 둘 중 하나라도 1이면 true 즉, 1
toString(2)으로 2진수로 변환한후 replace 메서드와 정규표현식으로 1이면 # 0이면 공백으로 문자열 변환
- 생성된 배열 바로 return
replace(/1|0/g, (a) => +a ? "#" : " ")
- 여기서 콜백의 매개변수 a는 앞의 정규표현식으로 바꿀 문자를 의미합니다. g 플래그가 있으므로 전체 확인
1
2
3
4
5
6
7
8
9
10
11
12
13
function solution(n, arr1, arr2) {
return arr1.map((v, i) =>
addZero(n, (v | arr2[i]).toString(2)).replace(/1|0/g, (a) =>
+a ? "#" : " "
)
);
}
// padStart 메서드 모를 때 함수 구현
// n : 목표 길이, s : 기존 문자열
const addZero = (n, s) => {
return "0".repeat(n - s.length) + s;
};
문자열 내 마음대로 정렬하기
문자열로 구성된 리스트 strings와, 정수 n이 주어졌을 때, 각 문자열의 인덱스 n번째 글자를 기준으로 오름차순 정렬하려 합니다.
예를 들어 strings가 [“sun”, “bed”, “car”]이고 n이 1이면 각 단어의 인덱스 1의 문자 “u”, “e”, “a”로 strings를 정렬합니다.
풀이
입력으로 받은 n을 인덱스로 사용해 localeCompare 함수를 사용합니다.
localeCompare()
메서드정렬 순으로 지정된 문자열 앞 혹은 뒤에 오는지 또는 동일한 문자열인지 나타내는 수치를 반환합니다.
str.localeCompare(compareString)
compareString : 비교할 문자열
반환 값 : str이 compareString보다 알파벳 순으로 앞에 있으면 음수, 뒤면 양수, 같으면 0
1
2
3
4
5
function solution(strings, n) {
strings.sort();
return strings.sort((a, b) => a[n].localeCompare(b[n]));
}
다른 풀이
1
2
3
4
5
6
7
8
9
10
11
function solution(strings, n) {
strings.sort((next, prev) => {
if (next[n] == prev[n]) {
return next < prev ? -1 : 1;
} else {
return next.charCodeAt(n) - prev.charCodeAt(n);
}
});
return strings;
}
[PCCP 기출문제] 1번 / 붕대 감기
어떤 게임에는 붕대 감기라는 기술이 있습니다.
붕대 감기는 t초 동안 붕대를 감으면서 1초마다 x만큼의 체력을 회복합니다. t초 연속으로 붕대를 감는 데 성공한다면 y만큼의 체력을 추가로 회복합니다. 게임 캐릭터에는 최대 체력이 존재해 현재 체력이 최대 체력보다 커지는 것은 불가능합니다.
기술을 쓰는 도중 몬스터에게 공격을 당하면 기술이 취소되고, 공격을 당하는 순간에는 체력을 회복할 수 없습니다. 몬스터에게 공격당해 기술이 취소당하거나 기술이 끝나면 그 즉시 붕대 감기를 다시 사용하며, 연속 성공 시간이 0으로 초기화됩니다.
몬스터의 공격을 받으면 정해진 피해량만큼 현재 체력이 줄어듭니다. 이때, 현재 체력이 0 이하가 되면 캐릭터가 죽으며 더 이상 체력을 회복할 수 없습니다.
당신은 붕대감기 기술의 정보, 캐릭터가 가진 최대 체력과 몬스터의 공격 패턴이 주어질 때 캐릭터가 끝까지 생존할 수 있는지 궁금합니다.
붕대 감기 기술의 시전 시간, 1초당 회복량, 추가 회복량을 담은 1차원 정수 배열 bandage와 최대 체력을 의미하는 정수 health, 몬스터의 공격 시간과 피해량을 담은 2차원 정수 배열 attacks가 매개변수로 주어집니다. 모든 공격이 끝난 직후 남은 체력을 return 하도록 solution 함수를 완성해 주세요. 만약 몬스터의 공격을 받고 캐릭터의 체력이 0 이하가 되어 죽는다면 -1을 return 해주세요.
풀이
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function solution(bandage, health, attacks) {
let time = 0;
let cur_health = health;
let succ_cnt = 0;
let [t, x, y] = bandage;
for (let [timing, deal] of attacks) {
for (; time <= timing; time++) {
let change = 0;
if (time == timing) {
succ_cnt = 0;
change -= deal;
} else if (succ_cnt < t - 1) {
succ_cnt += 1;
change = x;
} else {
succ_cnt = 0;
change = x + y;
}
cur_health = cur_health + change > health ? health : cur_health + change;
if (cur_health <= 0) return -1;
}
}
return cur_health;
}