Lv1 총 56문제 풀이 기간: 2022.09.04 ~ 2022.09.16
파이썬으로 한 번씩 다 풀었던 문제들인데 코딩 테스트 언어를 자바스크립트로 바꾸면서 공부를 위해 다시 풀었습니다.
문제를 풀면서 정리한 자바스크립트 개념을 PR에 적어놨는데 검색에 불편함을 느껴 블로그에 정리해두려고 합니다.
📌는 다시 풀어볼 문제를 의미합니다.
K번째 수
https://github.com/algo-malgo/jungo-malgo/pull/3
공부한 개념
- slice
- for of / for in / forEach
- sort
- push
참고 레퍼런스
- [Javascript] 배열 자르기 - slice()
- [javascript] for in / for of / forEach() 차이점
- [Javascript] 배열 정렬하기 (오름차순, 내림차순, 문자열, 객체)
- 자바스크립트 배열에 원하는 값 넣기
후기
function solution(array, commands) {
return commands.map(command => {
const [sPosition, ePosition, position] = command
const newArray = array
.filter((value, fIndex) => fIndex >= sPosition - 1 && fIndex <= ePosition - 1)
.sort((a,b) => a - b)
return newArray[position - 1]
})
}
command를 구조 분해 할당한 다른 사람의 풀이를 봤는데 가독성 측면에서 더 좋은 것 같다.
모의고사 (Array.from)
https://github.com/algo-malgo/jungo-malgo/pull/5
공부한 개념
- 길이가 3인 배열을 모든 값을 0으로 채워서 생성하고 싶을 때는 다음과 같이 작성한다.
- Array.from({length: 3}, () => 0)
- 최대값은 Math의 max를 사용해서 구한다. 배열의 경우 스프레드 연산자를 사용해서 넣어준다.
- Math.max(...answer)
참고 레퍼런스
후기
map 안에서 && 연산자를 사용했다.
리액트에서 많이 사용했던 연산자인데 여기서 사용하니까 색다르다.
체육복 📌
https://github.com/algo-malgo/jungo-malgo/pull/7
후기
처음에는 여벌을 가진 학생이 도난당한 경우를 아래와 같이 배열에서 제외해줬는데
const tmp = [...reserve]
for (let i = 0; i < tmp.length; i++) {
const idx = lost.indexOf(tmp[i]);
if (idx !== -1) {
lost.splice(idx, 1);
reserve.splice(reserve.indexOf(tmp[i]), 1);
answer += 1;
}
}
filter를 이용하여 조금 더 깔끔하게 짤 수 있는 방법이 있길래 아래와 같이 수정했다.
const newLost = lost.filter(l => !reserve.includes(l));
const newReserve = reserve.filter(r => !lost.includes(r));
좀 더 효율적으로 코드를 짤 수 있는 방법이 있을까?
나중에 한 번 더 풀어보려고 한다.
완주하지 못한 선수 (Map, || / ??) 📌
https://github.com/algo-malgo/jungo-malgo/pull/9
공부한 개념
해시(Hash)
- 데이터를 다루는 기법 중 하나로, 검색과 저장을 아주 빠르게 하는 자료구조
- Key와 Value가 한 쌍으로 존재 (Hash Table이라고 함)
- key값이 배열의 인덱스로 변환되기 때문에 검색과 저장의 평균적인 시간 복잡도가 O(1)에 수렴
Map
- ES6에서 나온 값들을 매핑하기 위한 새로운 데이터 구조
- 간단한 키와 값을 서로 연결(매핑)시켜 저장하며 저장된 순서대로 각 요소들을 반복적으로 접근 가능
논리 연산자 OR(||)과 널 병합 연산자(??)
- 논리 연산자 OR은 왼쪽 피연산자가 null 또는 undefined 뿐만 아니라 falsy값에 해당할 경우 오른쪽 피연산자를 반환
- 널 병합 연산자는 왼쪽 피연산자가 null또는 undefined일 때 오른쪽 피연산자를 반환하고, 그렇지 않으면 왼쪽 피연산자를 반환
참고 레퍼런스
후기
처음 두 번은 효율성이 0점이었고, 다른 사람 풀이 참고해서 정렬을 이용한 방법으로 풀었다.
하지만 sort()를 사용하는 게 성능 면에서 좋지 않다고 하길래 해시의 특징을 잘 풀어냈다고 하는 아래 코드를 공부했다.
function solution(participant, completion) {
const map = new Map();
for(let i = 0; i < participant.length; i++) {
let a = participant[i],
b = completion[i];
map.set(a, (map.get(a) || 0) + 1);
map.set(b, (map.get(b) || 0) - 1);
}
for(let [k, v] of map) {
if(v > 0) return k;
}
return 'nothing';
}
participant의 길이가 더 기니 completion[i]에서 오류가 나지 않을까 했는데 콘솔에 찍어보니 undefined가 들어가고 있었다.
map에 키가 없는 경우에 get을 하면 undefined를 반환한다.
폰켓몬 (Set)
https://github.com/algo-malgo/jungo-malgo/pull/11
공부한 개념
- Set은 길이를 구할 때 size를 사용
- Set을 배열로 변환할 때는 Array.from()을 사용
참고 레퍼런스
후기
다른 사람 풀이에 스프레드 연산자를 사용한 게 있었다.
Set을 배열로 만들고자 할 때 Array.from()을 사용하지 않고 아래와 같이 쓸 수도 있을 것 같다.
function solution(nums) {
const max = nums.length / 2;
const arr = [...new Set(nums)];
return arr.length > max ? max : arr.length
}
소수 만들기 (조합)
https://github.com/algo-malgo/jungo-malgo/pull/13
공부한 개념
- 조합
- reduce으로 sum 구하기
- comb.reduce((a, b) => a + b, 0);
참고 레퍼런스
후기
파이썬에서 라이브러리로 주어지는 조합 함수를 사용했었다.
JS에서는 조합을 직접 구현해야 했는데 고민을 하다가 결국 구글링을 했다.
다음에 다시 풀 때는 구글링의 도움 없이 풀고 싶다.
*
재귀를 이용한 조합 알고리즘을 사용했는데 다른 사람들의 풀이를 보니까 재귀보다는 3중 반복문을 쓰는 게 시간복잡도 측면에서 더 나은 것 같다.
메모이제이션을 사용해서 시간 복잡도를 줄일 수 있나 싶은데 여기에 메모를 어떻게 적용해야 할지 잘 모르겠다.
2016년
https://github.com/algo-malgo/jungo-malgo/pull/15
후기
다른 사람 풀이를 봤는데 Date를 사용한 사람도 있었다.
시간 복잡도를 고려한다면 사용하지 않는 게 더 좋을 것 같다.
가운데 글자 가져오기 (substr은 레거시, substring 권장)
https://github.com/algo-malgo/jungo-malgo/pull/17
공부한 개념
- substr
- substr("시작 위치", "길이") 또는 substr("시작 위치")
- substring
- substring("시작 위치", "종료 위치") 또는 substring("시작 위치")
- 주의할 점은 종료 위치의 -1까지 문자열을 자른다.
참고 레퍼런스
후기
다른 사람의 풀이를 보는데 substr을 쓰지 말라는 댓글이 있었다.
substr()::JavaScript 레퍼런스
웹 표준에서 제거될 예정이며 레거시로 남아있고, substring을 권장한다고 한다.
그래서 substrring을 사용하는 걸로 바꿨고, 다른 사람의 풀이를 참고해 3항 연산자의 위치를 함수 안으로 옮겨봤다.
같은 숫자는 싫어
https://github.com/algo-malgo/jungo-malgo/pull/19
후기
첫 번째 인덱스의 값은 배열에 무조건 넣고 그 이후의 값들부터 이전의 값과 비교하였는데
다른 사람의 풀이를 보고 이후의 값과 비교하면 한 줄로 문제를 풀 수 있다는 것을 알았다.
나누어 떨어지는 숫자 배열
https://github.com/algo-malgo/jungo-malgo/pull/21
두 정수 사이의 합 (가우스)
https://github.com/algo-malgo/jungo-malgo/pull/23
후기
가우스 공식을 사용하면 더 빠르고 간단하게 풀 수 있다는 것을 알았다.
[알고리즘] 가우스의 덧셈 공식
a ~ b까지의 숫자를 더한 합은
처음 숫자와, 마지막 숫자를 더한 합 = ( a + b )
더할 숫자의 개수 총합의 1/2 = ( b - a + 1) * 1/2
= ( a + b ) * ( b - a + 1) * 1/2
문자열 내 마음대로 정렬하기 (charCodeAt, localeCompare)
https://github.com/algo-malgo/jungo-malgo/pull/25
공부한 개념
- charCodeAt
- localeCompare
참고 레퍼런스
- 자바스크립트 아스키코드 변환하기 (charCodeAt / fromCharCode)
- localeCompare()::JavaScript 레퍼런스
- sort(), localeCompare()
후기
첫 번째 풀이는 문자를 아스키 코드로 변환해서 비교했다.
단, 인덱스 1의 문자가 같은 문자열이 여럿일 경우, 사전순으로 앞선 문자열이 앞쪽에 위치한다는 조건이 있었기 때문에 가장 먼저 사전 순으로 정렬을 먼저 해줬다.
두 번째 풀이는 다른 사람의 코드를 참고해서 하나의 sort로 풀었다.
localeCompare 메서드는 참조 문자열이 정렬 순서에서 앞 또는 뒤에 오는지 또는 주어진 문자열과 같은지를 숫자로 반환한다.
referenceStr이 compareString보다 앞에 있으면 -1, 뒤에 있으면 1, 같으면 0 반환
'a'.localeCompare('b') // -1 ,
'b'.localeCompare('a') // 1
'c'.localeCompare('c') // 0
하지만 첫 번째 코드의 실행 속도가 훨씬 빠르다.
매번 조건을 비교하는 게 생각보다 시간이 오래 걸리는 것 같다.
문자열 내 p와 y의 개수
https://github.com/algo-malgo/jungo-malgo/pull/27
후기
다른 사람의 풀이를 보니 split으로 푸는 신박한 방법도 있었다.
function solution(s){
return s.toUpperCase().split("P").length === s.toUpperCase().split("Y").length;
}
문자열 내림차순으로 배치하기
https://github.com/algo-malgo/jungo-malgo/pull/29
공부한 개념
- sort
- join
- split
참고 레퍼런스
- JavaScript - 배열 정렬 방법 (오름차순, 내림차순)
- JavaScript에서 배열을 문자열로 변환
- [Javascript] 배열을 문자열로 변환하기
- [JavaScript] 문자열 구분자로 자르기 (split)
후기
sort를 하고 reverse를 해서 문자열 내림차순 정렬을 하는 것과 처음부터 sort에서 조건문을 이용해서 내림차순을 하는 코드의 시간을 비교해봤는데 전자가 조금 더 빠른 것 같다.
function solution(s) {
const arr = Array.from(s);
arr.sort((a, b) => {
if (b > a) return 1;
else if (b < a) return -1;
else return 0;
});
return arr.join('');
}
문자열을 배열로 만들기 위해서 Array.from()을 사용했는데 다른 사람의 풀이를 보고 split을 사용해서도 문자열을 배열로 만들 수 있다는 것을 알았다.
그리고 splite, sort, reverse, join 등의 함수가 메소드 체이닝이 가능하다는 것을 알았다.
문자열 다루기 기본 (isNaN/Number.isNaN, Number/parseInt) 📌
https://github.com/algo-malgo/jungo-malgo/pull/31
공부한 개념
- isNaN
- Number.isNaN
- Number
- parseInt
- 정규식
참고 레퍼런스
후기
Number(" ");
Number는 빈 문자열을 0으로 바꾼다.
따라서 !Number.isNaN(Number(" "))을 하면 true가 된다.
parseInt(" ");
parseInt는 빈 문자열을 0으로 바꾸지는 않고 NaN을 반환한다.
!Number.isNaN(parseInt(" "))를 하면 false가 된다.
또한 parseInt("12aa")는 12가 된다.
parseInt("aa12")는 NaN이 된다.
isNaN()과 달리 Number.isNaN()은 강제로 매개변수를 숫자로 변환하지 않는다.
레퍼런스 첫 번째 링크에 둘의 차이점이 자세히 설명되어 있다.
replace는 모든 텍스트를 바꾸지 않는다.
원하는 조건의 텍스트를 모두 바꾸고 싶으면 정규식을 이용하면 된다.
const s = " ";
s = s.replace(/ /gi, "")
테스트 케이스 11번에서 자꾸 fail이 떠서 결국 힌트를 봤는데 지수 표기법을 고려를 못했다.
Number("10e1")을 출력하면 100이 콘솔에 찍힌다.
따라서 e에 대한 예외 처리를 해주는 식으로 마무리했다.
정규식만을 사용해서 푸는 방법도 있다.
function solution(s) {
var regex = /^\d{6}$|^\d{4}$/;
return regex.test(s);
}
test는 문자열에 일치하는 부분이 있는지 확인하고 true 또는 false를 반환한다.
- 데이터의 시작점(^)
- 여섯 개의 숫자(\d{6})
- 데이터의 끝점($)
서울에서 김서방 찾기
https://github.com/algo-malgo/jungo-malgo/pull/33
소수 찾기 (에라토스테네스의 체) 📌
https://github.com/algo-malgo/jungo-malgo/pull/35
공부한 개념
- 에라토스테네스의 체
참고 레퍼런스
후기
첫 번째 코드는 어쩔 때는 효율성을 통과하고 어쩔 때는 시간 초과가 뜬다.
에라토스테네스의 체를 사용하는 게 맞는 것 같다.
다른 사람의 풀이를 보고 에라토스테네스의 체를 공부했다.
function solution(n) {
const s = new Set();
s.add(2);
for (let i = 3; i <= n; i += 2)
s.add(i);
for (let i = 3; i <= n ** 0.5; i += 2)
if (s.has(i)) {
for (let j = i * 2; j <= n; j += i)
s.delete(j);
}
return s.size;
}
2를 제외한 3 이상의 소수만 판별하면 된다.
- 2를 포함한 n까지의 홀수를 Set 객체에 담는다.
- n의 제곱근까지 반복문을 돌리면서 특정 수의 배수를 모두 지운다.
수박수박수박수박수박수? (repeat)
https://github.com/algo-malgo/jungo-malgo/pull/37
공부한 개념
- repeat
참고 레퍼런스
후기
그냥 for문 돌리는 것보다 repeat을 사용해서 푸는 게 더 빠르다.
문자열을 정수로 바꾸기 (Number와 parseInt 차이)
https://github.com/algo-malgo/jungo-malgo/pull/39
공부한 개념
- Number와 parseInt의 차이
Number('') -> 0 / parseInt('') -> NaN
Number(12.123) -> 12.123 / parseInt(12.123) -> 12
Number('12삼') -> NaN / parseInt('12삼') -> 12
참고 레퍼런스
후기
parseInt와 Number를 쓰는 것 이외에도 +s, s/1과 같은 방법이 있다.
시저 암호 📌
https://github.com/algo-malgo/jungo-malgo/pull/41
공부한 개념
- charCodeAt
문자열 -> 아스키 코드 : s.charCodeAt() - fromCharCode
아스키 코드 -> 문자열 : String.fromCharCode() - 파이썬과 달리 isLower()이나 isUpper()같은 함수가 존재하지 않는다. 따라서 아래처럼 판단해준다.
ch === ch.toUpperCase() - filter 함수는 값 못 바꾼다.
- 문자열을 배열로 바꿀 때 Array.from()을 사용하는 것 말고 split("")을 사용하는 방법도 있다.
- charCodeAt의 인자를 비우면 문자열의 첫 번째 값의 아스키 코드를 반환한다.
참고 레퍼런스
후기
다른 사람의 풀이 중에서 내 코드랑 비슷하면서 좀 더 깔끔한 코드를 찾았다.
function solution(s, n) {
return s
.split("")
.map((el) => {
if (el == " ") return el;
const tmp = el.charCodeAt();
return el.toUpperCase().charCodeAt() + n > 90
? String.fromCharCode(tmp + n - 26)
: String.fromCharCode(tmp + n);
})
.join("");
}
나는 대문자와 소문자를 나누어서 구현하느라 코드가 복잡해졌는데
이 코드는 문자의 아스키 코드를 tmp에 저장해둔 다음에 모두 대문자로 변환하여 n을 더했을 때 'Z'를 넘었는지 보고 있기 때문에 더 깔끔한 것 같다.
그리고 다음에 다시 풀 때는 아스키 코드 사용없이 풀어보려고 한다.
약수의 합
https://github.com/algo-malgo/jungo-malgo/pull/42
후기
처음에는 for문을 다 돌렸다가 그럴 필요가 없을 것 같아서 약수의 짝을 한 번에 더해줬다.
이상한 문자 만들기
https://github.com/algo-malgo/jungo-malgo/pull/45
자릿수 더하기 (string / toString)
https://github.com/algo-malgo/jungo-malgo/pull/47
공부한 개념
- toString()과 string()의 차이
- reduce
참고 레퍼런스
- JavaScript - 숫자를 문자열로 변환하는 방법
- JS - String() 과 toString()
- [Node.js] javascript: Array.reduce() 사용 방법 정리
후기
n + ""말고 숫자를 문자열로 변환하는 법에 뭐가 있나 했는데 string()과 toString()이 있었다.
값이 null이나 undefined인 경우에 string()은 문자로 바꿔주고 toString()은 에러가 난다.
toString()은 진수를 변환하고 싶을 경우 사용할 수 있다.
자연수 뒤집어 배열로 만들기
https://github.com/algo-malgo/jungo-malgo/pull/49
후기
문자열 배열로 만들고 숫자로 바꾼 다음에 다시 뒤집는 코드를 작성했는데 10으로 나눠가면서 배열에 숫자를 담는 코드가 더 빠르다.
정수 내림차순으로 배치하기
https://github.com/algo-malgo/jungo-malgo/pull/51
후기
join 메소드를 쓸 때 배열 요소가 문자열이 아니어도 된다.
숫자 풀이 방식과 join을 사용하는 게 시간이 가장 빠른 것 같다.
정수 제곱근 판별
https://github.com/algo-malgo/jungo-malgo/pull/53
공부한 개념
- Number.isInteger()
참고 레퍼런스
제일 작은 수 제거하기 (Math)
https://github.com/algo-malgo/jungo-malgo/pull/55
공부한 개념
- Math
자바스크립트에서 min이나 max값은 직접 구해야하는 줄 알았는데 Math 객체에 존재했다.- Math.abs()
- Math.sqrt()
- Math.min(), Math.max()
- Math.ceil(), Math.floor(), Math.round()
- Math.trunc()
- Math.pow()
- Math에서 자주 사용할 것 같은 메소드
참고 레퍼런스
짝수와 홀수
https://github.com/algo-malgo/jungo-malgo/pull/57
최대공약수와 최소공배수 (유클리드 호제법) 📌
https://github.com/algo-malgo/jungo-malgo/pull/59
공부한 개념
- 유클리드 호제법
최대공약수 (greatest common factor)
2개의 자연수 a, b(a > b)에 대해서 a를 b로 나눈 나머지가 r일 때, a와 b의 최대공약수는 b와 r의 최대공약수와 같다.
1071과 1029의 최대공약수를 구하면,
1071은 1029로 나누어 떨어지지 않기 때문에, 1071을 1029로 나눈 나머지를 구한다. ≫ 42
1029는 42로 나누어 떨어지지 않기 때문에, 1029를 42로 나눈 나머지를 구한다. ≫ 21
42는 21로 나누어 떨어진다.
따라서, 최대공약수는 21이다.
최소공배수 (Least Common Multiple)
두 수 a와 b의 최소공배수는 a와 b의 곱을 a와 b의 최대공약수를 나눈 것과 같다.
참고 레퍼런스
콜라츠 추측
https://github.com/algo-malgo/jungo-malgo/pull/61
후기
while문의 조건문에 count 500을 확인하는 조건을 넣어도 좋을 것 같다.
function solution(num) {
let count = 0;
while (num !== 1 && count !== 500) {
num = num % 2 ? num * 3 + 1 : num / 2;
count += 1;
}
return count === 500 ? -1 : count;
}
평균 구하기 (reduce 초기값)
https://github.com/algo-malgo/jungo-malgo/pull/63
공부한 개념
- reduce
초기값이 없다면 발생하는 경우
배열의 첫번째 요소(0번 인덱스)를 accumulator에 누적한 후 1번 인덱스부터 reducer를 거친다.
배열 요소 1개 + 초기값 x 혹은 빈 배열 + 초기값 o 인 경우에는 그 단독 값을 리듀서를 거치지 않고 바로 반환한다.
빈 배열 + 초기값 x인 경우에 reduce()를 호출하면 TypeError 오류가 발생한다.
이렇게 초기값을 주지 않으면 발생할 수 있는 경우의 수가 3가지이므로 초기값은 주는 것이 안전하다.
참고 레퍼런스
하샤드 수
https://github.com/algo-malgo/jungo-malgo/pull/65
후기
문자열 배열에 reduce를 사용하고 초기값을 생략한 채로 acc과 cur을 더했더니 문자열의 덧셈이 이루어졌다.
알고보니 reduce의 초기값을 생략하면 인덱스 0이 acc에 누적되고 인덱스 1부터 시작되는 거였다.
acc에 문자열이 들어갔으니 다음 덧셈부터는 문자열 덧셈이 이루어져 값이 이상하게 나왔다.
reduce의 초기값에 대해 찾아본 결과 초기값은 생략하지 않다는 것을 알게 되었다.
핸드폰 번호 가리기
https://github.com/algo-malgo/jungo-malgo/pull/67
공부한 개념
- repeat
repeat 메서드는 문자열을 주어진 횟수만큼 반복해 붙인 새로운 문자열을 반환한다. - slice
slice 메서드가 음수도 지원하는 건 처음 알았다.
만일 s.slice(-1)이라고 하면 마지막 문자만 반환한다.
참고 레퍼런스
행렬의 덧셈
https://github.com/algo-malgo/jungo-malgo/pull/69
후기
다른 사람의 풀이를 보다가 첫 번째 코드에서 tmp 배열을 따로 만들 필요 없이 answer[i]로 접근을 할 수 있다는 것을 알았다.
그리고 인상 깊었던 두 번째 풀이는 아래와 같다.
function solution(arr1, arr2) {
return arr1.map((arr, i) => arr.map((n, j) => n + arr[i][j]));
}
로직 자체는 크게 다르지 않은데 map을 사용함으로써 코드 길이를 줄일 수 있기 때문에 괜찮은 접근 방식 같다.
x만큼 간격이 있는 n개의 숫자
https://github.com/algo-malgo/jungo-malgo/pull/71
후기
다른 사람의 풀이에서 인상 깊은 한 줄 코드를 발견했다.
function solution(x, n) {
return Array(n).fill(x).map((v, i) => (i + 1) * v)
}
x로 채워진 n의 길이를 가진 배열을 만들고 map을 돌려가면서 값을 바꾸는 코드다.
Array와 fill의 조합을 생각안한 건 아니지만 빈 배열에 완성된 값을 넣는 코드보다는 성능이 좋지 못할 것 같아서 사용하지 않았다.
근데 그렇게 큰 차이는 없는 것 같기도 하고..
직사각형 별찍기
https://github.com/algo-malgo/jungo-malgo/pull/73
후기
repeat을 두 번 쓰는 방법도 있다.
process.stdin.setEncoding('utf8');
process.stdin.on('data', data => {
const n = data.split(" ");
const a = Number(n[0]), b = Number(n[1]);
console.log(('*'.repeat(a) + '\n').repeat(b))
});
예산
https://github.com/algo-malgo/jungo-malgo/pull/75
[1차] 비밀지도 (이진수 변환, padStart, 비트 OR, replace 두 번째 인자) 📌
https://github.com/algo-malgo/jungo-malgo/pull/77
공부한 개념
- toString(2)
- padStart
'03'.padStart(6,'0'); // '000003'
'2500'.padStart(8,'$'); // "$$$$2500"
'12345'.padStart(10); // " 12345"
'abc'.padEnd(9,'123'); // "abc123123"
'주석문'.padStart(6,'*').padEnd(9,'*'); // "***주석문***"
- 비트 연산자 OR (|)
a | b 두 피연산자의 각 자리 비트의 값이 모두 0인 위치에 0을 반환합니다.
const a = 5; // 00000000000000000000000000000101
const b = 3; // 00000000000000000000000000000011
console.log(a | b); // 00000000000000000000000000000111
// expected output: 7
- replace
replace 메소드의 두 번째 인자에는 함수가 올 수 있다.
const str = '1, 4, 5, 6에서 짝수를 골뱅이로 바꾸고 싶다.';
const findAllNumber = /\d/g;
// 짝수는 @로 바꾸고, 홀수는 놔둠
const changeEvenNumber = number => {
// number는 string형식이기 때문에 number형식으로 바꿔준다.
number = parseInt(number, 10);
return number % 2 === 0 ? '@' : number;
};
const newStr = str.replace(findAllNumber, changeEvenNumber);
console.log(newStr) // '1, @, 5, @에서 짝수를 골뱅이로 바꾸고 싶다.'
위 예제에서 number를 콘솔에 찍어보면 1, 4, 5, 6이 나온다.
정규 표현식의 플래그로 글로벌이 오는 경우에는 일치하는 문자열을 찾을 때마다 함수가 호출된다.
현재 정규 표현식이 /\d/g이므로 숫자인 1, 4, 5, 6의 경우 함수의 인자로 넘어가게 된다.
참고 레퍼런스
후기
다른 사람의 풀이를 공부했다.
function solution(n, arr1, arr2) {
return arr1.map((v, i) => addZero(n, (v | arr2[i]).toString(2)).replace(/1|0/g, a => +a ? '#' : ' '));
}
const addZero = (n, s) => {
return '0'.repeat(n - s.length) + s;
}
- 비트연산자 |를 이용해서 값을 구한 뒤 이진수로 바꿔준다.
- addZero 함수를 호출하여 남은 공간을 0으로 채운다.
- 정규 표현식에 따라 1이나 0인 경우에 함수를 호출하는데 1인 경우에 '#', 0인 경우에 공백으로 대체된다.
addZero 함수를 사용하지 않고 padStart를 사용하는 것이 더 간단할 것 같다.
function solution(n, arr1, arr2) {
return arr1.map((v, i) => (v | arr2[i]).toString(2).padStart(n, '0').replace(/1|0/g, a => +a ? '#' : ' '));
}
나머지가 1이 되는 수 찾기
https://github.com/algo-malgo/jungo-malgo/pull/79
없는 숫자 더하기
https://github.com/algo-malgo/jungo-malgo/pull/81
최소 직사각형
https://github.com/algo-malgo/jungo-malgo/pull/84
후기
두 번째 풀이처럼 forEach 안에서 한 번에 푸는 방법도 있다.
또한, 구조 분해 할당을 이용한 점이 가독성이 더 좋은 것 같다.
부족한 금액 계산하기 (가우스)
https://github.com/algo-malgo/jungo-malgo/pull/86
후기
가우스를 사용하는 방식도 있다.
(첫항 + 마지막항) * 항수 / 2
약수의 개수와 덧셈 (약수 개수 특징)
https://github.com/algo-malgo/jungo-malgo/pull/88
후기
제곱근이 정수면 약수의 개수가 홀수다.
분명 이 말을 다른 문제에서도 본 것 같은데 기억이 안난다...
조금만 생각해보면 쉬운데 자꾸 까먹는다.
제발 잊지 말자!!!
음양 더하기
https://github.com/algo-malgo/jungo-malgo/pull/90
내적
https://github.com/algo-malgo/jungo-malgo/pull/92
3진법 뒤집기 (toString, parseInt 진수 변환)
https://github.com/algo-malgo/jungo-malgo/pull/94
공부한 개념
- toString
원하는 10진수를 특정 진수로 변환하고 싶을때 사용한다.
숫자.toString(진수) - parseInt
문자열을 특정 진수의 정수로 변환한다.
parseInt('변환시키고자하는 문자열', 해당 수의 진수)
참고 레퍼런스
후기
n.toString(3).split('')과 같이 각각의 문자를 배열로 만들기 split을 사용하는 것 대신에 스프레드 연산자를 사용할 수도 있다.
[...n.toString(3)]
두 개 뽑아서 더하기
https://github.com/algo-malgo/jungo-malgo/pull/96
후기
Set 객체를 어떻게 배열로 바꿨는지 기억이 안나서 폰켓몬을 보고 스프레드 연산자를 사용해서 풀었다.
성격 유형 검사하기
https://github.com/algo-malgo/jungo-malgo/pull/98
공부한 개념
- 자바스크립트 객체는 length로 길이를 구하지 못한다.
배열과 문자열에만 length가 있다. - split 사용하지 않고 문자열 쪼개기 (아래 후기 참고)
참고 레퍼런스
후기
function solution(survey, choices) {
const MBTI = {};
const types = ["RT","CF","JM","AN"];
types.forEach((type) =>
type.split('').forEach((char) => MBTI[char] = 0)
)
choices.forEach((choice, index) => {
const [disagree, agree] = survey[index];
MBTI[choice > 4 ? agree : disagree] += Math.abs(choice - 4);
});
return types.map(([a, b]) => MBTI[b] > MBTI[a] ? b : a).join("");
}
다른 사람의 풀이를 보다가 새로운 사실을 알았다.
const alpha = 'ABC';
const [a, b, c] = alpha;
console.log(a, b, c); // A B C
문자열을 저렇게 쪼개기 위해서는 split('')을 써야 한다고 생각했는데 사용하지 않고도 가능했다.
이것도 구조 분해 할당인가 싶어서 검색해봤는데 확실하지는 않다.
그리고 삼항 연산자를 대괄호 안에 쓴 것도 인상깊었다.
절대값을 사용한 것은 생각도 못했다.
위에서 알게된 것들을 적용해봤다.
for (let i = 0; i < survey.length; i++) {
const [t1, t2] = survey[i];
score[choices[i] > 4 ? t2 : t1] += Math.abs(4 - choices[i]);
}
신고 결과 받기
https://github.com/algo-malgo/jungo-malgo/pull/100
공부한 개념
- 배열을 객체의 키로 변환하는 방법
배열을 객체의 키로 변환하고 값은 모두 0으로 초기화 하고 싶었는데 reduce 함수를 이용하면 된다.
const count = id_list.reduce((acc, cur) => {
acc[cur] = 0;
return acc;
}, {});
참고 레퍼런스
후기
처음에는 저 배열을 객체 키로 변환하는 방법을 이용해서 두 개의 객체를 만들었는데 객체가 꼭 두 개나 필요한가? 라는 생각이 들었다.
그러다 예전에 풀었던 파이썬 풀이를 보고 객체를 하나 없애고 빈 배열을 만든 뒤 코드를 다음과 같이 수정했다.
result[id_list.indexOf(newReport[i].split(' ')[0])] += 1;
객체를 두 개 만들었던 이유가 id 순서대로 각 유저가 받은 결과 메일 수를 담아야 했기 때문인데 위와 같이 인덱스를 찾아주면 굳이 객체를 하나 더 만들지 않아도 됐다.
아래는 다른 사람의 풀이인데 Map을 사용하는 방법도 있다.
function solution(id_list, report, k) {
let reports = [...new Set(report)].map(a=>{return a.split(' ')});
let counts = new Map();
for (const bad of reports){
counts.set(bad[1],counts.get(bad[1])+1||1)
}
let good = new Map();
for(const report of reports){
if(counts.get(report[1])>=k){
good.set(report[0],good.get(report[0])+1||1)
}
}
let answer = id_list.map(a=>good.get(a)||0)
return answer;
}
익숙하지 않다 보니 전혀 생각하지 못했는데 나중에 다시 풀 때 Map으로 풀면 좋을 것 같다.
숫자 문자열과 영단어
https://github.com/algo-malgo/jungo-malgo/pull/102
공부한 개념
- Number.isNaN("abc"); // false
주어진 값의 유형이 Number이고 값이 NaN이면 true, 아니면 false이므로 문자열이 주어지면 false가 반환된다.
참고 레퍼런스
후기
처음에 객체로 숫자와 숫자 영단어를 연결해줬는데 그냥 배열로 만들고 인덱스로 접근해줘도 된다.
다른 사람의 풀이에서 split과 join을 활용한 아주 기발한 풀이를 봤다.
function solution(s) {
let numbers = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"];
var answer = s;
for(let i=0; i< numbers.length; i++) {
let arr = answer.split(numbers[i]);
answer = arr.join(i);
}
return Number(answer);
}
로또의 최고 순위와 최저 순위
https://github.com/algo-malgo/jungo-malgo/pull/47
후기
다른 사람 풀이에서 rank 배열 센스가 정말 좋았던 코드를 봤다.
function solution(lottos, win_nums) {
const rank = [6, 6, 5, 4, 3, 2, 1];
let minCount = lottos.filter(v => win_nums.includes(v)).length;
let zeroCount = lottos.filter(v => !v).length;
const maxCount = minCount + zeroCount;
return [rank[maxCount], rank[minCount]];
}
나 같은 경우는 리턴문이 좀 복잡한데 이 방법을 적용하면 훨씬 깔끔해질 것 같다..
기발하다..
신규 아이디 추천 (정규표현식) 📌
https://github.com/algo-malgo/jungo-malgo/pull/106
공부한 개념
- 정규표현식
참고 레퍼런스
- [자바스크립트] 정규표현식(Regular Expression) 기초/기본 쉽고 상세한 사용 방법 정리(샘플 예제 코드)
- [JS] 📚 정규표현식(RegExp) - 이해하기 쉽게 정리 + 응용 예제
- [regex] 정규식 빈 문자열 또는 이메일
후기
정규식을 사용하지 않고 풀어보려고 했는데 문자가 알파벳인지 아닌지 판별하는 부분에서 막혀서 그냥 정규식을 사용했다. 그러다 다른 사람 풀이를 보고 'abcdefghijklmnopqrstuvwxyz'.indexOf('a') 이런식으로 판별하는 방법이 있다는 것을 알았다.
내가 사용한 정규표현식과 다른 사람이 사용한 정규표현식을 비교해보겠다.
[조건] new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거
나: /[a-z0-9\-\_\.]/g
다른 사람: /[^\w\d-_.]/g
나는 match를 이용해서 정규표현식에 매칭되는 항목들만 배열로 반환한 뒤 join('')을 사용하여 문자열로 만들었다.
다른 사람은 replace를 사용했고, [^문자]를 사용하여 괄호 안의 문자를 제외한 것들을 공백으로 바꿔줬다.
또 다른 점은 나는 소문자와 숫자를 a-z0-9로 나타냈는데 \w\d로 나타낼 수 있는 것을 알았다.
그리고 특수문자 앞에 이스케이프 문자()를 붙여줘야 한다고 생각했는데 안 붙여도 잘 돌아가는 것 같다..
그리고 new_id 배열의 길이에 따라 문자열을 자르거나 채우거나 'a'를 넣는 조건은 삼항 연산자를 사용해서 비교할 필요가 없다는 것을 알았다.
길이가 16보다 클 때 15글자만큼 자르는 건 어차피 길이가 16 미만일 때 slice(0, 15)를 한다 해도 잘리지 않고, padEnd를 사용하여 문자를 채우는 것은 default값 느낌으로 생각해도 되는 것 같다.
그리고 빈 문자열과 일치하는 정규표현식은 ^$라고 한다.
padEnd를 사용하여 빈 문자열일 때 'a'를 채우는 방식도 있지만 replace(/^$/, 'a') 이렇게 작성하는 방법도 있다.
키패드 누르기
https://github.com/algo-malgo/jungo-malgo/pull/108
실패율
https://github.com/algo-malgo/jungo-malgo/pull/110
참고 레퍼런스
후기
객체의 값에 따라 정렬하는 방법이 없나?
검색해도 객체를 배열로 만들어서 정렬하는 건 있는데 객체 자체로 접근하는 방식은 없는 것 같다.
못 찾은 걸지도...
크레인 인형뽑기 게임
https://github.com/algo-malgo/jungo-malgo/pull/112
후기
기존 내 풀이는 일단 bucket에 값을 넣고 그 이전의 값과 비교를 했는데 다른 사람의 풀이를 보다가 넣는 것은 비교를 하고 나서 해도 되는 것을 깨달았다. 이 방식으로 하는 게 훨씬 효율적이고 좋은 것 같다.
[1차] 다트 게임 (정규표현식)
https://github.com/algo-malgo/jungo-malgo/pull/114
후기
정규표현식에 대해 더 잘 알았더라면 더 쉽게 풀었을 문제였다.
아래는 다른 사람의 풀이인데 살짝 틀린 부분이 있어 댓글을 보고 수정을 했다.
function solution(dartResult) {
const bonus = { 'S': 1, 'D': 2, 'T': 3 },
options = { '*': 2, '#': -1, undefined: 1 };
let darts = dartResult.match(/\d\d.?\D/g);
for (let i = 0; i < darts.length; i++) {
let split = darts[i].match(/(^\d{1,})(S|D|T)(\*|#)?/),
score = Math.pow(split[1], bonus[split[2]]) * options[split[3]];
if (split[3] === '*' && darts[i - 1]) darts[i - 1] *= options['*'];
darts[i] = score;
}
return darts.reduce((a, b) => a + b);
}
/\d\d.?\D/g을 콘솔에 찍어보면 [ '1S', '2D*', '3T' ] 이렇게 나온다.
- \d: 숫자
- \D: 숫자가 아닌 것
- .: 모든 문자열(숫자, 한글, 영어, 특수기호, 공백 모두! 단, 줄바꿈X)
- ?: 최대 한번(없음 || 한개)
음.. 사실 중간에 .?\D 이 부분은 잘 모르겠다.
.은 SDT를 의미한거고 \D는 *#을 의미한건가? 근데 중간에 ?가 왜 . 뒤에 있는지 잘 모르겠다..
내가 조금 더 이해가 잘 되는 정규표현식은 /\d\d?\w\D?/g이거인데 위랑 의미가 동일한지는 모르겠다.
숫자는 하나 필수에, 다른 숫자 하나가 더 올 수도 있고 안 올 수도 있고(10의 경우를 의미), 중간에 문자가 오고, 숫자가 아닌 애가 올 수도 있고 안 올 수도 있다는 뜻이다.
/(^\d{1,})(S|D|T)(\*|#)?/ 그룹을 묶을 수 있다는 건 처음 알았다. 이걸 콘솔에 찍어보면 아래처럼 나온다.
[ '1D', '1', 'D', undefined, index: 0, input: '1D', groups: undefined ]
[ '2S', '2', 'S', undefined, index: 0, input: '2S', groups: undefined ]
[ '3T*', '3', 'T', '*', index: 0, input: '3T*', groups: undefined ]
- (): 그룹 검색 및 분류 (match 메서드에서 그룹별로 묶어줌)
'알고리즘' 카테고리의 다른 글
[백준] 2579 계단 오르기 - 파이썬 (0) | 2022.04.24 |
---|---|
[백준] 1003 피보나치 함수 - 파이썬 (0) | 2022.04.21 |
[백준] 18870 좌표 압축 - 파이썬 (0) | 2022.04.11 |
[백준] 1181 단어 정렬 - 파이썬 (0) | 2022.04.09 |
[백준] 11650 좌표 정렬하기 - 파이썬 (0) | 2022.04.07 |