4.9프로그래머스 Lv.0 #81~100
프로그래머스 Lv.0 81~100번
개요
기초 트레이닝 문제(Lv.0) 81 ~ 100번 문제 풀이 중 배울 점이 있는 풀이들에서 배운 개념들을 내 것으로 만들고자 정리해본다.
85. 공백으로 구분하기 2
공백으로 구분하기 2는 1번보다야 한 단계가 더 들어가지만 간단한 문제다. 나는 이렇게 풀었다:
javascriptfunction 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 값이 뜨는 데이터들은 포함이 되지 않기 때문이다.
javascriptfunction solution(my_string) { return my_string.split(' ').filter(v => v); }
또, 이를 활용해 이렇게 쓸 수도 있다:
javascriptreturn str.split(' ').filter(Boolean); // `v => v` 대신 Boolean 사용도 가능
85-2. trim 활용하기
trim()
은 문자열 앞뒤의 공백을 제거한다.
javascriptfunction solution(my_string) { return my_string.trim().split(/ +/); }
85-3. 정규표현식 활용하기
정규표현식은 저번에 따로 정리를 했다. 공백 문자 1회 이상 반복을 제외한 문자열 부분집합만 g
플래그로 추출(match
)하면 원하는 결과를 얻을 수 있다.
javascriptconst solution = my_string => my_string.match(/[^\s]+/g);
91. 세 개의 구분자
세 개의 구분자는 정규표현식으로 푸는게 가장 깔끔한 문제일 것으로 보였지만 아직도(..) 정규표현식이 덜 익숙해서 나는 이렇게 풀었다.
javascriptfunction 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 사이의 문자는 제외하는 방식으로 풀 수 있다.
javascriptconst solution=s=>s.match(/[^a-c]+/g)||['EMPTY']
또는, a-c 사이의 문자를 기준으로 split
할 수도 있다.
javascriptfunction 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
문 문제다. 다른 사람의 풀이들 중 문법을 공부하고 싶은게 있어 남긴다.
javascriptfunction 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
javascriptfunction solution(arr) { return arr.reduce((list, num) => [...list, ...new Array(num).fill(num)], []); }
92-2. Array.fill
javascriptconst solution=a=>a.map(v=>Array(v).fill(v)).flat()
92-3. flatMap
javascriptfunction solution(arr) { return arr.flatMap((n) => Array(n).fill(n)); }
96. 배열의 길이를 2의 거듭제곱으로 만들기
배열의 길이를 2의 거듭제곱으로 만들기는 문제에 조건이 arr
의 길이가 1000 이하라고 주어져서 그렇게 케이스가 많지는 않겠구나 싶어서 약간 억지로 풀었다. arr가 1000 이하의 길이라면, 해봤자 1024까지의 2의 거듭제곱들만 모아둔 비교용 배열을 만들고 이 배열의 각 원소들과 비교하면서 풀 수 있기 때문이다. 난 아래와 같이 풀었다:
javascriptfunction 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.log2
와 Math.ceil
을 적용해 최종 길이를 구할 수 있다. 여기에 spread operator와 Array.fill
을 통해 0을 채울 수 있다.
javascriptfunction 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을 추가하기
javascriptconst solution = (arr) => { let num = 1; while (arr.length > num) num *= 2; while(arr.length !== num) arr.push(0); return arr; }
96-3. 비트 연산
고인물의 답인데, 희한한 풀이지만 마냥 안 쓸거라고 생각해서 넘어가기보단 따져보고 싶어서 남긴다.
javascriptconst 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을 0으로, 0을 2로)한다.
- 여기에 1을 더하면 2의 보수가 된다.
예를 들어 이런 식이다. l이 6(=2진수로 0110)이라고 하면,
bashl = 00000110 -l = 11111010 ← 2의 보수 (== -6) l & -l = 00000010
l & -l
은 결국 가장 낮은 자리수에 있는 1만 남기는데, 이 숫자가 l
과 같을시 2의 거듭제곱이 된다. 이 풀이는 이 성질을 이용한 것이다.