Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions ts-programmers/greedy/001_체육복.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
// https://school.programmers.co.kr/learn/courses/30/lessons/42862

{
// 세번째 풀이 Map + 배열 버전
function solution4(n: number, lost: number[], reserve: number[]): number {
// 학생 기본 Map
const studentMap = new Map<number, number>();

// 모든 학생에게 체육복 1벌씩 주기
for (let i = 1; i <= n; i++) {
studentMap.set(i, 1);
}

// 잃은개수 빼기
for (const student of lost) {
studentMap.set(student, studentMap.get(student)! - 1);
}

// 여유분 더하기
for (const student of reserve) {
studentMap.set(student, studentMap.get(student)! + 1);
}

// 배열로 변환하여 순차 처리
const studentArr = Array.from({ length: n }, (_, i) => [
i + 1,
studentMap.get(i + 1)!,
]);

// 체육복 없는 학생이 좌우에서 빌릴 수 있는지 확인
for (let i = 0; i < studentArr.length; i++) {
const [, count] = studentArr[i];

if (count === 0) {
// 왼쪽 학생
if (i > 0 && studentArr[i - 1][1] === 2) {
studentArr[i - 1][1] -= 1;
studentArr[i][1] += 1;
}
// 오른쪽 학생
else if (i < n - 1 && studentArr[i + 1][1] === 2) {
studentArr[i + 1][1] -= 1;
studentArr[i][1] += 1;
}
}
}

// 체육 수업 가능한 학생 수
return studentArr.filter(([, v]) => v >= 1).length;
}

// test
console.log(solution4(5, [2, 2, 2, 4], [1, 2, 3, 3, 5])); // 4

// 세번째 풀이 - 여러 벌 도난 / 여러 벌 보유의 경우
// ex) lost = [2, 2, 4] / reserve = [1, 2, 3, 3, 5]

// 전체 학생에게 1벌을 기본으로 설정
// 각 학생에 대해 앞/뒤 친구 중 여분이 있으면 1개 빌려옴

// 마지막에 체육복이 1개 이상인 학생 수를 세어 반환

function solution3(n: number, lost: number[], reserve: number[]): number {
let answer = 0;

// 학생 기본 Map
const studentMap = new Map<number, number>();

// 모든 학생에게 체육복 1벌씩 주기
for (let i = 1; i <= n; i++) {
studentMap.set(i, 1);
}
console.log(studentMap);

// 잃은개수 빼기
for (const student of lost) {
studentMap.set(student, studentMap.get(student)! - 1);
}

// 여유분 더하기
for (const student of reserve) {
studentMap.set(student, (studentMap.get(student) ?? 0) + 1);
}

for (const [student, count] of studentMap) {
if (count === 0) {
const prev = student - 1;
const next = student + 1;

if (studentMap.get(prev) && studentMap.get(prev)! > 1) {
studentMap.set(prev, studentMap.get(prev)! - 1);
studentMap.set(student, 1);
} else if (studentMap.get(next) && studentMap.get(next)! > 1) {
studentMap.set(next, studentMap.get(next)! - 1);
studentMap.set(student, 1);
}
}
}
for (const count of studentMap.values()) {
if (count >= 1) answer++;
}
return answer;
}

// test
// console.log(solution3(5, [2, 2, 4], [1, 2, 3, 3, 5])); // 5

// 두번째 풀이
function solution2(n: number, lost: number[], reserve: number[]): number {
const filteredLost: number[] = lost
.filter((x) => !reserve.includes(x))
.sort((a, b) => a - b);
const filteredReserve: number[] = reserve.filter((x) => !lost.includes(x));

const reserveSet: Set<number> = new Set(filteredReserve);

let answer = n - filteredLost.length;

for (const student of filteredLost) {
if (reserveSet.has(student - 1)) {
reserveSet.delete(student - 1);
answer++;
} else if (reserveSet.has(student + 1)) {
reserveSet.delete(student + 1);
answer++;
}
}

return answer;
}

// 첫번째 풀이
function solution(n: number, lost: number[], reserve: number[]): number {
// 잃어버린 사람의 +1 / -1 값이 reserve에 있다면 빌려주기 완 그리고 n에 ++
// 5명 중 못 빌린 사람을 빼면 값이 나옴

// 누락된 조건 추가 (여분을 가지고 있는 사람 중 도난당한 경우)
const filteredLost = lost
.filter((x) => !reserve.includes(x))
.sort((a, b) => a - b);
const filteredReserve = reserve
.filter((x) => !lost.includes(x))
.sort((a, b) => a - b);

for (const lostStudent of filteredLost) {
const idx = filteredReserve.findIndex(
(v) => v === lostStudent - 1 || v === lostStudent + 1
); // findIndex(callback) 여기서 인자 v 는 filteredReserve의 각 요소가 들어옴

if (idx !== -1) {
filteredReserve.splice(idx, 1);
n++;
}
}

return n - filteredLost.length;
}

// test
// console.log(solution(5, [2, 4], [1, 3, 5])); // 5
// console.log(solution2(5, [2, 4], [1, 3, 5])); // 5
}
40 changes: 40 additions & 0 deletions ts-programmers/greedy/002_조이스틱.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// https://school.programmers.co.kr/learn/courses/30/lessons/42860

