sungyup's.

Web_Miscellaneous / Algorithm(JS) / 4.9 프로그래머스 Lv.0 #81~100

4.9프로그래머스 Lv.0 #81~100

프로그래머스 Lv.0 81~100번

개요

기초 트레이닝 문제(Lv.0) 81 ~ 100번 문제 풀이 중 배울 점이 있는 풀이들에서 배운 개념들을 내 것으로 만들고자 정리해본다.

85. 공백으로 구분하기 2

공백으로 구분하기 2는 1번보다야 한 단계가 더 들어가지만 간단한 문제다. 나는 이렇게 풀었다:

javascript
function solution(my_string) { const result = my_string.split(" "); return result.filter(v => v !== "") }

85-1. filter(v => v)로 falsy value 걸러내기

빈 문자열, null, undefined, 0, false 같은 falsy value들은 filter(v => v)로 걸러낼 수 있다. false 값이 뜨는 데이터들은 포함이 되지 않기 때문이다.

javascript
function solution(my_string) { return my_string.split(' ').filter(v => v); }

또, 이를 활용해 이렇게 쓸 수도 있다:

javascript
return str.split(' ').filter(Boolean); // `v => v` 대신 Boolean 사용도 가능

85-2. trim 활용하기

trim()은 문자열 앞뒤의 공백을 제거한다.

javascript
function solution(my_string) { return my_string.trim().split(/ +/); }

85-3. 정규표현식 활용하기

정규표현식은 저번에 따로 정리를 했다. 공백 문자 1회 이상 반복을 제외한 문자열 부분집합만 g플래그로 추출(match)하면 원하는 결과를 얻을 수 있다.

javascript
const solution = my_string => my_string.match(/[^\s]+/g);

91. 세 개의 구분자

세 개의 구분자는 정규표현식으로 푸는게 가장 깔끔한 문제일 것으로 보였지만 아직도(..) 정규표현식이 덜 익숙해서 나는 이렇게 풀었다.

javascript
function solution(myStr) { const arr = myStr.replaceAll("a"," ").replaceAll("b", " ").replaceAll("c", " ").split(" ").filter(v => v); return arr.length === 0 ? ["EMPTY"] : arr; }

91-1. 정규표현식 풀이

정규표현식으로도 여러 방식으로 풀이가 있었다.

우선, a-c 사이의 문자는 제외하는 방식으로 풀 수 있다.

javascript
const solution=s=>s.match(/[^a-c]+/g)||['EMPTY']

또는, a-c 사이의 문자를 기준으로 split할 수도 있다.

javascript
function solution(myStr) { const list = myStr.split(/[a|b|c]/).filter(str => str); // myStr.split(/[abc]/).filter(str => str)도 가능하다! return list.length ? list : ["EMPTY"]; }

92. 배열의 원소만큼 추가하기

배열의 원소만큼 추가하기는 단순한 for문 문제다. 다른 사람의 풀이들 중 문법을 공부하고 싶은게 있어 남긴다.

javascript
function solution(arr) { const answer = []; for(const n of arr){ for(let i = 1; i <= n; i++){ answer.push(n) } } return answer; }

92-1. reduce와 Array.fill

javascript
function solution(arr) { return arr.reduce((list, num) => [...list, ...new Array(num).fill(num)], []); }

92-2. Array.fill

javascript
const solution=a=>a.map(v=>Array(v).fill(v)).flat()

92-3. flatMap

javascript
function solution(arr) { return arr.flatMap((n) => Array(n).fill(n)); }

96. 배열의 길이를 2의 거듭제곱으로 만들기

배열의 길이를 2의 거듭제곱으로 만들기는 문제에 조건이 arr의 길이가 1000 이하라고 주어져서 그렇게 케이스가 많지는 않겠구나 싶어서 약간 억지로 풀었다. arr가 1000 이하의 길이라면, 해봤자 1024까지의 2의 거듭제곱들만 모아둔 비교용 배열을 만들고 이 배열의 각 원소들과 비교하면서 풀 수 있기 때문이다. 난 아래와 같이 풀었다:

javascript
function solution(arr) { const powList = []; for(let i = 0; i <= 10; i++){ powList.push(2 ** i); } let idx = 0; while(true){ if(powList[idx] >= arr.length) break; idx++; } for(let j = arr.length; j < powList[idx]; j++){ arr.push(0) } return arr; }

이 풀이는 만족스럽지 않은 이유가 몇가지 있다. 우선 powList를 만들었는데, 이것이 조건에 크게 기대었을뿐더러 불필요하게 메모리도 사용한다. 이후에 볼 96-2번 풀이는 다이나믹하게 비교해야하는 2의 거듭제곱 수를 구해 불필요하게 메모리를 쓰지 않는다.

96-1. log2를 쓴 풀이

arr.length에 Math.log2Math.ceil을 적용해 최종 길이를 구할 수 있다. 여기에 spread operator와 Array.fill을 통해 0을 채울 수 있다.

javascript
function solution(arr) { const totalLength = 2 ** Math.ceil(Math.log2(arr.length)); return [...arr, ...new Array(totalLength - arr.length).fill(0)]; // 또는 return [arr.concat(Array(totalLength - arr.length).fill(0))] }

96-2. while을 활용해 num을 다이나믹하게 구하고 while로 0을 추가하기

javascript
const solution = (arr) => { let num = 1; while (arr.length > num) num *= 2; while(arr.length !== num) arr.push(0); return arr; }

96-3. 비트 연산

고인물의 답인데, 희한한 풀이지만 마냥 안 쓸거라고 생각해서 넘어가기보단 따져보고 싶어서 남긴다.

javascript
const solution = a => { let l = a.length; while ((l & -l) != l) { a.push(0); l = a.length; } return a; }

이 풀이에서 어려운 딱 한 줄은 l & -l != l일 것인데, -l은 그냥 길이를 음수화한거 아니야?라고 생각할 수 있지만, &라는 비트 연산자로 인해 상황이 모두 바뀐다.

&비트 AND 연산자로, 두 비트 모두 1일때만 1, 나머지는 0을 반환한다. 자바스크립트는 음수를 표현할 때 다음의 과정을 거친다.

  1. 정수를 이진수로 바꾼다.
  2. 비트를 반전(1을 0으로, 0을 2로)한다.
  3. 여기에 1을 더하면 2의 보수가 된다.

예를 들어 이런 식이다. l이 6(=2진수로 0110)이라고 하면,

bash
l = 00000110 -l = 11111010 ← 2의 보수 (== -6) l & -l = 00000010

l & -l은 결국 가장 낮은 자리수에 있는 1만 남기는데, 이 숫자가 l과 같을시 2의 거듭제곱이 된다. 이 풀이는 이 성질을 이용한 것이다.