TIL
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec
Sun
Mon
Tue
Wed
Thu
Fri
Sat
Today I Learned를 기록하는 공간입니다. 🔥🔥🔥
잔디를 클릭하면 내용확인이 가능합니다.
잔디를 클릭하면 내용확인이 가능합니다.
프로그래머스 고득점 kit 그리디 복습
Array.indexOf(value)
- 배열에 있는 특정 값에 대한 인덱스 반환
- 없으면 -1, 있으면 가장 가까운 인덱스
체육복 문제
- 초기 접근 ⇒ filter 메소드를 통해 중복되는 부분 제거 (비효율) , set을 통해 순회한 값 판단
function solution(n, lost, reserve) {
const lostSet = new Set(lost);
const reserveSet = new Set(reserve);
for (const v of reserve) {
if (lostSet.has(v)) {
lostSet.delete(v);
reserveSet.delete(v);
}
}
for (const v of lostSet) {
if (reserveSet.has(v - 1)) {
reserveSet.delete(v - 1);
} else if (reserveSet.has(v + 1)) {
reserveSet.delete(v + 1);
} else {
n--;
}
}
return n;
}
⇒ Set, Map등 다양한 자료구조를 사용한다면 훨씬 더 직관적이고 효율적인 구현이 가능
⇒ 특히 체육복문제와 같이 독립적인 값에서의 중복제거는 set이 매우 이상적
리스트로 답이 없을 것 같다 싶으면, 다른 컬렉션 구조를 한번 보자
조이스틱 문제
- 초기 접근
- 커서의 알파벳 개수를 찾고, 우측과 좌측중 당장 가장 가까운 곳을 식별 후 이동하도록 구현
- 이러면
"BBBAAAAAAAB"다음과 같은 예제 해결 불가 ⇒ 틀림
/*
- 'N' 보다 클 부터는 이전 알파벳으로 이동하는게 더 빠름
- 작성 후, 우측과 좌측 중 가장 빠르게 작성할 수 있는 곳 식별
*/
function solution(name) {
const alpha = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4,
3, 2, 1,
];
let str = new Array(name.length).fill("A");
let cursor = 0;
let count = 0;
while (true) {
let code = name[cursor].charCodeAt(0) - 65;
count += alpha[code];
str[cursor] = name[cursor];
if (str.join("") === name) break;
let checkLR = checkLeftRight(str, name, cursor);
count += Math.abs(checkLR);
if (cursor + checkLR < 0) cursor = str.length + checkLR;
else cursor = cursor + checkLR;
}
return count;
}
function checkLeftRight(str, name, cursor) {
let right_count = 0;
let left_count = 0;
let idx = cursor;
while (true) {
right_count++;
idx++;
if (str[idx] !== name[idx]) break;
}
idx = cursor;
while (true) {
left_count++;
idx--;
if (idx === -1) idx = name.length - 1;
if (str[idx] !== name[idx]) break;
}
return right_count <= left_count ? right_count : -left_count;
}
- 정답 코드 ( GPT )
function solution(name) {
const alpha = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4,
3, 2, 1,
];
let count = 0;
// 1️⃣ 알파벳 변경 비용 (네 로직 그대로)
for (let i = 0; i < name.length; i++) {
const code = name[i].charCodeAt(0) - 65;
count += alpha[code];
}
// 2️⃣ 커서 이동 최소값 계산 (checkLR의 역할을 승격)
let move = name.length - 1;
for (let i = 0; i < name.length; i++) {
let next = i + 1;
// 연속된 A 스킵
while (next < name.length && name[next] === "A") {
next++;
}
// 👉 네가 while에서 하려던 판단을 "수식"으로 한 번에
const goRightThenLeft = i * 2 + (name.length - next);
const goLeftThenRight = i + (name.length - next) * 2;
move = Math.min(move, goRightThenLeft, goLeftThenRight);
}
return count + move;
}
⇒ 이 문제의 핵심풀이
커서가 한 번만 방향을 바꾼다는 성질을 이용해, 그 전환 지점을 전부 후보로 두고 각 경우의 이동 비용을 계산한 뒤 최솟값을 선택하는 문제
실화냐;;;; 개어렵다;;; 접근 방식은 알았으니 다음에 다시 풀자
큰 수 만들기
- 초기 접근
- 제한 조건 숫자가 100만, 조합 사용 불가능 ⇒ 앞에서부터 순차적으로 탐색
- 탐색한 수 보다 더 큰수가 있다면 거기까지 자르고 k를 사용할 수 있을 만큼 작은 수 세기 ⇒ 효율성 X
function solution(number, k) {
var answer = "";
const stack = [];
for (let digit of number) {
while (stack.length && k > 0 && stack[stack.length - 1] < digit) {
stack.pop();
k--;
}
stack.push(digit);
}
return stack.join("").slice(0, stack.length - k);
}
⇒ 이 문제 핵심풀이
- 순차적으로 탐색하면서 스택을 사용해서 값 저장.
- 스택의 마지막 값 보다 현재 값이 더 크다면 값을 가지고 있을 이유가 없기에 k가 남아있는 만큼 버릴 수 있음
- 전부 순회 후 k가 남아 있다 ⇒ 앞에 값들이 이미 더 큰값으로 채워져있음
- 남은 k만큼 꼬리 제거
이것도 다시풀어 보자