Skip to main content

JS 알고리즘을 위한 문법 정리

1.입력/출력

// BOJ에서의 입력 가이드
const TC = `
1000 1 1000
999 1000
`;

const readline = (() => {
const stdin =
process.platform === "linux"
? require("fs").readFileSync("dev/stdin").toString().split("\n")
: TC.trim().split("\n");

let line = 0;
return () => stdin[line++];
})();

const [N, M, V] = readline().split(" ").map(Number); // 정점수, 간선수, 시작노드
process.stdout.write(`${now} `); // 개행없이 출력
console.log(now) // 출력 및 개행

2.변수/반복문

// let으로 선언하여 반복자(i++)로 사용한다.
for (let i = 0; i < M; i++) {
const [u, v] = readline().split(" ").map(Number);
graph[u].push(v); graph[v].push(u);
}

3.문자열 다루기

str > arr

// str > arr
"123".split(""); // [1,2,3]
"1 2 3".split(" "); // [1,2,3]
"1,2,3".split(","); // [1,2,3]

// 공백문자도 하나의 문자로 취급
" P ".split(""); // [' ', 'P', ' ', ' ']
// 공백제거 + 분리 (배열에 빈 문자열이 들어간것에 주의!)
" P ".split(" "); //  ['', 'P', '', '']
",P,,".split(","); // ['', 'P', '', '']

padStart, padEnd

// 길이 5만큼 앞에서 부터 0으로 채우기
String("12").padStart(5,"0"); // 00012

📌 slice

  • substring 대신 slice을 사용할것 ( substring은 음수를 0으로 간주하여 처리한다)
  • substr은 비권장 (비일관성 인자)
'abcd'.slice(1) // bcd
'abcd'.slice(-1) // d
'abcd'.slice(1,3) // bc
"abcd".slice(1,-1) // bc
// (] - end is not included

+문자열에서 특정 단어수 카운팅

"00111222".split("").filter(e => e ==="0").length; // 2

이진변환

// 1. 10진법(숫자) > 2진법(문자열)  
(42).toString(2); // '101010'
// 2. 2진법(문자열) > 10진법(숫자)
parseInt("101010",2); // 42

문자열 코드 (charCode)

charCodeAt, String.fromCharCode

https://school.programmers.co.kr/learn/courses/30/lessons/12926?language=javascript

// 'A'.charCodeAt() // 65
// String.fromCharCode(65) // 'A'

// a 97 - z 122
// A 65 - Z 90
// range - 0~25
function move(e,n){
if(e === " ") return e;
const code = e.charCodeAt();
if(code >= 97){
const nextCode = (code-97 + n) % 26
return String.fromCharCode(nextCode+97);
}else{
const nextCode = (code-65 + n) % 26
return String.fromCharCode(nextCode+65);
}
}

function solution(s, n) {
var answer = '';
const result = s.split("").map((str)=>move(str,n)).join("");
return result;
}

4.1 Array - 기본

📌 mutable, immutable 컨벤션

  • sort() : mutable, 원본이 수정된다.
  • toSorted() : immutable, 원본을 유지하며 정렬된 배열리턴
  • *이처럼 splice(), toSpliced() 메서드도 추가되고 있다.

📌 초기화

// [1] new Array 버전
// 1차원 배열 (크기 N)+ 0 초기화
new Array(N).fill(0); // [0,0,0,0]
new Array(N).fill(0).map((_,idx) => idx+1); // [0,1,2,3]
readline().split(" ").map(Number); // from input

// 2차원 배열
new Array(N).fill(0).map(() => new Array()); // [[], [], []]
new Array(N).fill(0).map(() => new Array(),fill(0)); // [[0,0,0], [0,0,0], [0,0,0]]

// [2] Array.from 버전
// 1차원 배열 초기화
Array.from({ length: N }, () => 0); // [0, 0, 0, 0, 0]
// 1차원 배열 초기화 및 idx
Array.from({ length: 5 }, (_,idx) => idx); // [0, 1, 2, 3, 4]

// 2차원 배열 초기화
Array.from({ length: N }, () => new Array(M).fill(0));
// 2차원 배열 초기화 3*5, 0~14 까지
Array.from({ length: 3 }, (_,i) => new Array(5).fill(0).map((_,j)=> i*5 + j ));

4.2 Array - 알고리즘

📌 JavaScript 배열 메서드: Mutable vs Immutable

Mutable (변형 O)  
push(value) ✅ (배열 끝에 추가)
pop() ✅ (배열 끝에서 제거)
unshift(value) ✅ (배열 앞에 추가)
shift() ✅ (배열 앞에서 제거)
splice(start, deleteCount, ...items) ✅ (특정 위치에서 요소 제거/추가)
sort(compareFn) ✅ (배열 정렬, 원본 변경)
reverse() ✅ (배열 순서 반전)
fill(value, start, end) ✅ (특정 범위 값 변경)
copyWithin(target, start, end) ✅ (자기 자신을 복사하여 덮어씀)

