4.5프로그래머스 Lv.0 #41~50
프로그래머스 Lv.0 41~50번
개요
기초 트레이닝 문제(Lv.0) 41 ~ 50번 문제 풀이 중 배울 점이 있는 풀이들에서 배운 개념들을 내 것으로 만들고자 정리해본다.
45. 접미사인지 확인하기
접미사인지 확인하기는 is_suffix가 my_string의 특정 인덱스에서 시작되어 끝까지 이어지는 문자열인지 확인하는 문제다. 나는 이렇게 풀었다.
javascriptfunction 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
간단한 메소드가 있다.
javascriptconst solution = (str, suff) => str.endsWith(suff) ? 1 : 0
45-2. RegExp
이번 기회에 RegExp를 정리했다. 아래 $
는 문자열의 끝을 의미한다.
javascriptfunction solution(my_string, is_suffix) { return Number(new RegExp(`${is_suffix}$`).test(my_string)) }
47. 문자열 뒤집기
문자열 뒤집기는 일전에 40번에서 본 문자열 여러번 뒤집기의 하위 버전이다. 그때, reverse
메소드를 다른 사람들이 쓴 걸 기억하고 써보았다.
javascriptfunction 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와도 함께 종종 쓰인다고 한다.
javascriptfunction 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++
만 써오던 습관이 되어 있어서 굳은 머리를 풀 수 있는 풀이를 하나 보고 넘어간다.
javascriptfunction 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. 세로 읽기
세로 읽기는 말은 세로 읽기지만 실제로는 문자열에서 일정한 간격으로 문자를 추출하는 문제다. 나는 아마 가장 직관적이라고 할만한 풀이로 풀었다.
javascriptfunction 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
를 통해 풀었다.
javascriptfunction 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다.
javascriptconst solution=(s,m,c)=>s.match(new RegExp(`.{${m}}`,'g')).map(v=>v[c-1]).join('')
49. qr코드
또다른 시키는 대로만 하면 풀리는 문제다.
javascriptfunction 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
로 처리하는 것도 가능하다.
javascriptfunction solution(q, r, code) { return [...code].filter((_, i) => i % q === r).join(''); }
49-2. map 활용
map
으로 처리하는 것도 가능하다.
javascriptfunction solution(q, r, code) { let answer = ''; [...code].map((v, idx) => idx % q === r ? answer += v : answer) return answer; }
49-3. 또듀스(..)도 가능
우리의 강력한 reduce
도 물론 가능하다.
javascriptfunction 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이다. 유니코드 관련 보다 자세한 내용은 여기에 전에 정리한 적이 있다.javascriptfunction 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를 다 적은 사람이 있었다. 그런데 이렇게 적은걸 보니 더 가독성이 좋아보이기도 했다. 물론, 확실한 검증을 위해선 처음부터 끝까지 다 알파벳 송을 부르면서 세봐야하겠지만 무엇이 의도인지 정확하게 알 수 있다.
javascriptfunction 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
를 활용한 사례여서 다시 볼 필요가 있다고 생각한다.
javascriptfunction solution(str) { return [...str].reduce((p, c) => (p[c.charCodeAt() - (c === c.toLowerCase() ? 71 : 65)]++, p), Array(52).fill(0)); }