백준 1157번을 풀어보았다.
아주 다양한 풀이가 존재하는 문제이지만 세 가지 풀이만 정리해보았다.
나중에 복습할 때 다른 풀이들까지 공부해보기로 하고..
1. 배열을 이용한 풀이
let words = require('fs').readFileSync('/dev/stdin').toString().trim().toUpperCase()
let alphabet = Array(26).fill(0)
for (const word of words) {
const index = word.charCodeAt()
alphabet[index-65]++
}
const max_count = Math.max(...alphabet)
const max_alphabet = alphabet.filter((value) => value === max_count)
if (max_alphabet.length > 1) { console.log('?') }
else {
const index = alphabet.indexOf(...max_alphabet)
console.log(String.fromCharCode(index+65))
}
2. 객체를 이용한 풀이
let words = require('fs').readFileSync('/dev/stdin').toString().trim().toUpperCase()
let alphabet = {}
for (const word of words) {
alphabet[`${word}`] ? alphabet[`${word}`]++ : alphabet[`${word}`] = 1
}
const max_value = Math.max(...Object.values(alphabet))
const max_key = Object.keys(alphabet).filter((key) => alphabet[key] === max_value)
max_key.length > 1 ? console.log('?') : console.log(...max_key)
내가 작성한 코드가 위 코드인데, 몇몇 헷갈리는 부분이 있었다.
• 객체의 속성 값에 접근하기
위에선 alphabet[`${word}`]로 객체의 속성 값에 접근하고 있지만,
처음에는 alphabet.word, alphabet.`${word}`와 같이 접근하려 했고 왜인지 안 되더라.
먼저 객체의 속성 값에 접근하는 방법으로는 점 표기법과 대괄호 표기법이 있다.
점 표기법은 점 뒤에 나온 문자 그대로를 키로 찾고 템플릿 리터럴을 허용하지 않는 반면 대괄호 표기법은 템플릿 리터럴을 허용한다.
즉, alphabet.word는 word를 키로 찾고 alphabet[word]는 word 변수의 값을 키로 찾는다.
또한 alphabet.`${word}`는 Syntax Error를 발생하지만 alphabet[`${word}`]는 템플릿 리터럴 값을 키로 찾는다.
참고) 객체 ① 객체 기본
• 객체의 다양한 메소드
객체를 자주 다루지는 않다보니 객체 관련 메소드를 잘 사용하지 못 하더라.
자주 사용되는 객체 관련 메소드를 정리해봤다.
Object.keys() | 객체의 모든 키를 배열로 반환한다. |
Object.values() | 객체의 모든 값을 배열로 반환한다. |
Object.entries() | 객체의 키-값 쌍을 배열로 반환한다. |
Object.fromEntries() | 키-값 쌍 배열을 객체로 반환한다. |
Object.assign() | 하나 이상의 객체를 병합하고 복사한다. |
Object.freeze() | 객체를 동결하여 값을 변경할 수 없도록 한다. |
Object.seal() | 객체의 속성 추가/삭제는 금지하고 기존 속성 수정은 허락한다. |
Object.hasOwnProperty() | 객체가 특정 키를 가지고 있는지 확인한다. |
Object.is() | 두 값을 엄격하게 비교한다. |
Object.defineProperty() | 객체의 특정 속성을 정의/수정한다. |
> const obj = { a: 1, b: 2, c: 3 }
undefined
> Object.keys(obj)
(3) ['a', 'b', 'c']
> Object.values(obj)
(3) [1, 2, 3]
> Object.entries(obj)
(3) [Array(2), Array(2), Array(2)]0: (2) ['a', 1]1: (2) ['b', 2]2: (2) ['c', 3]length: 3[[Prototype]]: Array(0)
> const entries = [['a', 1], ['b', 2], ['c', 3]]
undefined
> Object.fromEntries(entries)
{a: 1, b: 2, c: 3}
> const target = { a: 1 }
undefined
> const source = { b: 2, c: 3 }
undefined
> Object.assign(target, source)
{a: 1, b: 2, c: 3}
> Object.freeze(obj)
{a: 1, b: 2, c: 3}
> obj.a = 2
2
> obj.a
1
> Object.seal(obj)
{a: 1, b: 2, c: 3}
> obj.a = 2
2
> obj.a
2
> obj.d = 4
4
> obj
{a: 2, b: 2, c: 3}
> obj.hasOwnProperty('a')
true
> obj.hasOwnProperty('d')
false
> Object.is(1, '1')
false
> Object.is(NaN, NaN)
true
> Object.is(+0, -0)
false
> NaN === NaN
false
> +0 === -0
true
3. 객체와 reduce, sort 메소드를 이용한 풀이
let words = require('fs').readFileSync('/dev/stdin').toString().trim().toUpperCase()
const alphabet = words.split('').reduce((acc, cur) => {
acc[cur] ? acc[cur]++ : acc[cur] = 1
return acc
}, {})
const sortedAlphabet = Object.entries(alphabet).sort(([, a], [, b]) => b - a)
sortedAlphabet.length !== 1 && sortedAlphabet[0][1] === sortedAlphabet[1][1] ? console.log('?') : console.log(sortedAlphabet[0][0])
각 알파벳의 개수를 구하는 과정을 reduce 메소드로,
가장 많이 사용된 알파벳을 구하는 과정을 sort 메소드로 풀이할 수도 있다.
2번 풀이를 발전시킨 풀이인데,
reduce 메소드의 acc를 0이 아니라 '', [], {} 등으로 초기화할 수도 있다는 것과
sort를 [, a], [, b]와 같이도 쓸 수 있다는 것이 새로웠다.
다만 reduce 메소드를 사용하는 과정에서 처음에 return acc을 안 썼더니 에러가 발생했는데,
그간 자주 사용하던 reduce((acc, cur) => acc += cur, 0) 과 같은 단일 표현식은 연산 결과를 자동으로 반환하지만
위와 같이 복잡한 연산이나 여러 줄의 코드에서는 반환할 값을 명시적으로 나타내주어야 한다.
💫 이 문제를 통해 배운 것
• 객체의 속성 값에 접근하는 점 표기법과 대괄호 표기법의 사용법, 객체 관련 다양한 메소드를 정확히 알아두자.
• reduce 메소드의 acc는 0, '', [], {} 등 다양한 값으로 초기화할 수 있으며 복잡한 연산의 경우 return문을 작성해주어야 한다.