백준

2941 백준 크로아티아 문자 nodejs

mynamemj 2025. 4. 29. 21:34
반응형

실버 문제 만만치 않았다..
처음엔 가볍게 생각했는데 의외로 내가 신경쓰지 못한 부분에서 문제가 발생했다.
썩 좋은 코드는 아니었지만 지금까지 익힌 기술들로 힘겹게 극복하긴 했다. 결코 좋은 코드는 아니겠지만 gpt로 더 좋은 코드도 연습 해보자.

접근방식

  1. 크로아티아 문자를 순환한다. 이 때 반드시 한 글자로 봐야하는 dz=, lj, nj 를 앞에 배치해서 먼저 순환할 수 있도록 한다.
  2. reduce로 순환한 값을 바로바로 활용할 수 있게 한다.
  3. input값을 돌면서 찾아지면 그 문자를 target에서 제외하고 따로 보관한다.
  4. 최종적으로 걸러진 크로아티아 문자의 갯수와 걸러지지 않은 문자열의 갯수를 더해 정답을 내놓는다.

문제

1-1 split으로 분류하려니 같은 문자가 존재할 때 문제발생

같은 글자가 나올거라 생각하지 않고 짜다보니 이렇게 되버렸다.

// 여러개의 크로아티아 문자가 있을 때
const targetCroatiaWord = "es"
const 예시Input = "es1es2es3es4es5es6"
예시Input.split(targetCroatiaWord)

이런 느낌의 문제였다. 찾았다고 보관한 크로아티아 문자는 1개인데 실제 인풋에는 6개에 있었던 것이다.

1-2 크로아티아 문자열을 제외한 나머지 문자열을 붙이니 새로운 크로아티아 문자열이 나올 때

// 여러개의 크로아티아 문자는 아니지만 문자열을 붙이면 크로아티아 문자가 되버림
const 크로아티아문자들 = ["es", "wa"]
const targetCroatiaWord = "wa"
const 예시Input = "ewas"

const 예시Output = [...예시Input.split(targetCroatiaWord)].join('')
console.log(예시Output) // "es"

이런 상황이 되면 원래 es를 인식하면 안되는데 인식을 해버린다. "삼성엘지전자"에서 "엘지"를 뺐다고 "삼성전자"가 원래 있던건 아니니까.

이런 문제들을 해결하기 위해 reduce의 acc.target에 들어있는 input(순환하며 크로아티아 문자를 찾을 타겟이 됨)을 문자열이 아닌 배열로 바꿔볼 생각을 했다. 어차피 문자열로 다시 붙이면 안되고, 떨어뜨려도 크로아티아 문자여야 의미가 있으니까 괜찮다고 생각했다.

풀어내기

flat 리스트 한겹 벗겨내기
크로아티아 문자가 없을때는 문제가 없지만 있을 때가 문제다. 위의 문제로 문자열을 배열로 돌 생각을 하니 이중 중첩이 되는 문제가 있었는데 다행히 이건 일할때인가 다뤄본적 있었다. flat()을 쓰면 벗겨낸다! 이건 기억을 하고있어 사용해봤다. 테스트는 안해봤는데 이중 삼중을 다 벗겨내는지 기억은 안난다. -> 쓰다가 궁금해서 바로 테스트 해보니 한 겹만 벗겨준다. 다행히 바로바로 중첩 안 시키는 코드라 문제가 없었다.

for를 꼭 써야했나?
좋은 코드가 아니라고 생각하는 이유 중 가장 큰건 for 반복문 사용 부분이라 생각한다. split 없이 searchtarget에 남아 있지 않을 때 까지 써야겠다 생각할때 while도 생각하다가 while보단 나을거라 생각하며 쓴건데 막상 쓰다보니 search에 안쓰고 push해서 사용한 크로아티아 문자 넣는 것에만 썼다. 결국 split과 for, push를 써서 겨우 풀어내긴 했다.

split으로 타겟 문자에서 필요한 문자와 필요없는 문자 분리
split을 하면 return된 배열의 길이 - 1만큼 문자가 있었단 말이 된다. 이걸 이용해서 몇 개를 넣을지 알고 냅다 for문 돌려버렸다. 남은 문자열은 flat으로 평탄화 작업 후 acc.target에 넣고 다음 순환때 사용!

const fs = require('fs')

const filePath = process.platform === "linux" ? "dev/stdin" : "input.txt";

const input = fs.readFileSync(filePath).toString().trim()

const croatiaWordList = [

"dz=",

"lj",

"nj",

"c=",

"s=",

"z=",

"c-",

"d-"

]



const wordCounts = croatiaWordList.reduce((acc, croatiaWord, index) => {

const newTarget = acc.target.map((resChar) => {

const searchIndex = resChar.search(croatiaWord)

if (searchIndex == -1) {

return resChar

} else {

const exceptWordSplitList = resChar.split(croatiaWord)

if (exceptWordSplitList.length > 2) {

for (let i=0;i<(exceptWordSplitList.length - 1);i++) {

acc.croatiaWordBox.push(croatiaWord)

}

return [...exceptWordSplitList]

} else {

const front = resChar.slice(0, searchIndex)

const back = resChar.slice(searchIndex + croatiaWord.length)

acc.croatiaWordBox.push(croatiaWord)

return [front, back]

}

}

})

acc.target = newTarget.flat().filter(value => !!value)

return acc

}, {croatiaWordBox:[], target: [input]})



console.log(wordCounts.croatiaWordBox.length + wordCounts.target.join("").length)
반응형