Immutable (변형 X, 새 배열 반환) slice(start, end) ❌ (부분 배열 반환)
map(callback) ❌ (새로운 배열 반환)
filter(callback) ❌ (조건에 맞는 요소만 새 배열 반환)
reduce(callback, initialValue) ❌ (누적 연산 수행, 배열 변형 X)
concat(arr2, arr3, …) ❌ (배열 합치기)
flat(depth) ❌ (중첩 배열 펼쳐서 새 배열 반환)
toSorted(compareFn) ❌ (정렬된 새 배열 반환)
toReversed() ❌ (뒤집힌 새 배열 반환)

📌 push + pop(뒤에서) + shift + unshift(앞에서)

  • 모두 mutable 함수
const dequeue = [1]; // dq = push + pop(뒤에서) + shift + unshift(앞에서)  
// stack - push + pop
dequeue.push(10); // dequeue = [1, 10]
dequeue.pop(); // dequeue = [1]
// queue - push + unshift
dequeue.unshift(7); // dequeue = [7,1]
dequeue.shift(); // dequeue = [1]

📌 slice, splice, (rotate)

  • slice(immutable)
  • splice(muttable) : splice(시작 인덱스, 제거할 요수 수, 추가할 아이템 들)
    • 제거를 먼저하고 추가 된다.
// slice
const arr = ['a','b','c'];
arr.slice(1) // ['b','c']
arr.slice(-1) // ['c']
arr.slice(1,3) // ['b','c']
arr.slice(1,-1) // ['b'], -1은 'c'를 가르키는데 이는 제외 된다.
// (] - end is not included

// splice
var myFish = ["angel", "clown", "trumpet", "sturgeon"];
var removed = myFish.splice(0, 2, "parrot", "anemone", "blue");
var removed = myFish.splice(0, 2, ...["parrot", "anemone", "blue"]); // 이렇게 넘겨도 된다.
// myFish is ["parrot", "anemone", "blue", "trumpet", "sturgeon"]
// removed is ["angel", "clown"]

// rotate(by1)
let arr = ['1','2','3'];
arr = [...arr.slice(1), ...arr.slice(0,1)];

// rotate(by n)
function rotateArray(arr, k, direction = "right") {
const n = arr.length;
if (n === 0) return arr; // 빈 배열 처리
k = k % n; // 배열 길이보다 큰 k 처리

if (direction === "left") {
return arr.slice(k).concat(arr.slice(0, k));
} else {
return arr.slice(-k).concat(arr.slice(0, -k));
}
}

📌 concat

  • concat(immutable)
const arr1 = [1, 2];
const arr2 = [3, 4];
const arr3 = [7];

// 단일값 합치기
arr1.concat(arr2).concat(arr3) // (5) [1, 2, 3, 4, 7]
arr1.concat(arr2, arr3) // (5) [1, 2, 3, 4, 7]
// 특별히 배열아닌 원소도 들어간다.
arr1.concat(arr2, arr3, 8, [9]) // (7) [1, 2, 3, 4, 7, 8, 9]

📌 flat

  • flat(immutable) : 원소의 배열을 하나 까서 리턴
[[1],[2],3,[[4]]].flat() // [1, 2, 3, Array(1)]

📌 deepCopy

// 재귀 함수를 이용해서 프리미티브 타입일때까지 재귀함수를 호출한다.
const deepCopy = (items) => items.map((item) => (Array.isArray(item) ? deepCopy(item) : item))

📌 Remove multiple elements by index (array)

// 방법 1.  indexOf + filter 이용 
// - N**2 시간이 예상되며 , 대신 코드가 깔끔
const arr = ["v1","v2","v3","v4","v5"];
const toBeRemoveIdx = [2, 0, 4];
arr.filter((val,idx)=> {
return toBeRemoveIdx.indexOf(idx) === -1
})

// 방법 2. 정렬 및 splice 이용
// - NlogN, 뒤에서부터 제거하면 인덱스 영향 받지 않고 가능
const arr = ["v1","v2","v3","v4","v5"];
const toBeRemoveIdx = [0, 2, 4];

toBeRemoveIdx.sort((a,b)=>b-a)
for(let idx of toBeRemoveIdx){ arr.splice(idx,1) }

4.3 Array - 정렬

  • compartor함수에서 -1 = a,b는 올바른 순서, 0 = 판단 불가, 1 = 역순이다.
// 숫자, 문자, bool 정렬  
const arr = [1,2,8,4,2,1,0]
arr.sort((a,b) => a-b); // [0, 1, 1, 2, 2, 4, 8]

const arr = ['banana','apple','a','b','ab'];
arr.sort((a,b) => a.localeCompare(b)) // ['a', 'ab', 'apple', 'b', 'banana']

'a'.localeCompare('b') // -1 (a 다음에는 b가 온다.)
'b'.localeCompare('b') // 0 (동등)
'bc'.localeCompare('b') // 1 ( bc 다음 b 오는건 아니다.)

