sungyup's.

Web_Miscellaneous / Algorithm(JS) / 4.5 프로그래머스 Lv.0 #41~50

4.5프로그래머스 Lv.0 #41~50

프로그래머스 Lv.0 41~50번

개요

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

45. 접미사인지 확인하기

접미사인지 확인하기는 is_suffix가 my_string의 특정 인덱스에서 시작되어 끝까지 이어지는 문자열인지 확인하는 문제다. 나는 이렇게 풀었다.

javascript
function solution(my_string, is_suffix) { const array = []; for(let i = 0; i < my_string.length; i++){ array.push(my_string.slice(i)) } return +array.includes(is_suffix) }

45-1. endsWith

간단한 메소드가 있다.

javascript
const solution = (str, suff) => str.endsWith(suff) ? 1 : 0

45-2. RegExp

이번 기회에 RegExp를 정리했다. 아래 $는 문자열의 끝을 의미한다.

javascript
function solution(my_string, is_suffix) { return Number(new RegExp(`${is_suffix}$`).test(my_string)) }

47. 문자열 뒤집기

문자열 뒤집기는 일전에 40번에서 본 문자열 여러번 뒤집기의 하위 버전이다. 그때, reverse 메소드를 다른 사람들이 쓴 걸 기억하고 써보았다.

javascript
function solution(my_string, s, e) { return my_string.slice(0, s) + my_string.slice(s, e + 1).split("").reverse().join("") + my_string.slice(e + 1) }

47-1. replace 메소드

세상은 넓고 메소드는 많은 것 같다. replace라는 메소드를 통해, 원하는 부분만 깔끔하게 변경이 가능하다. Regex와도 함께 종종 쓰인다고 한다.

javascript
function solution(my_string, s, e) { let answer = ''; let str = my_string.substring(s,e+1); let newStr = str.split('').reverse().join(''); answer = my_string.replace(str, newStr); return answer; }

47-2. i--

아주 좋은 방법이라고 생각하진 않지만, 하도 for 루프 안에 i++만 써오던 습관이 되어 있어서 굳은 머리를 풀 수 있는 풀이를 하나 보고 넘어간다.

javascript
function solution(my_string, s, e) { let chars = ''; for (let i = 0; i < s; i++) chars += my_string[i]; // 앞 for (let i = e; i >= s; i--) chars += my_string[i]; // 뒤집힌 중간 for (let i = e + 1; i < my_string.length; i++) chars += my_string[i]; // 뒤 return chars; }

48. 세로 읽기

세로 읽기는 말은 세로 읽기지만 실제로는 문자열에서 일정한 간격으로 문자를 추출하는 문제다. 나는 아마 가장 직관적이라고 할만한 풀이로 풀었다.

javascript
function solution(my_string, m, c) { let answer = ''; for(let i = c - 1; i < my_string.length ; i = i + m){ answer += my_string[i] } return answer; }

48-1. filter활용

문자열을 배열로 바꾸면 보다 강력한 메소드들을 활용할 수 있다. 이 풀이는 filter를 통해 풀었다.

javascript
function solution(my_string, m, c) { return [...my_string].filter((_, i) => i % m === c - 1).join(''); }

48-2. RegExp 활용

/.{m}/g는,

  • .: 임의의 문자 1개
  • {m}: 정확히 m개
  • g: 전역 검색 즉 문자열을 m개 글자씩 끊어서 배열로 만드는 RegExp다.
javascript
const solution=(s,m,c)=>s.match(new RegExp(`.{${m}}`,'g')).map(v=>v[c-1]).join('')

49. qr코드

또다른 시키는 대로만 하면 풀리는 문제다.

javascript
function solution(q, r, code) { let answer = ''; for(let i = 0; i < code.length; i++){ if(i % q === r) answer += code[i]; } return answer; }

49-1. filter 활용

code 문자열을 배열로 바꿔서 filter로 처리하는 것도 가능하다.

javascript
function solution(q, r, code) { return [...code].filter((_, i) => i % q === r).join(''); }

49-2. map 활용

map으로 처리하는 것도 가능하다.

javascript
function solution(q, r, code) { let answer = ''; [...code].map((v, idx) => idx % q === r ? answer += v : answer) return answer; }

49-3. 또듀스(..)도 가능

우리의 강력한 reduce도 물론 가능하다.

javascript
function solution(q, r, code) { return [...code].reduce( (acc, cur, idx) => (idx % q === r ? acc + cur : acc), "" ); }

50. 문자 개수 세기

문자 개수 세기는 개인적으로 어떻게 a-z, A-Z를 쉽고 가독성 좋게 array로 만들 수 있는지에 대한 문제라고 생각했다.

이 부분에 대해 막연하게나마 Array.from이 떠올라 인터넷에 찾아보니, 아래와 같이 Array.from({length: 26}, (_, i) => String.fromCharCode('a'.charCodeAt(0) + i))라는 방법이 나왔다. 따라서 이 방법을 사용했다.

Array.from(arrayLike, mapFn?, thisArg?)는 유사배열, 또는 이터러블 객체를 배열(Array)로 변환한다. 위에서 {length: N}은 유사배열로 기능한다.

charCodeAt(index)는 문자열에서 주어진 인덱스 문자의 UTF-16 코드(유니코드 값)을 반환한다. A는 65, a는 97이다. 유니코드 관련 보다 자세한 내용은 여기에 전에 정리한 적이 있다.
javascript
function solution(my_string) { const alphabetLowercase = Array.from({ length: 26 }, (_, i) => String.fromCharCode('a'.charCodeAt(0) + i)); const alphabetUppercase = Array.from({ length: 26 }, (_, i) => String.fromCharCode('A'.charCodeAt(0) + i)); const lookup = alphabetUppercase.concat(alphabetLowercase); const answer = Array.from({length: 52}, ()=> 0) for(let i of my_string){ let idx = lookup.indexOf(i); answer[idx] = (answer[idx] || 0) + 1; } return answer; }

50-1. 노가다가 더 나을때도 있다.

설마했는데 진짜로 A-Z, a-z를 다 적은 사람이 있었다. 그런데 이렇게 적은걸 보니 더 가독성이 좋아보이기도 했다. 물론, 확실한 검증을 위해선 처음부터 끝까지 다 알파벳 송을 부르면서 세봐야하겠지만 무엇이 의도인지 정확하게 알 수 있다.

javascript
function solution(m) { const answer = []; let al = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; const a = []; a.length = 52; a.fill(0); m.split("").map((n)=>{ a[al.indexOf(n)]+=1 }) return a; }

a를 정의하고, length 속성에 값을 할당한게 흥미로웠다. 이렇게 할 경우 [empty * 52]식으로 길이는 52인데 텅 빈 배열이 생긴다. 여담으로, al이 뭔가 싶었는데 alphabet의 약자로 보인다.

50-2. reduce의 유혹

역시나 reduce는 빠지지 않는다. 참고로, 아래에서 71이 나오게 된 것은 97 - 21이다. 소문자 a를 예로 들면, c.charCodeAt()이 97이므로 71을 빼서 26번째 index에 1을 추가하고, 대문자 A는 65를 빼서 0번째 index에 1을 추가하는 것. 개인적으로 가독성에는 약간의 문제가 있다고 생각하는 코드지만, reduce를 활용한 사례여서 다시 볼 필요가 있다고 생각한다.

javascript
function solution(str) { return [...str].reduce((p, c) => (p[c.charCodeAt() - (c === c.toLowerCase() ? 71 : 65)]++, p), Array(52).fill(0)); }