import _ from 'lodash';

{
// 로직을 나눈다면? 위 / 아래 조작 횟수 계산
function countUpDownMoves(char: string): number {
const up = char.charCodeAt(0) - 'A'.charCodeAt(0);
const down = 'Z'.charCodeAt(0) - char.charCodeAt(0) + 1;
return Math.min(up, down);
}

function countLeftRightMoves(str: string[]): number {
let minMove = str.length - 1;
for (let i = 0; i < str.length; i++) {
let next = i + 1;

while (next < str.length && str[next] === 'A') {
next++;
}

const goAndBack = i + i + (str.length - next);
const backAndGo = i + (str.length - next) * 2;

minMove = Math.min(minMove, goAndBack, backAndGo);
}

return minMove;
}

// 좌 / 우 조작(커서 이동) 최소화 (a일 경우에 넘어가야하는?)
function solution(name: string): number {
return (
_.sum([...name].map(countUpDownMoves)) + countLeftRightMoves([...name])
);
}

// test
console.log(solution('JAZ')); // 11
}
76 changes: 76 additions & 0 deletions ts-programmers/greedy/003_큰_수_만들기.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// https://school.programmers.co.kr/learn/courses/30/lessons/42883

{
function solution(number: string, k: number): string {
const answer: number[] = [];

for (const char of number) {
const num = Number(char);

// 이름 붙이기
// 스택의 마지막 숫자가 현재 숫자보다 작으면 제거한다 (더 큰 숫자를 앞으로 배치)
// 제거 가능한 기회(k)가 남아있는 동안 반복한다.
while (k > 0 && answer.length && answer.at(-1)! < num) {
answer.pop();
k--;
}
}

// 만약 k 가 남았을 경우 뒤에서 잘라줘야함
if (k > 0) {
answer.splice(-k);
}

return answer.join('');
}

// test
console.log(solution('4177252841', 4)); // 775841

// solution2 - 함수형으로 분할해보고 assert 까지 적용해보기
function isDescending(arr: number[]): boolean {
for (let i = 0; i < arr.length - 1; i++) {
if (arr[i] < arr[i + 1]) return false;
}
return true;
}

function optimizeStack(stack: number[], num: number, k: number): number {
// while 없애면 assert 터트릴 수 있음
while (k > 0 && stack.length && stack.at(-1)! < num) {
stack.pop();
k--;
}
stack.push(num);
console.assert(
isDescending(stack),
'스택의 숫자는 항상 내림차순이어야 함당'
);
return k;
}

function solution2(number: string, k: number): string {
const answer: number[] = [];

for (const char of number) {
const num = Number(char);
k = optimizeStack(answer, num, k);
}

if (k > 0) {
answer.splice(-k);
}

return answer.join('');
}

// test
console.log(solution2('4177252841', 4)); // 775841
}
// // ok, k > 0
// [4]
// [4, 1]

// // not ok
// [7, 2, 5]
// [1,2,3]