// 커스텀 enum 정렬
const Colors = {
RED: 1,
GREEN: 2,
BLUE: 3,
YELLOW: 4
};
const c = ["GREEN","RED","BLUE"];
c.sort((a,b) => Colors[a] - Colors[b]); // ['RED', 'GREEN', 'BLUE']

// 커스텀 객체 정렬
const people = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
{ name: "Charlie", age: 25 },
{ name: "David", age: 30 },
{ name: "Eve", age: 20 }
];
people.sort((a, b) => {
if (a.age === b.age) return a.name.localeCompare(b.name);
return a.age - b.age; // 나이로 오름차순 정렬
});

console.log(people);

5.1 Object 01 기본

5.2 Object 02 알고리즘

6. 자료구조

시간

GMT vs UTC

한국은 9시간이 빠르다.

한국은 영국 그리니치 천문대보다 9시간이 빠르므로 GMT+9라고, UTC+9 표기한다.

  • 대한민국 시간은 Coordinated Universal Time 시간보다 9시간 빠릅니다.
  • Coordinated Universal Time 시간으로 목요일 오후 1:06이면
  • 목요일 오후 10:06, 대한민국(GMT+9)입니다.

Ref) aws DB인스턴스의 시간 수정방법

JS에서 ISO 형식

new Date().toTimeString()
'21:18:39 GMT+0900 (한국 표준시)'
new Date().toGMTString()
'Sun, 09 Jun 2024 12:18:44 GMT'
new Date().toISOString()
'2024-06-09T12:18:48.464Z'
new Date().toLocaleDateString()
'2024. 6. 9.'
new Date().toLocaleString()
'2024. 6. 9. 오후 9:19:01'
new Date().toLocaleTimeString()
'오후 9:19:09'
new Date().toTimeString()
'21:19:15 GMT+0900 (한국 표준시)'
new Date().toUTCString()
'Sun, 09 Jun 2024 12:19:21 GMT'

2020-05-11T02:00:00.000Z

  • Z = Zulu time = GMT = UTC 다 같은말 이다.
  • 위의 5월 11일 오전 2시(UTC) >>> 한국시간으로 5월 11일 11시
  • 위 같은 형식을 ISO 형식이라고 한다. ( 표준시 표기 )
  • 시간대를 포함하고 싶다면 아래와 같이 사용하면 된다.

2021-07-17T14:30:00+09:00

  • ( 한국기준 ) 위 시각 표시는 17일 14:30이라는 뜻이다
  • ( 그리니치 기준, GMT+0 기준 ) 위 시각 표시는 17일 05:30으로 읽어야 한다.

UTC -> 한국시각

// UTC 시간대로 Date 객체를 만들면 , 한국 시간으로 출력해준다. 
let timeSource = "2020-10-05T09:00:00.000Z"
let dateObj = new Date(timeSource);
console.log(dateObj); // 2020-10-05T09:00:00.000Z

// toLocale 을 이용해서 출력도 된다.

let timeString = dateObj.toLocaleString("en-US", {timeZone: "Asia/Seoul"});
let timeString_KR = dateObj.toLocaleString("ko-KR", {timeZone: "Asia/Seoul"});

console.log(timeString); // 10/5/2020, 6:00:00 PM
console.log(timeString_KR); // 2020. 10. 5. 오후 6:00:00
- en-US와 ko-KR은 시간을 바꾸진 않고 년월일 같은 형식과 언어를 바꿔준다.
- 뒤의 타임존이 부분이 반영되어 utc를 타임존에 맞는 시간대로 바꿔준다.

// JS 현재 타임존 확인하기

Offset만 확인하면 된다.
alert("Current Local Desktop Date " + new Date() + " whose offset difference is " + new Date().getTimezoneOffset() + " mins from UTC");

유틸

deepCopy

// 2차원 배열 깊은 복사
const deepCopy = (items) =>
items.map((it) => (Array.isArray(it) ? deepCopy(it) : it));
// - spread operator는 첫번째 껍대기의 값만 복사한다.
// - 그 값은 참조값(주소값)이 될 수 있고 프리미티브값(원시값)이 될 수 있다.
// - 하지만 그 값이 어떠한 객체의 주소값이라면 깊은복사가 아니다.

const a = [
[1, 2, 3],
[4, 5, 6],
];
const b = deepCopy(a); //[...a];
console.log(b);
a[0][0] = "a";
console.log(b);

zip (배열들의 요소를 병렬적으로 묶어주는)

// zip
const zip = (...rows) => [...rows[0]].map((_, c) => rows.map((row) => row[c]));
// - 가변인자로 n개의 배열을 받는다. rows는 2차원 배열
// - 첫번째 인자의 배열 크기 만큼 공간을 만든다.
// - 각 배열의 n번째 원소는 인자배열의 n번째 원소가 된다.

const array1 = [1, 2, 3];
const array2 = ["a", "b", "c"];
const array3 = [true, false, true];

const result = zip(array1, array2, array3);
console.log(result);
/*
[
[1, 'a', true],
[2, 'b', false],
[3, 'c', true]
]
*/