Intro
์๋ก์ด ๊ณผ์ ํ ์คํธ๋ฅผ ํ์๋ค. ๊ณผ์ ํ ์คํธ๋ ์ฌ๋ฌ๋ฒ ํธ๋๊น ์ต์ํด์ง๊ณ ์ค๋ ฅ์ด ๋๋ ๊ฒ ๊ฐ๋ค. ๐
ํ์ ๊ตฌํ ๋ฌธ์ ์์ ์ด์ ๋ฒํผ ๊ตฌํํ๋ค๊ฐ ์ ๋ ์ฝ์ ๋๋ฌธ์ 30๋ถ ์ ์ ์ ์ถ์ ํด๋ฒ๋ ธ๋ค ์์ฝ ใ ํ ์ ์์๋๋
์ต์ ๊ตฌํ ๋ฌธ์ ๋ ๋ชจ๋ฌ ์ฐฝ ๋ซ๋ ๊ฑฐ ํ๋ ํ์๋ค. ๋ค ๊ตฌํํ๊ธฐ์๋ ์๊ฐ์ด ๋งค์ฐ ๋งค์ฐ ๋ถ์กฑํ๋ค.
์์ง ์ค๋ ฅ์ด ๋ง์ด ๋ถ์กฑํ๊ฐ๋ณด๋น...
๊ทธ๋ฆฌ๊ณ ํ๋ ๋จ์ ์๊ณ ๋ฆฌ์ฆ ๋ฌธ์ ๋ ํ์๋ฐ. ๐
์ค๋ ํ์ตํ ๋ด์ฉ
: ๊ณผ์ ํ ์คํธ (๊ณ ์์ด ์ฌ์ง์ฒฉ ๋ง๋ค๊ธฐ), ์ฝ๋ฉํ ์คํธ
๊ณผ์ ํ ์คํธ - ๊ณ ์์ด ์ฌ์ง์ฒฉ ๋ง๋ค๊ธฐ
๋ฌธ์
๋น์ ์ ๊ณ ์์ด๋ค์ ๋ชจ์๊ณ ์๋ ์ด๋ ์ง์ฌ์๊ฒ ์์ ์ ๊ณ ์์ด ์ฌ์ง์ ๊ด๋ฆฌํด๋ฌ๋ผ๋ ์๋ขฐ๋ฅผ ๋ฐ์์ต๋๋ค.
์๋ขฐ์ธ์ ๋น์ ์ด ๋ฏฟ์๋งํ ์ฌ๋์ธ์ง ํ ์คํธํ๊ธฐ ์ํด, ์ฝ๊ฐ์ ์ฌ์ง์ ๋น์ ์๊ฒ ๋ณด๋์ผ๋ฉฐ ์ด ์ฌ์ง๋ค์ ์น์์ ๋ณผ ์ ์๋๋ก ํด๋ฌ๋ผ๊ณ ํฉ๋๋ค.
์ด ์ฌ์ง์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ๊น ๊ณ ๋ฏผ ์ค์ด๋ ๋, ๋น์ ์ ์ ์นํ ์น๊ตฌ Back-end ๊ฐ๋ฐ์๊ฐ ๋น์ ์ ๋๊ธฐ ์ํด ์๋ขฐ์ธ์ด ๋ณด๋ธ ์ฌ์ง๋ค์ API ํํ๋ก ๋ง๋ค์ด์ฃผ์์ต๋๋ค.
์ด API๋ฅผ ์ด์ฉํด, ์๋ขฐ์ธ์ ๋ง์กฑ์ํฌ ์ ์๋ ๊ณ ์์ด ์ฌ์ง์ฒฉ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค์ด๋ด ์๋ค!
๊ณ ์์ด ํด๋๋ฅผ ๊ด๋ฆฌํ๋ ํ์ด์ง๋ฅผ ๋ง๋๋ ๋ฌธ์ ์๋ค.
ํด๋๋ฅผ ๋๋ฅด๋ฉด ํด๋น ํด๋๋ก ์ด๋ํ๊ณ , ํ์ผ์ ๋๋ฅด๋ฉด ์ฌ์ง์ด ๋จ๊ฒ ๊ตฌํํ๊ณ root๊ฐ ์๋ ๋ ธ๋์๋ ์ด์ ๋ฒํผ์ด ๋จ๊ณ ์ด์ ๋ฒํผ์ ํด๋ฆญํ์ ์ ์์ ๋ ธ๋๋ก ์ด๋ํ๋ ๊ฑธ ๊ตฌํํ๋ ๋ฌธ์ ์๋ค.
๋จผ์ , ES6 ๋ชจ๋ํ๋ถํฐ ์งํํ๋ค.
main์์ div[class=App] ์์๋ฅผ ๋ถ๋ฌ์ App ํด๋์ค์ ์ ๋ฌํด์ฃผ๊ณ App ํด๋์ค์ Breadcrumb, Modal, Nodes ์ปดํฌ๋ํธ๋ค์ ํธ์ถํ๋ค. ์ปดํฌ๋ํธ ์ข ๋ฅ๋ก๋ ์๋จ์ ํ์ฌ ๊ฒฝ๋ก๋ฅผ ํ์ํด์ฃผ๋ Breadcrumb ์ปดํฌ๋ํธ์ ํด๋ ๋ด์ ํ์ผ, ํด๋ ๋ฆฌ์คํธ๋ฅผ ๋ณด์ฌ์ฃผ๋ Nodes ์ปดํฌ๋ํธ, ๊ทธ๋ฆฌ๊ณ ํ์ผ์ ๋๋ ์ ๋ ๋ชจ๋ฌ์ฐฝ์ ๋์ฐ๋ Modal ์ปดํฌ๋ํธ๋ก ๋๋์๋ค.
- Breadcrumb.js
class Breadcrumb {
filePath = ['root']
constructor({ $target }) {
const $breadcrumb = document.createElement('nav')
this.$breadcrumb = $breadcrumb
this.$breadcrumb.className = 'Breadcrumb'
$target.appendChild(this.$breadcrumb)
this.render()
}
nextRoute(name) {
const filePath = [ ...this.filePath ]
filePath.push(name)
this.setState(filePath)
}
prevRoute() {
const filePath = [ ...this.filePath ]
filePath.pop()
this.setState(filePath)
return filePath[filePath.length-1]
}
setState(newData) {
this.filePath = newData
this.render()
}
render() {
this.$breadcrumb.innerHTML = this.filePath.map(nav => `
<div>${nav}</div>
`).join('')
}
}
export default Breadcrumb
๋ฐฐ์ด์ ์ด๋ ๊ฒฝ๋ก๋ฅผ ๋ฃ์ด์ฃผ๊ณ map์ ๋๋ฉฐ ์์์ ์ถ๊ฐํ๋ค.
ํด๋๋ฅผ ๋๋ฅผ ๋๋ง๋ค nextRoute๋ก ํด๋ ์ด๋ฆ์ ์ถ๊ฐํ๊ณ ์ด์ ๋ฒํผ์ ๋๋ฅด๋ฉด prevRoute ํจ์๊ฐ ์คํ๋๋๋ก ํ๋ค.
- Nodes.js
const PREV_IMG_SRC = './assets/prev.png'
const TYPES = {
DIRECTORY: 'directory',
FILE: 'file'
}
class Nodes {
data = {
isRoot: true,
items: []
}
constructor({ $target, onChangeNode, onPrevPage, onShowImg }) {
const $nodes = document.createElement('div')
this.$nodes = $nodes
this.$nodes.className = 'Nodes'
$target.appendChild(this.$nodes)
this.onChangeNode = onChangeNode
this.onPrevPage = onPrevPage
this.onShowImg = onShowImg
this.render()
}
renderPrevImg() {
const $prevNode = document.createElement('div')
$prevNode.className = 'Node'
$prevNode.dataset.type = 'PREV_BTN'
const $prevImg = document.createElement('img')
$prevImg.src = PREV_IMG_SRC
$prevNode.appendChild($prevImg)
this.$nodes.appendChild($prevNode)
}
setState(newData) {
this.data = { ...this.data, ...newData }
this.render()
}
render() {
this.$nodes.innerHTML = ''
if(this.data.items?.length) {
if(!this.data.isRoot) this.renderPrevImg()
this.$nodes.innerHTML += this.data.items.map(({ id, name, type, filePath, parent }) => `
<div class="Node" data-id=${id} data-type=${type} data-name=${name} data-path=${filePath}>
<img src="./assets/${TYPES[type]}.png">
<div>${name}</div>
</div>
`).join('')
}
this.$nodes.querySelectorAll('.Node').forEach(item => {
item.addEventListener('click', e => {
const { id, name, type, path } = e.currentTarget.dataset
if(type === 'DIRECTORY') {
this.onChangeNode(id, name)
} else if(type === 'FILE') {
this.onShowImg(path)
} else if(type === 'PREV_BTN') {
this.onPrevPage()
}
})
})
}
}
export default Nodes
์ด์ ๋ฒํผ ํด๋ฆญ ์ ์ด์ ๋ฃจํธ๋ก ๋์๊ฐ๋ ๋ถ๋ถ์ ์ค๋ฅ๊ฐ ๋์ ์๊ฐ์ ํด๊ฒฐ ๋ชปํ๊ณ ์ ์ถํ๋ค.
๋ ธ๋์ ํ์ ์ ๋ฐ๋ผ DIRECTORY์ธ์ง FILE์ธ์ง ๊ตฌ๋ถํด์ DIRECTORY๋ฉด ๋ ธ๋๋ฅผ ์ด๋ํ๊ณ FILE์ด๋ฉด ๋ชจ๋ฌ์ฐฝ์ด ์คํ๋๊ฒ ๊ตฌํํ๋ค.
- Modal.js
const IMG_API = 'https://cat-photos-dev-serverlessdeploymentbucket-fdpz0swy5qxq.s3.ap-northeast-2.amazonaws.com/public'
class Modal {
data = {
isVisible: false,
path: ''
}
constructor({ $target }) {
const $modal = document.createElement('div')
$modal.className = 'Modal ImageViewer'
this.$modal = $modal
this.$modal.style.display = 'none'
$target.appendChild(this.$modal)
}
hideModal() {
this.$modal.style.display = 'none'
this.$modal.innerHTML = ``
this.setState({
isVisible: false,
path: ''
})
}
setState(newData) {
this.data = newData
this.render()
}
render() {
if(this.data.isVisible) {
this.$modal.style.display = 'block'
this.$modal.innerHTML = `
<div class="content">
<img src="${IMG_API}${this.data.path}">
</div>
`
document.addEventListener('keydown', e => {
if(e.key === 'Escape') this.hideModal()
})
document.addEventListener('click', e => {
if(e.target.className === 'Modal ImageViewer') this.hideModal()
})
} else {
this.$modal.innerHTML = ``
}
}
}
export default Modal
๋ชจ๋ฌ์ฐฝ ๋ง๋๋ ๊ฑด ์ด์ ๊ณผ์ ์์ ๋ง์ด ๊ตฌํ์ ํด๋ณด์์ ์์ํ๋ค.
display: 'none'์ผ๋ก ๋ชจ๋ฌ์ฐฝ์ ์จ๊ธฐ๊ฑฐ๋ ๋ณด์ฌ์ฃผ๊ฒ๋ ๊ตฌํํ๋ค.
์ฝ๋ฉํ ์คํธ ๋ฌธ์
- Lv2) ๋ํ์ค ๊ฒ์
๋ฌธ์ ์ค๋ช
์คํธ๋ ์์ฆ ๋ํ์ค ๊ฒ์์ ํน ๋น ์ ธ ์์ต๋๋ค. ๋ํ์ค ๊ฒ์์ ์คํธ๊ฐ ๋ณด์ ํ ๋ณ์ฌ n๋ช ์ผ๋ก ์ฐ์๋๋ ์ ์ ๊ณต๊ฒฉ์ ์์๋๋ก ๋ง๋ ๊ฒ์์ ๋๋ค. ๋ํ์ค ๊ฒ์์ ๋ค์๊ณผ ๊ฐ์ ๊ท์น์ผ๋ก ์งํ๋ฉ๋๋ค.
โช๏ธ ์คํธ๋ ์ฒ์์ ๋ณ์ฌ n๋ช ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
โช๏ธ ๋งค ๋ผ์ด๋๋ง๋ค enemy[i]๋ง๋ฆฌ์ ์ ์ด ๋ฑ์ฅํฉ๋๋ค.
โช๏ธ ๋จ์ ๋ณ์ฌ ์ค enemy[i]๋ช ๋งํผ ์๋ชจํ์ฌ enemy[i]๋ง๋ฆฌ์ ์ ์ ๋ง์ ์ ์์ต๋๋ค.
(โซ๏ธ ์๋ฅผ ๋ค์ด ๋จ์ ๋ณ์ฌ๊ฐ 7๋ช ์ด๊ณ , ์ ์ ์๊ฐ 2๋ง๋ฆฌ์ธ ๊ฒฝ์ฐ, ํ์ฌ ๋ผ์ด๋๋ฅผ ๋ง์ผ๋ฉด 7 - 2 = 5๋ช ์ ๋ณ์ฌ๊ฐ ๋จ์ต๋๋ค.
โซ๏ธ ๋จ์ ๋ณ์ฌ์ ์๋ณด๋ค ํ์ฌ ๋ผ์ด๋์ ์ ์ ์๊ฐ ๋ ๋ง์ผ๋ฉด ๊ฒ์์ด ์ข ๋ฃ๋ฉ๋๋ค.)
โช๏ธ ๊ฒ์์๋ ๋ฌด์ ๊ถ์ด๋ผ๋ ์คํฌ์ด ์์ผ๋ฉฐ, ๋ฌด์ ๊ถ์ ์ฌ์ฉํ๋ฉด ๋ณ์ฌ์ ์๋ชจ์์ด ํ ๋ผ์ด๋์ ๊ณต๊ฒฉ์ ๋ง์ ์ ์์ต๋๋ค.
โช๏ธ ๋ฌด์ ๊ถ์ ์ต๋ k๋ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์คํธ๋ ๋ฌด์ ๊ถ์ ์ ์ ํ ์๊ธฐ์ ์ฌ์ฉํ์ฌ ์ต๋ํ ๋ง์ ๋ผ์ด๋๋ฅผ ์งํํ๊ณ ์ถ์ต๋๋ค.
์คํธ๊ฐ ์ฒ์ ๊ฐ์ง๊ณ ์๋ ๋ณ์ฌ์ ์ n, ์ฌ์ฉ ๊ฐ๋ฅํ ๋ฌด์ ๊ถ์ ํ์ k, ๋งค ๋ผ์ด๋๋ง๋ค ๊ณต๊ฒฉํด์ค๋ ์ ์ ์๊ฐ ์์๋๋ก ๋ด๊ธด ์ ์ ๋ฐฐ์ด enemy๊ฐ ๋งค๊ฐ๋ณ์๋ก ์ฃผ์ด์ง๋๋ค. ์คํธ๊ฐ ๋ช ๋ผ์ด๋๊น์ง ๋ง์ ์ ์๋์ง return ํ๋๋ก solution ํจ์๋ฅผ ์์ฑํด์ฃผ์ธ์.
์ ํ์ฌํญ
โ๏ธ 1 ≤ n ≤ 1,000,000,000
โ๏ธ 1 ≤ k ≤ 500,000
โ๏ธ 1 ≤ enemy์ ๊ธธ์ด ≤ 1,000,000
โ๏ธ 1 ≤ enemy[i] ≤ 1,000,000
โ๏ธ enemy[i]์๋ i + 1 ๋ผ์ด๋์์ ๊ณต๊ฒฉํด์ค๋ ์ ์ ์๊ฐ ๋ด๊ฒจ์์ต๋๋ค.
โ๏ธ ๋ชจ๋ ๋ผ์ด๋๋ฅผ ๋ง์ ์ ์๋ ๊ฒฝ์ฐ์๋ enemy[i]์ ๊ธธ์ด๋ฅผ return ํด์ฃผ์ธ์.
์ ์ถ๋ ฅ ์
n: 7 / k: 3 / enemy: [4, 2, 4, 5, 3, 3, 1] / result: 5
n: 2 / k: 4 / enemy: [3, 3, 3, 3] / result: 4
๋ด๊ฐ ํผ ์ฝ๋
function solution(n, k, enemy) {
let answer = 0
let heap = [null]
const TOTAL_ROUND = enemy.length
if (k >= TOTAL_ROUND) return TOTAL_ROUND
if (n >= enemy.reduce((sum, num) => (sum += num), 0)) return TOTAL_ROUND
// ํ ๊ตฌํ
const swap = (a, b) => {
return ([heap[a], heap[b]] = [heap[b], heap[a]])
}
const pushHeap = (enemy) => {
heap.push(enemy)
let i = heap.length - 1
while (true) {
const parentIdx = parseInt(i / 2)
const parent = heap[parentIdx]
if (parent && parent < heap[i]) {
swap(i, parentIdx)
i = parentIdx
} else break
}
}
const deleteHeap = () => {
const target = heap[1]
const lastValue = heap.pop()
if (heap.length > 1) heap[1] = lastValue
else return target
let i = 1
while (true) {
const leftIdx = 2 * i
const rightIdx = 2 * i + 1
if (!heap[leftIdx]) break
if (!heap[rightIdx]) {
if (heap[leftIdx] > heap[i]) {
swap(leftIdx, i)
i = leftIdx
} else break
} else {
if (heap[leftIdx] >= heap[rightIdx]) {
if (heap[leftIdx] > heap[i]) {
swap(leftIdx, i)
i = leftIdx
} else break
} else {
if (heap[rightIdx] > heap[i]) {
swap(rightIdx, i)
i = rightIdx
} else break
}
}
}
return target
}
for (let i = 0; i < TOTAL_ROUND; i++) {
n -= enemy[i]
pushHeap(enemy[i])
if (n < 0) {
if (k > 0) {
const deletedValue = deleteHeap()
k--
n += deletedValue
} else return (answer = i)
}
}
if (!answer) answer = TOTAL_ROUND
return answer
}
๋ํ์ค ๊ฒ์์ ์๋ ์ ํ์ด๋ณธ ์ ์ด ์์๋ ๋ฌธ์ ์๋ฐ.
์ฐ์ ์์ ํ์ผ๋ก ํ์์๋๋ฐ ๋ค์ ํ๋ผ๋๊น ๊ธฐ์ต์ด ์๋์ ๋ด๊ฐ ํผ ์ฝ๋ ์ฐธ๊ณ ํด์ ๋ค์ ํ์ด๋ดค๋ค.
์๋ฐ์คํฌ๋ฆฝํธ์๋ ์ฐ์ ์์ ํ ํจ์๊ฐ ์์ด์ ์ง์ ๊ตฌํ์ ํด์ผํด์ Lv2์ง๋ง ์กฐ๊ธ ๋ ์ด๋ ต๊ฒ ๋๊ปด์ก๋ค.
๋ด๊ฐ ๊ฐ์ง ๋ณ์ฌ n์ผ๋ก ์ ์ธ enemy๋ฅผ ๋ฌผ๋ฆฌ์น๋ค๊ฐ n์ผ๋ก ๋ฌผ๋ฆฌ์น ์ ์๋ ์๊ธฐ๊ฐ ์ค๋ฉด ๋ฌด์ ๊ถ์ธ k๊ฐ ์๋์ง ํ์ธํ๊ณ , ์ฐ์ ์์ ํ์ ์๋ ๊ฐ์ฅ ํฐ ์ (heap[1])์ k๋ก ์ฌ์ฉํ๋๋ก ๊ตฌํํด์ผ ํ๋ค.
heap[1]์ ๊ฐ์ฅ ํฐ ์๊ฐ ์ค๊ธฐ ์ํด swap๊ณผ์ ์ ๊ฑฐ์ณ์คฌ๋ค.
๋ง๋ฌด๋ฆฌ
๋ฐฉํ์ด์์ง๋ง ๋ฐ๋ฆฐ ๊ณต๋ถ๋ฅผ ๋๋ด๊ธฐ ์ํด ์นดํ๊ฐ์ ์ด์ฌํ ๊ณผ์ ํ ์คํธ๋ฅผ ํ์๋ค. ๋ฟ๋ฏํ๋ค ๐คจ
๋ค์ ์ฃผ์๋ Figma ์์ ์ธ๋ฐ ๊ทธ ์ ๊น์ง ๋จ์ JS๊ฐ์ ๋ค ๋ค์ด์ผ์ง ํ,,