Spring Boot ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋˜์ค‘์— Security ๊ด€๋ จ ๊ณต๋ถ€๋ฅผ ํ•˜๋ฉด์„œ csrf ์„ค์ •์„ ํ•ด์•ผํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋ณด๊ณ , csrf๊ฐ€ ๊ถ๊ธˆํ•ด์ ธ์„œ ์•Œ์•„๋ณด๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋น„์Šทํ•œ ๊ฐœ๋…์ธ XSS์— ๋Œ€ํ•ด์„œ๋„ ์‚ด์ง ๋ง›๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


1. CSRF(Cross-Site Request Forgery: ํฌ๋กœ์Šค ์‚ฌ์ดํŠธ ์š”์ฒญ ์œ„์กฐ)

CSRF๋Š” Cross-Site Request Forgery์˜ ์•ฝ์ž๋กœ, ๋ฒˆ์—ญํ•˜๋ฉด ์‚ฌ์ดํŠธ ๊ฐ„ ์š”์ฒญ ์œ„์กฐ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

CSRF๋Š” ์›น์‚ฌ์ดํŠธ์˜ ์ทจ์•ฝ์ ์„ ์ด์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž์˜ ์˜์ง€์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ๊ณต๊ฒฉ์ž๊ฐ€ ์˜๋„ํ•œ ํ–‰์œ„(๋ฐ์ดํ„ฐ ์‚ญ์ œ, ์ˆ˜์ •, ๋“ฑ๋ก ๋“ฑ)์„ ํŠน์ • ์›น์‚ฌ์ดํŠธ์— ์š”์ฒญํ•˜๊ฒŒ ํ•˜๋Š” ๊ณต๊ฒฉ์ž…๋‹ˆ๋‹ค.

์ƒ์„ฑ๋œ ์š”์ฒญ์ด ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์˜ ๋™์˜๋ฅผ ๋ฐ›์•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์—†๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ CSRF ์ทจ์•ฝ์ ์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆํ•œ ์„ธ์…˜์—์„œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ •์ƒ์ ์ธ ์š”์ฒญ๊ณผ ๋น„์ •์ƒ์ ์ธ ์š”์ฒญ์„ ๊ตฌ๋ถ„ํ•˜์ง€ ๋ชปํ•˜๋Š” ์ ์„ ์•…์šฉํ•˜๋Š” ๊ณต๊ฒฉ ๋ฐฉ์‹

๊ณต๊ฒฉ์ž์˜ ์š”์ฒญ์ด ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์ธ ๊ฒƒ์ฒ˜๋Ÿผ ์†์—ฌ์„œ ๊ณต๊ฒฉํ•˜๋Š” ๋ฐฉ์‹์ด๊ธฐ์— 'ํฌ๋กœ์Šค ์‚ฌ์ดํŠธ ์š”์ฒญ ์œ„์กฐ'๋ผ๋Š” ๋ช…์นญ์ด ๋ถ™์—ˆ์Šต๋‹ˆ๋‹ค.

 

CSRF ๊ณต๊ฒฉ ์‹œ๋‚˜๋ฆฌ์˜ค

CSRF ๊ณต๊ฒฉ์˜ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

1๏ธโƒฃ ์‚ฌ์šฉ์ž๊ฐ€ ์›น์‚ฌ์ดํŠธ์— ์ ‘์†ํ•ด์„œ ๋กœ๊ทธ์ธํ•˜์—ฌ ๊ถŒํ•œ์„ ์ธ์ฆํ•˜๊ณ  ์„ธ์…˜์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ ๊ณต๊ฒฉ์ž๋Š” ์•…์„ฑ ์›น์‚ฌ์ดํŠธ๋กœ ์‚ฌ์šฉ์ž๋ฅผ ์œ ์ธํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ด ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด ๊ณต๊ฒฉ์ž์˜ ์•…์„ฑ ์›น์‚ฌ์ดํŠธ๋กœ ์ด๋™ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ ์‚ฌ์šฉ์ž๊ฐ€ ์•…์„ฑ ์›น์‚ฌ์ดํŠธ์— ๋ฐฉ๋ฌธํ•˜๋ฉด, ํ•ด๋‹น ํŽ˜์ด์ง€์— ํฌํ•จ๋œ ์Šคํฌ๋ฆฝํŠธ๋‚˜ ์ด๋ฏธ์ง€ ํƒœ๊ทธ๊ฐ€ ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•œ ์›น์‚ฌ์ดํŠธ์— ์š”์ฒญ์„ ์ž๋™์œผ๋กœ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

  • ์˜ˆ๋ฅผ ๋“ค์–ด, ์€ํ–‰ ์‚ฌ์ดํŠธ๋ผ๊ณ  ํ•  ๋•Œ, ๊ณต๊ฒฉ์ž๊ฐ€ ์ด๋ฏธ์ง€ ํƒœ๊ทธ๋กœ ๋ˆ์„ ์†ก๊ธˆํ•˜๋Š” ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค๊ณ  ํ•ด๋ด…์‹œ๋‹ค.
< img  src = "http://bank.com/transfer?amount=9999&toAccount=000011112222" />

ํ•ด๋‹น ์ด๋ฏธ์ง€ ํƒœ๊ทธ๋ฅผ ์•…์„ฑ ์›น์‚ฌ์ดํŠธ์— ์‹ฌ์–ด๋‘๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘์†์‹œ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ด ์ด๋ฏธ์ง€๋ฅผ ๋กœ๋“œํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํ•ด๋‹น ์€ํ–‰ ์›น์‚ฌ์ดํŠธ๋กœ ๋ˆ ์†ก๊ธˆ ์š”์ฒญ์ด ๋ณด๋‚ด์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

4๏ธโƒฃ ์‚ฌ์šฉ์ž๋Š” ์›น์‚ฌ์ดํŠธ์— ์ด๋ฏธ ์ธ์ฆ์„ ํ•œ ์ƒํƒœ์ด๋ฏ€๋กœ, ํ•ด๋‹น ์š”์ฒญ์€ ์„œ๋ฒ„์—์„œ ์‚ฌ์šฉ์ž์˜ ์ •์ƒ์ ์ธ ์š”์ฒญ์œผ๋กœ ํŒ๋‹จํ•˜๊ณ  ์ธ์ฆ๋œ ์š”์ฒญ์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

5๏ธโƒฃ ์„œ๋ฒ„๋Š” ์ด ์•…์˜์ ์ธ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ์˜๋„ํ•˜์ง€ ์•Š์€, ๊ณต๊ฒฉ์ž๊ฐ€ ์˜๋„ํ•œ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

  • ์˜ˆ์‹œ๋กœ ๋ณด๋ฉด, ์‚ฌ์šฉ์ž๋Š” ์˜๋„ํ•˜์ง€ ์•Š์€ ์š”์ฒญ์ธ, '000011112222' ๊ณ„์ขŒ๋กœ 9,999์›์„ ์†ก๊ธˆํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

CSRF ๊ณต๊ฒฉ ์‚ฌ๋ก€

CSRF๋Š” ๋ฐ์ดํ„ฐ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š” ์š”์ฒญ์„ ๋Œ€์ƒ์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌํ•œ ์š”์ฒญ์œผ๋กœ๋Š” ์ œํ’ˆ์„ ๊ตฌ์ž…ํ•˜๊ฑฐ๋‚˜ ๊ณ„์ • ์„ค์ •, ๊ธฐ๋ก์„ ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋“ฑ์˜ ์š”์ฒญ์ด ์žˆ์Šต๋‹ˆ๋‹ค. 

 

์‹ค์ œ๋กœ 2008๋…„์— ์˜ฅ์…˜์ด ์ค‘๊ตญ์ธ ํ•ด์ปค์—๊ฒŒ CSRF ๊ณต๊ฒฉ ๋ฐฉ์‹์œผ๋กœ ํšŒ์›์ •๋ณด๊ฐ€ ์œ ์ถœ๋œ ์‚ฌ๋ก€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•ด์ปค๋Š” ๊ถŒํ•œ์„ ๊ฐ€์ง€๊ณ  ํšŒ์‚ฌ ๋‚ด ์ž‘์—…์„ ํ•˜๋˜ ์˜ฅ์…˜ ๊ด€๋ฆฌ์ž์—๊ฒŒ ๋ฉ”์ผ์„ ๋ณด๋ƒˆ๊ณ , ๊ด€๋ฆฌ์ž๋Š” ์ด ๋ฉ”์ผ์„ ์กฐํšŒํ–ˆ์Šต๋‹ˆ๋‹ค. 

ํ•ด์ปค๊ฐ€ ๋ณด๋‚ธ ๋ฉ”์ผ์—๋Š” ํƒœ๊ทธ๊ฐ€ ๋“ค์–ด๊ฐ„ ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. 

< img  src = "http://auction.com/changeUserAccount?id=admin&password=admin"  ๋„ˆ๋น„ = "0"  ๋†’์ด = "0" >

(์ด๋ฏธ์ง€ ํฌ๊ธฐ๊ฐ€ 0์ด๋ฏ€๋กœ ๊ด€๋ฆฌ์ž๋Š” ์ด ์กด์žฌ๋ฅผ ์•Œ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.)

๊ด€๋ฆฌ์ž๊ฐ€ ๋ฉ”์ผ์„ ์กฐํšŒํ•˜๋Š” ์ˆœ๊ฐ„ ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•ด URL์ด ์—ด๋ฆฌ๊ฒŒ ๋˜๊ณ , ํ•ด์ปค๊ฐ€ ์›ํ•˜๋Š”๋Œ€๋กœ ๊ด€๋ฆฌ์ž์˜ ๊ณ„์ •์ด ํ•ด์ปค๊ฐ€ ์„ค์ •ํ•œ "admin"์œผ๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. ์ดํ›„ ํ•ด์ปค๋Š” ์ด ๊ณ„์ •์œผ๋กœ ์„œ๋ฒ„ ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€์— ์ ‘์†ํ•ด์„œ *๋ฐฑ๋„์–ด ํ”„๋กœ๊ทธ๋žจ์„ ์˜ฌ๋ ธ์Šต๋‹ˆ๋‹ค.

*๋ฐฑ๋„์–ด ํ”„๋กœ๊ทธ๋žจ: ์ •์ƒ์ ์ธ ์ ˆ์ฐจ๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ ๋„ ์ ‘๊ทผ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ํ”„๋กœ๊ทธ๋žจ

๋ฐฑ๋„์–ด ํ”„๋กœ๊ทธ๋žจ์„ ์ด์šฉํ•ด์„œ ์˜ฅ์…˜ ๋‚ด๋ถ€ ์›น ์„œ๋ฒ„์— ์ ‘์†ํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ํ•ดํ‚นํ–ˆ๊ณ , ํšŒ์› ์ •๋ณด๋ฅผ ๋นผ๋‚ด๊ฐ„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋•Œ ์œ ์ถœ๋œ ํšŒ์› ์ •๋ณด๊ฐ€ 1860๋งŒ๋ช…์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

์ด๋Ÿฌํ•œ CSRF ๊ณต๊ฒฉ์— ๋‹นํ•˜๊ฒŒ ๋˜๋ฉด ๋ง‰๋Œ€ํ•œ ํ”ผํ•ด๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ CSRF ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด CSRF ํ† ํฐ์„ ํ†ตํ•ด ํ•ด๋‹น ์š”์ฒญ์ด ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์ „์†กํ•œ ๊ฒƒ์ด ๋งž๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๊ฑฐ๋‚˜ ์žฌ์ธ์ฆ์„ ์š”๊ตฌํ•˜๋Š” ๋“ฑ์˜ ๋ฐฉ์‹์œผ๋กœ CSRF ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.


2. CSRF ๊ณต๊ฒฉ ๋ฐฉ์ง€ - Synchronizer Token Pattern

Spring์—์„œ๋Š” CSRF ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์ค‘ Synchronizer Token Pattern์„ ๊ฐ€์žฅ ์šฐ์„ธํ•˜๊ณ  ํฌ๊ด„์ ์ธ ๋ฐฉ๋ฒ•์œผ๋กœ ์†Œ๊ฐœํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Synchronizer Token Pattern์€ CSRF ๊ณต๊ฒฉ์œผ๋กœ๋ถ€ํ„ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•ด ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ๊ฐ„์— ๊ณ ์œ ํ•œ ๋ณด์•ˆ ํ† ํฐ์ธ CSRF ํ† ํฐ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

 

๐Ÿ” CSRF ํ† ํฐ

์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ์„ ํ•˜๋”๋ผ๋„ CSRF ๊ณต๊ฒฉ์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณดํ†ต JWT๋งŒ์„ ์ด์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž๋ฅผ ์ธ์ฆํ•œ๋‹คํ•˜์˜€์„๋•Œ์—๋„ ๊ณต๊ฒฉ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ CSRF ํ† ํฐ์„ ์‚ฌ์šฉํ•ด์„œ CSRF ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

 

CSRF ํ† ํฐ์ด๋ž€, ์„œ๋ฒ„์— ๋“ค์–ด์˜จ ์š”์ฒญ์ด ์‹ค์ œ ์„œ๋ฒ„์—์„œ ํ—ˆ์šฉํ•œ ์š”์ฒญ์ด ๋งž๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•œ ํ† ํฐ์ž…๋‹ˆ๋‹ค.

CSRF ํ† ํฐ์€ ์„œ๋ฒ„์—์„œ ์ƒ์„ฑํ•ด์„œ ํด๋ผ์ด์–ธํŠธ์™€ ๊ณต์œ ๋˜๋Š” ์ธ์ฆ ๊ฐ’์ž…๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๋Š” ์„œ๋ฒ„์— ์š”์ฒญ์‹œ์— ์„œ๋ฒ„์—์„œ ์ธ์ฆํ•ด์ค€ CSRF ํ† ํฐ์„ ํฌํ•จํ•ด์„œ ์š”์ฒญํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. CSRF ํ† ํฐ์ด ์—†์œผ๋ฉด ์„œ๋ฒ„๋Š” ์š”์ฒญ์„ ๊ฑฐ๋ถ€ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 

 

CSRF ํ† ํฐ์„ HTML ํผ์— ๋‹ด์•„์„œ ๋ณด๋‚ด๋Š” ๋ฐฉ์‹์ด ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

 

1๏ธโƒฃ ํด๋ผ์ด์–ธํŠธ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋ฒ„์— HTTP GET ์š”์ฒญ์„ ํ†ตํ•ด ์•ก์„ธ์Šคํ•ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ ์„œ๋ฒ„๋Š” CSRF ํ† ํฐ์„ ์ƒ์„ฑํ•˜๊ณ  HTTP ์„ธ์…˜์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ƒ์„ฑ๋œ CSRF ํ† ํฐ์€ HTML ํ˜•์‹์˜ ์ˆจ๊ฒจ์ง„ ํƒœ๊ทธ(hidden)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์™€ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ ํด๋ผ์ด์–ธํŠธ๋Š” HTML ํผ์˜ ๋ฒ„ํŠผ์„ ํ†ตํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค. CSRF ํ† ํฐ์€ HTML ํผ์˜ Hidden ํ•„๋“œ์— ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ CSRF ํ† ํฐ ๊ฐ’์ด ์š”์ฒญ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ํ•จ๊ป˜ ์ „์†ก๋ฉ๋‹ˆ๋‹ค. 

4๏ธโƒฃ ์„œ๋ฒ„๋Š” ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ง€์ •๋œ CSRF ํ† ํฐ ๊ฐ’๊ณผ HTTP POST ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ก์„ธ์Šค ํ•  ๋•Œ HTTP ์„ธ์…˜์— ์œ ์ง€๋œ CSRF ํ† ํฐ ๊ฐ’์ด ๋™์ผํ•œ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ํ† ํฐ ๊ฐ’์ด ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด ์ž˜๋ชป๋œ ์š”์ฒญ์œผ๋กœ, ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

 

๋‹ค์‹œ ์ •๋ฆฌํ•˜์ž๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€์— ์ ‘์†์‹œ ์„œ๋ฒ„์—์„œ๋Š” CSRF ํ† ํฐ์„ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉ์ž ์„ธ์…˜์ด ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ์ดํ›„ ์‚ฌ์šฉ์ž๊ฐ€ ์„œ๋ฒ„์— ์• ํ”Œ๋ง„์ด์…˜์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์ž‘์—…์„ ์š”์ฒญํ•  ๋•Œ ํŽ˜์ด์ง€์— Hidden ์œผ๋กœ ์ˆจ์–ด์žˆ๋Š” CSRF ํ† ํฐ ๊ฐ’์ด ์„œ๋ฒ„๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค. 
  • ์„œ๋ฒ„์—์„œ๋Š” ์ด CSRF ๊ฐ’์ด ์„ธ์…˜์— ์ €์žฅ๋œ ๊ฐ’๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์—ฌ ํ•ด๋‹น ์š”์ฒญ์ด ์ •์ƒ์ ์ธ ์š”์ฒญ์ž„์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

CSRF ํ† ํฐ ์œ ์˜์‚ฌํ•ญ

[CSRF ํ† ํฐ์˜ ์œ„์น˜]

  • HTML ํผ ์ œ์ถœ์‹œ hidden ํ•„๋“œ๋กœ ํฌํ•จ์‹œ์ผœ์„œ ์ „์†กํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.
  • AJAX ์š”์ฒญ์„ ๋ณด๋‚ผ์‹œ์—๋Š” CSRF ํ† ํฐ์„ Custom Header ๊ฐ’์œผ๋กœ ํฌํ•จ์‹œํ‚ค๊ฑฐ๋‚˜ JSON payload(๋ฐ์ดํ„ฐ)๋กœ ์ „์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • CSRF ํ† ํฐ์„ ์ฟ ํ‚ค์— ํฌํ•จ์‹œ์ผœ์„œ ์ „์†กํ•˜๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค.
    • CSRF ํ† ํฐ์€ ์‹ค์ œ ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญํ•œ ์ •์ƒ์ ์ธ ์ž‘์—…์ธ์ง€๋ฅผ ๊ฒ€์ฆํ•ด์•ผํ•˜๋Š”๋ฐ, ์ฟ ํ‚ค๋Š” ๋ธŒ๋ผ์šฐ์ €์— ์˜ํ•ด ์ž๋™์œผ๋กœ HTTP ์š”์ฒญ์— ํฌํ•จ๋˜๋ฏ€๋กœ, ์ •์ƒ์ ์ธ ์š”์ฒญ์ธ์ง€ ๊ฒ€์ฆํ•  ์ˆ˜ ์—†๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
    • '์ž๋™ ์ „์†ก'์ด๋ผ๋Š” ๊ธฐ๋Šฅ๋•Œ๋ฌธ์— ๊ณต๊ฒฉ์ž๊ฐ€ ๋งŒ๋“  ์š”์ฒญ์ด์—ฌ๋„ ์ฟ ํ‚ค๊ฐ€ ์ž๋™์œผ๋กœ ํฌํ•จ๋˜์–ด ์„œ๋ฒ„์— ์ „์†ก๋ฉ๋‹ˆ๋‹ค. ์ด๋กœ์ธํ•ด ์„œ๋ฒ„๋Š” ์ด ์š”์ฒญ์ด ์ •์ƒ์ ์ธ ์š”์ฒญ์ด๋ผ๊ณ  ์ฐฉ๊ฐํ•˜์—ฌ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ๋”ฐ๋ผ์„œ CSRF ํ† ํฐ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ์‹์œผ๋กœ ์ „์†ก๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • CSRF ํ† ํฐ์€ ์„œ๋ฒ„ ๋กœ๊ทธ๋‚˜ URL์— ๋…ธ์ถœ๋˜์–ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค.

[HTTP ์š”์ฒญ์— ๋”ฐ๋ฅธ ์š”๊ตฌ์‚ฌํ•ญ]

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์š”์ฒญ์— ๋Œ€ํ•ด์„œ๋งŒ CSRF๋ฅผ ์š”์ฒญํ•ด๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. (POST, PUT, PATCH, DELETE)
    • ๋‹จ, ์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”(=๋ฉฑ๋“ฑ ์š”์ฒญ)์š”์ฒญ(GET, HEAD, OPTIONS, ๋ฐ TRACE)์ด ์˜ค์ง ์ฝ๊ธฐ ์ „์šฉ(read-only) ์ž‘์—…๋งŒ ์ˆ˜ํ–‰ํ•˜๋„๋ก ๋ณด์žฅํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.
  • HTTP GET(์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ์•ˆ์ „ํ•œ ์š”์ฒญ)์—๋Š” CSRF ํ† ํฐ์„ ํฌํ•จ์‹œํ‚ค์ง€ ์•Š์•„์•ผํ•ฉ๋‹ˆ๋‹ค.
    • GET ์š”์ฒญ์€ ์บ์‹œ๋˜๊ฑฐ๋‚˜ URL๋กœ ๋…ธ์ถœ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— CSRF ํ† ํฐ์ด ์œ ์ถœ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ํ† ํฐ์ด ์œ ์ถœ๋˜๋ฉด ๊ณต๊ฒฉ์ž๊ฐ€ ์ด ํ† ํฐ์„ ์žฌ์‚ฌ์šฉํ•˜์—ฌ CSRF ๊ณต๊ฒฉ์„ ์‹œ๋„ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

3. CSRF vs XSS

CSRF์™€ XSS๋Š” ๋ชจ๋‘ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ์˜ ๊ณต๊ฒฉ ์œ ํ˜•์ด์ง€๋งŒ, ์ฐจ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋จผ์ € XSS๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๊ฐ„๋‹จํ•˜๊ฒŒ ์งš๊ณ  ๋„˜์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.

 

XSS(Cross-Site Scripting)

XSS๋Š” Cross-Site Scripting์˜ ์•ฝ์ž๋กœ, ๋ฒˆ์—ญํ•˜๋ฉด ์‚ฌ์ดํŠธ ๊ฐ„ ์Šคํฌ๋ฆฝํŒ… ์ž…๋‹ˆ๋‹ค.

XSS ๊ณต๊ฒฉ์€ ๊ณต๊ฒฉ์ž๊ฐ€ ์›น ํŽ˜์ด์ง€์— ์•…์˜์ ์ธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฝ์ž…ํ•˜์—ฌ, ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰์‹œํ‚ค๋Š” ๊ณต๊ฒฉ์ž…๋‹ˆ๋‹ค. 

์ด๋กœ์ธํ•ด ์‚ฌ์šฉ์ž๋Š” ์˜๋„ํ•˜์ง€ ์•Š์€ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜, ๊ณต๊ฒฉ์ž์—๊ฒŒ ์ฟ ํ‚ค, ์„ธ์…˜ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ํƒˆ์ทจ ๋‹นํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

XSS๋Š” SQL Injection๊ณผ ํ•จ๊ป˜ ์›น ์ƒ์—์„œ ๊ฐ€์žฅ ๊ธฐ์ดˆ์ ์ธ ์ทจ์•ฝ์  ๊ณต๊ฒฉ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

XSS ๊ณต๊ฒฉ ๋Œ€์‘ ๋ฐฉ์•ˆ

  • ์ค‘์š” ์ •๋ณด๋Š” ์ฟ ํ‚ค ๋Œ€์‹  ์„œ๋ฒ„์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ์ •๋ณด๋ฅผ ์•”ํ˜ธํ™” ํ•ฉ๋‹ˆ๋‹ค.
  • httpOnly ์˜ต์…˜์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
    • document.cookie๋ฅผ ์ด์šฉํ•ด ์ฟ ํ‚ค์— ์ง์ ‘ ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€
  • URL Encoding์ด๋‚˜ ๋ฌธ์ž์—ด์„ ์น˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

CSRF ์™€ XSS ์˜ ์ฐจ์ด

[๊ณต๊ฒฉ ๋Œ€์ƒ]

  • CSRF ๊ณต๊ฒฉ ๋Œ€์ƒ์€ "Server"์ด๊ณ  XSS ๊ณต๊ฒฉ ๋Œ€์ƒ์€ "Client"์ž…๋‹ˆ๋‹ค.
  • CSRF๋Š” ํŠน์ • ์›น ์‚ฌ์ดํŠธ๊ฐ€ ์‚ฌ์šฉ์ž์˜ ์›น ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์‹ ๋ขฐํ•˜๋Š” ์ƒํƒœ๋ฅผ ๋…ธ๋ฆฐ ๊ฒƒ์ด๊ณ , XSS๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ํŠน์ • ์›น ์‚ฌ์ดํŠธ๋ฅผ ์‹ ๋ขฐํ•˜๋Š” ์ ์„ ๋…ธ๋ฆฐ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

[๊ณต๊ฒฉ ๋ฐฉ์‹]

  • CSRF๋Š” ๊ณต๊ฒฉ์ž๊ฐ€ ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์†์—ฌ ์˜๋„ํ•˜์ง€ ์•Š์€ ์š”์ฒญ์„ ํŠน์ • ์›น์‚ฌ์ดํŠธ๋กœ ๋ณด๋‚ด๋„๋ก ์œ ๋„ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ์„ ์ด์šฉํ•ด ์„œ๋ฒ„์— ๋Œ€ํ•œ ์•…์„ฑ ๊ณต๊ฒฉ์„์„ ํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. 
  • XSS๋Š” ๊ณต๊ฒฉ์ž๊ฐ€ ์•…์„ฑ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์›นํŽ˜์ด์ง€์— ์‚ฝ์ž…ํ•˜์—ฌ ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ•˜๋Š” ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹คํ–‰๋˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์Šคํฌ๋ฆฝํŠธ๋Š” ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰๋˜๋ฏ€๋กœ ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ์œผ๋กœ ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ํƒˆ์ทจํ•˜๊ฑฐ๋‚˜ ์ž„์˜์˜ ๋ช…๋ น์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CSRF ๊ณต๊ฒฉ

1๏ธโƒฃ ๊ณต๊ฒฉ์ž์ž ์›น ์‚ฌ์ดํŠธ์— ์ž๊ธˆ ์ด์ฒด ์š”์ฒญ์„ ์œ„์กฐํ•ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ ๊ณต๊ฒฉ์ž๋Š” ๊ทธ ์š”์ฒญ์„ ํ•˜์ดํผ๋งํฌ(์Šคํฌ๋ฆฝํŠธ)์— ์‚ฝ์ž…ํ•˜์—ฌ ์›น ์‚ฌ์ดํŠธ์— ๋กœ๊ทธ์ธ ํ•  ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ ์‚ฌ์šฉ์ž๊ฐ€ ๊ทธ ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด, ์‚ฌ์šฉ์ž๋„ ๋ชจ๋ฅด๊ฒŒ ์›น ์‚ฌ์ดํŠธ์— ์š”์ฒญ์„ ์ „์†กํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

4๏ธโƒฃ ์›น ์‚ฌ์ดํŠธ์˜ ์„œ๋ฒ„๋Š” ๋กœ๊ทธ์ธ ๋œ ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ •์ƒ์œผ๋กœ ํŒ๋‹จํ•˜๊ณ , ์‚ฌ์šฉ์ž์˜ ๊ณ„์ •์—์„œ ๊ณต๊ฒฉ์ž์˜ ๊ณ„์ •์œผ๋กœ ์ž๊ธˆ์„ ์ด์ฒดํ•ฉ๋‹ˆ๋‹ค.

XSS ๊ณต๊ฒฉ

1๏ธโƒฃ ๊ณต๊ฒฉ์ž๊ฐ€ ์Šคํฌ๋ฆฝํŠธ ์ฃผ์ž…์ด ๊ฐ€๋Šฅํ•œ ์ทจ์•ฝ์ ์ด ์žˆ๋Š” ์›น ์‚ฌ์ดํŠธ๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.

2๏ธโƒฃ ์ทจ์•ฝ์ ์„ ์ฐพ์•„ ์„ธ์…˜ ์ฟ ํ‚ค๋ฅผ ํƒˆ์ทจํ•˜๋Š” ์•…์„ฑ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์ดํŠธ์— ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค.

3๏ธโƒฃ ์‚ฌ์šฉ์ž๊ฐ€ ์›น ์‚ฌ์ดํŠธ๋ฅผ ๋ฐฉ๋ฌธํ•  ๋•Œ๋งˆ๋‹ค ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ž‘๋™๋ฉ๋‹ˆ๋‹ค.

4๏ธโƒฃ ์ž‘๋™๋œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž์˜ ์„ธ์…˜ ์ฟ ํ‚ค๋ฅผ ํƒˆ์ทจํ•ฉ๋‹ˆ๋‹ค.


Reference

 

 

Cross Site Request Forgery (CSRF) :: Spring Security

When should you use CSRF protection? Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users. If you are creating a service that is used only by non-browser clients, you likely want to disable CSRF

docs.spring.io

 

์›น ๋ณด์•ˆ์˜ ๊ธฐ๋ณธ: CSRF์™€ XSS ๊ณต๊ฒฉ ์ดํ•ดํ•˜๊ธฐ

CSRF์™€ XSS ๊ณต๊ฒฉ์˜ ๊ฐœ๋…์„ ์ดํ•ดํ•˜๊ณ , ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ•๋“ค์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋Š” ๊ธ€์ž…๋‹ˆ๋‹ค.

f-lab.kr

 
[๋ณด์•ˆ] CSRF

์—ฌ๊ธฐ์„œ๋Š” CSRF ๊ณต๊ฒฉ์ด ๋ฌด์—‡์ธ์ง€ ์•Œ์•„๋ณด๊ณ , ์ด๊ฒƒ์„ ์˜ˆ๋ฐฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ๋˜๋Š” CSRF Token์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌ๋ฅผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฒจ๋กœ๊ทธ.์•„์ด์˜ค
 

XSS์™€ CSRF ์ฐจ์ด์  ๋ฐ ๋Œ€์‘ ๋ฐฉ์•ˆ

์›น์‚ฌ์ดํŠธ์—์„œ ์˜๋„์น˜ ์•Š์€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋„ฃ์–ด์„œ ์‹คํ–‰์‹œํ‚ค๋Š” ๊ธฐ๋ฒ•์„ ๋งํ•ฉ๋‹ˆ๋‹ค.์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ์ž…๋ ฅ ๋ฐ›์€ ๊ฐ’์„ ์ œ๋Œ€๋กœ ๊ฒ€์‚ฌํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ๋ฐœ์ƒํ•˜๋ฉฐ, ๊ฒฐ๊ณผ๋กœ ์‚ฌ์šฉ์ž๋Š” ์˜

velog.io

1. ๋ชจ๋…ธํ†ค ์Šคํƒ(Monotone stack) ์ด๋ž€?

์Šคํƒ(Stack)์€ ํ•œ์ชฝ ๋์—์„œ๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ๊ณ  ๋บ„ ์ˆ˜ ์žˆ๋Š” ํ›„์ž…์„ ์ถœ(LIFO:Last In, First Out) ํ˜•ํƒœ์˜ ์ž๋ฃŒ๊ตฌ์กฐ ์ž…๋‹ˆ๋‹ค.
์ฆ‰, ๊ฐ€์žฅ ๋จผ์ € ๋“ค์–ด์˜จ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ๋‚˜๊ฐ€๊ณ , ๋งˆ์ง€๋ง‰์— ๋“ค์–ด์˜จ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ€์žฅ ๋จผ์ € ๋‚˜๊ฐ€๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

 

  • ๋ชจ๋…ธํ†ค ์Šคํƒ(Monotone stack)์€ ํŠน์ •ํ•œ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์Šคํƒ ์ž๋ฃŒ๊ตฌ์กฐ ์ž…๋‹ˆ๋‹ค.
    • Monotone์€ ์ฆ๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๊ฐ์†Œํ•˜๋Š” ๋“ฑ์˜ ์ผ์ •ํ•œ ๊ฒฝํ–ฅ์ด ๋ณด์ž„์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
  • ๋ชจ๋…ธํ†ค ์Šคํƒ(Monotone stack)์€ ์ฆ๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๊ฐ์†Œํ•˜๋Š” ์ผ์ •ํ•œ ๊ฒฝํ–ฅ์„ ๊ฐ€์ง„ ์Šคํƒ์ž…๋‹ˆ๋‹ค.
  • ๋ชจ๋…ธํ†ค ์Šคํƒ(Monotone stack)์€ ํŠน์ • ๋ฌธ์ œ์— ๋Œ€ํ•ด ์‹œ๊ฐ„ ๋ณต์žก๋„๋ฅผ O(N)์œผ๋กœ ์ค„์—ฌ์ฃผ๋Š” ๋งค์šฐ ํšจ์œจ์ ์ธ ํ•ด๊ฒฐ์ฑ…์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
    • ๋‹ค์Œ/์ด์ „ ๋ฐ์ดํ„ฐ์˜ ์ตœ๋Œ“๊ฐ’/์ตœ์†Ÿ๊ฐ’์„(Nearest Greater/Smaller Element) ์ฐพ๋Š” ๋ฌธ์ œ์— ์œ ์šฉํ•˜๊ฒŒ ์“ฐ์ž…๋‹ˆ๋‹ค.

 

2. ๋ชจ๋…ธํ†ค ์Šคํƒ(Monotone stack)์˜ ์ข…๋ฅ˜ ๋ฐ ๊ตฌํ˜„

์Šคํƒ์€ LIFO(Last In, First Out) ์ž๋ฃŒ ๊ตฌ์กฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋…ธํ†ค ์Šคํƒ์˜ ์ตœ์ƒ์œ„ ์š”์†Œ๋ฅผ ์ œ๊ฑฐํ•˜๋ฉด์„œ ๋‹จ์กฐ ์ฆ๊ฐ€/๊ฐ์†Œ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ์š”์†Œ๋Š” ํ•ญ์ƒ ์ตœ์ƒ์œ„์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.

1) ๋‹จ์กฐ ์ฆ๊ฐ€ ์Šคํƒ(Monotone Increasing Stack)

  • ์Šคํƒ์˜ ์š”์†Œ๋“ค์ด ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ๋˜๋Š” ์Šคํƒ
    • ์˜ค๋ฆ„์ฐจ์ˆœ์„ ์œ ์ง€ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์Šคํƒ์˜ ์•„๋ž˜์ชฝ๋ถ€ํ„ฐ ์œ„์ชฝ์œผ๋กœ ์˜ฌ๋ผ๊ฐˆ์ˆ˜๋ก ๊ฐ’์ด ์ปค์ง„๋‹ค๋Š” ์˜๋ฏธ
    • ์Šคํƒ์˜ ์ตœ์ƒ์œ„์—์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ ์•„๋ž˜๋กœ ๋‚ด๋ ค๊ฐˆ์ˆ˜๋ก ๊ฐ’์ด ์ž‘์•„์ง
10 (top)
5
2
1
  • ์Šคํƒ์˜ ๋งจ ์œ„์— ์žˆ๋Š” ์š”์†Œ๊ฐ€ ํ•ญ์ƒ ๊ทธ ์•„๋ž˜์— ์žˆ๋Š” ์š”์†Œ๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™์€ ๊ฒฝ์šฐ๋ฅผ ์œ ์ง€ํ•˜๋Š” ์Šคํƒ
    • ์Šคํƒ์— ์ƒˆ๋กœ์šด ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ, ๊ทธ ์š”์†Œ๊ฐ€ ์Šคํƒ์˜ ์ตœ์ƒ์œ„ ์š”์†Œ๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์„ ๋•Œ๊นŒ์ง€ ๊ธฐ์กด ์š”์†Œ๋ฅผ ์ œ๊ฑฐ
    • ์ด๋•Œ, ๋‹จ์กฐ์„ฑ์„ ์œ ์ง€ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. (์Šคํƒ์— ์žˆ๋Š” ์š”์†Œ๋“ค์ด ํ•ญ์ƒ ํŠน์ • ์ˆœ์„œ(์˜ค๋ฆ„์ฐจ์ˆœ)๋ฅผ ์œ ์ง€)
    • ์ค‘๋ณต ๊ฐ’ ํ—ˆ์šฉ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๊ฐ’์ด ๊ฐ™์€ ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์ œ๊ฑฐ ์—ฌ๋ถ€๋ฅผ ์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
Deque<Integer> stack = new ArrayDeque<>();
for (int i=0; i<arr.length; i++) {
    // ์Šคํƒ์˜ ์ตœ์ƒ์œ„ ์š”์†Œ๊ฐ€ ํ˜„์žฌ ๊ฐ’๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™์œผ๋ฉด pop();
    while (!stack.isEmpty() && stack.peekFirst() >= arr[i]) {
    	stack.removeFirst();
    }
    // ์Šคํƒ์˜ ์ตœ์ƒ์œ„ ์š”์†Œ๋ณด๋‹ค ์ž‘์„๋•Œ๊นŒ์ง€ ๊ธฐ์กด ์š”์†Œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ , ํ˜„์žฌ ์š”์†Œ ์Šคํƒ์— ์ถ”๊ฐ€
    stack.offerFirst(arr[i]);
}

2) ๋‹จ์กฐ ๊ฐ์†Œ ์Šคํƒ(Monotone Decreasing Stack)

  • ์Šคํƒ์˜ ์š”์†Œ๋“ค์ด ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ๋˜๋Š” ์Šคํƒ
    • ๋‚ด๋ฆผ์ฐจ์ˆœ์„ ์œ ์ง€ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์Šคํƒ์˜ ์•„๋ž˜์ชฝ๋ถ€ํ„ฐ ์œ„์ชฝ์œผ๋กœ ์˜ฌ๋ผ๊ฐˆ์ˆ˜๋ก ๊ฐ’์ด ์ž‘์•„์ง„๋‹ค๋Š” ์˜๋ฏธ
    • ์Šคํƒ์˜ ์ตœ์ƒ์œ„์—์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ ์•„๋ž˜๋กœ ๊ฐˆ์ˆ˜๋ก ๊ฐ’์ด ์ปค์ง
1 (top)
2
5
10
  • ์Šคํƒ์˜ ๋งจ ์œ„์— ์žˆ๋Š” ์š”์†Œ๊ฐ€ ํ•ญ์ƒ ๊ทธ ์•„๋ž˜์— ์žˆ๋Š” ์š”์†Œ๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์€ ๊ฒฝ์šฐ๋ฅผ ์œ ์ง€ํ•˜๋Š” ์Šคํƒ
    • ์Šคํƒ์— ์ƒˆ๋กœ์šด ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ, ๊ทธ ์š”์†Œ๊ฐ€ ์Šคํƒ์˜ ์ตœ์ƒ์œ„ ์š”์†Œ๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™์„ ๋•Œ๊นŒ์ง€ ๊ธฐ์กด ์š”์†Œ๋ฅผ ์ œ๊ฑฐ
    • ์ด๋•Œ, ๋‹จ์กฐ์„ฑ์„ ์œ ์ง€ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. (์Šคํƒ์— ์žˆ๋Š” ์š”์†Œ๋“ค์ด ํŠน์ • ์ˆœ์„œ(๋‚ด๋ฆผ์ฐจ์ˆœ)๋ฅผ ์œ ์ง€)
    • ์ค‘๋ณต ๊ฐ’ ํ—ˆ์šฉ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๊ฐ’์ด ๊ฐ™์€ ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์ œ๊ฑฐ ์—ฌ๋ถ€๋ฅผ ์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
Deque<Integer> stack = new ArrayDeque<>();
for (int i=0; i<arr.length; i++) {
    // ์Šคํƒ์˜ ์ตœ์ƒ์œ„ ์š”์†Œ๊ฐ€ ํ˜„์žฌ ๊ฐ’๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์œผ๋ฉด pop();
    while (!stack.isEmpty() && stack.peekFirst() <= arr[i]) {
    	stack.removeFirst();
    }
    // ์Šคํƒ์˜ ์ตœ์ƒ์œ„ ์š”์†Œ๋ณด๋‹ค ํด ๋•Œ๊นŒ์ง€ ๊ธฐ์กด ์š”์†Œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ , ํ˜„์žฌ ์š”์†Œ ์Šคํƒ์— ์ถ”๊ฐ€
    stack.offerFirst(arr[i]);
}

 

 

3. ๋ชจ๋…ธํ†ค ์Šคํƒ(Monotone stack) ๊ตฌํ˜„ - ์˜ˆ์‹œ๋กœ ํ™•์ธ

๊ฐœ์ธ์ ์œผ๋กœ ๋ชจ๋…ธํ†ค ์Šคํƒ์˜ ์ข…๋ฅ˜์— ๋Œ€ํ•ด ์ดํ•ดํ•˜๋Š”๋ฐ์— ์กฐ๊ธˆ ์‹œ๊ฐ„์ด ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค. ๋‹จ์กฐ ์ฆ๊ฐ€ ์Šคํƒ๊ณผ ๋‹จ์กฐ ๊ฐ์†Œ ์Šคํƒ์˜ ์ •๋ ฌ ์ˆœ์„œ๊ฐ€ ์–ด๋””๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ •ํ™•ํ•œ ์ดํ•ด๋ฅผ ๋ชปํ•˜๊ณ  ๋ฌด์ž‘์ • ์ดํ•ดํ•˜๋ ค๊ณ  ํ•˜๋‹ค๋ณด๋‹ˆ ํ—ท๊ฐˆ๋ ธ์Šต๋‹ˆ๋‹ค. 

๊ทธ๋ž˜์„œ ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ฐฐ์—ด ์˜ˆ์‹œ๋ฅผ ์ •๋ฆฌํ•˜๋ฉด์„œ ์•„์ง์€ ์กฐ๊ธˆ ํ—ท๊ฐˆ๋ฆฌ๋Š” ๋ถ€๋ถ„์„ ์ •๋ฆฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

public static void main(String[] args) {
    int[][] testArrays = {
        {1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
        {10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
        {5, 5, 4, 4, 3, 3, 2, 2, 1, 1},
        {3, 6, 1, 9, 4, 7, 2, 8, 5, 10}
    };

    for (int[] arr : testArrays) {
        System.out.println("Monotonic Stack for array: " + Arrays.toString(arr));
        incresing(arr);
        decresing(arr);
        System.out.println();
    }
}

ํ…Œ์ŠคํŠธ ๋ฐฐ์—ด์„ ์œ„์™€ ๊ฐ™์ด 4๊ฐ€์ง€ ์ •๋„๋กœ ์ƒ์„ฑํ•ด๋‘๊ณ  ๋‹จ์กฐ ์ฆ๊ฐ€ ์Šคํƒ๊ณผ ๋‹จ์กฐ ๊ฐ์†Œ ์Šคํƒ์„ ์ถœ๋ ฅํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

*๊ฐ ์Šคํƒ์€ 2๋ฒˆ ๋ชฉ์ฐจ์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•ด์„œ ์ƒ์„ฑ

 

์œ„ ์ฝ”๋“œ์— ๋Œ€ํ•œ ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Monotonic Stack for array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Monotonic Increasing Stack: 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 
Monotonic Decreasing Stack: 10, 

Monotonic Stack for array: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Monotonic Increasing Stack: 1, 
Monotonic Decreasing Stack: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 

Monotonic Stack for array: [5, 5, 4, 4, 3, 3, 2, 2, 1, 1]
Monotonic Increasing Stack: 1, 
Monotonic Decreasing Stack: 1, 2, 3, 4, 5, 

Monotonic Stack for array: [3, 6, 1, 9, 4, 7, 2, 8, 5, 10]
Monotonic Increasing Stack: 10, 5, 2, 1, 
Monotonic Decreasing Stack: 10,

 

๋‹จ์กฐ ์ฆ๊ฐ€ ์Šคํƒ์€ ์š”์†Œ๋“ค์ด ์˜ค๋ฆ„์ฐจ์ˆœ(์Šคํƒ์˜ ์•„๋ž˜๋ถ€ํ„ฐ ์ตœ์ƒ์œ„๊นŒ์ง€)์œผ๋กœ ์ •๋ ฌ๋˜์–ด ์žˆ๋Š” ์Šคํƒ

๋‹จ์กฐ ๊ฐ์†Œ ์Šคํƒ์€ ์š”์†Œ๋“ค์ด ๋‚ด๋ฆผ์ฐจ์ˆœ(์Šคํƒ์˜ ์•„๋ž˜๋ถ€ํ„ฐ ์ตœ์ƒ์œ„๊นŒ์ง€)์œผ๋กœ ์ •๋ ฌ๋˜์–ด ์žˆ๋Š” ์Šคํƒ

์ธ ์ ์„ ๋จธ๋ฆฌ์†์— ๊ผญ ๋‹ด์•„๋‘๊ณ  ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด, ์ œ๋Œ€๋กœ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ฝ”๋“œ ๊ตฌํ˜„์‹œ ์ค‘๋ณต ๊ฐ’์€ ํ—ˆ์šฉํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— 3๋ฒˆ ์˜ˆ์‹œ์ฒ˜๋Ÿผ ์ค‘๋ณต ๊ฐ’์ด ์—†๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์ค‘๋ณต์„ ํ—ˆ์šฉํ•œ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

Monotonic Stack for array: [5, 5, 4, 4, 3, 3, 2, 2, 1, 1]
Monotonic Increasing Stack: 1, 1, 
Monotonic Decreasing Stack: 1, 1, 2, 2, 3, 3, 4, 4, 5, 5,

 

๋‹จ์กฐ ์ฆ๊ฐ€ ์Šคํƒ ํ•จ์ˆ˜๋Š” ์•„๋ž˜์™€ ๊ฐ™์„๋•Œ ๋งˆ์ง€๋ง‰ ์˜ˆ์‹œ์ธ {3, 6, 1, 9, 4, 7, 2, 8, 5, 10} ์— ๋Œ€ํ•œ ๋‹จ์กฐ ์ฆ๊ฐ€ ์Šคํƒ ์ƒ์„ฑ ๊ณผ์ •์„ ๊ตฌ์ฒด์ ์œผ๋กœ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

public static void incresing(int[] arr) {
    Deque<Integer> stack = new ArrayDeque<>();
    for (int i=0; i<arr.length; i++) {
        // ์Šคํƒ์˜ ์ตœ์ƒ์œ„ ์š”์†Œ๊ฐ€ ํ˜„์žฌ ๊ฐ’๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™์œผ๋ฉด pop();
        while (!stack.isEmpty() && stack.peekFirst() >= arr[i]) {
        	stack.removeFirst();
        }
        // ์Šคํƒ์˜ ์ตœ์ƒ์œ„ ์š”์†Œ๋ณด๋‹ค ์ž‘์„๋•Œ๊นŒ์ง€ ๊ธฐ์กด ์š”์†Œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ , ํ˜„์žฌ ์š”์†Œ ์Šคํƒ์— ์ถ”๊ฐ€
        stack.offerFirst(arr[i]);
    }
}

 

  • ๋ฐฐ์—ด: {3, 6, 1, 9, 4, 7, 2, 8, 5, 10}
๋ฐฐ์—ด ์š”์†Œ ์„ค๋ช… ์Šคํƒ
์ฒซ๋ฒˆ์งธ ์š”์†Œ: 3 ์Šคํƒ์ด ๋น„์–ด์žˆ์œผ๋ฏ€๋กœ ์š”์†Œ 3 ์ถ”๊ฐ€  [3]
๋‘๋ฒˆ์งธ ์š”์†Œ: 6 ์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ(3)๊ฐ€ 6๋ณด๋‹ค ์ž‘์œผ๋ฏ€๋กœ 6์„ ์Šคํƒ์— ์ถ”๊ฐ€ [6, 3]
์„ธ๋ฒˆ์งธ ์š”์†Œ: 1 ์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ(6)๊ฐ€ 1๋ณด๋‹ค ํฌ๋ฏ€๋กœ, 6์„ ์Šคํƒ์—์„œ ์ œ๊ฑฐ [3]
์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ(3)๊ฐ€ 1๋ณด๋‹ค ํฌ๋ฏ€๋กœ, 3์„ ์Šคํƒ์—์„œ ์ œ๊ฑฐ [ ]
์Šคํƒ์ด ๋น„์—ˆ์œผ๋ฏ€๋กœ ์š”์†Œ 1 ์ถ”๊ฐ€ [1]
๋„ค๋ฒˆ์งธ ์š”์†Œ: 9 ์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ(1)๊ฐ€ 9๋ณด๋‹ค ์ž‘์œผ๋ฏ€๋กœ, 9๋ฅผ ์Šคํƒ์— ์ถ”๊ฐ€ [9, 1]
๋‹ค์„ฏ๋ฒˆ์งธ ์š”์†Œ: 4 ์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ(9)๊ฐ€ 4๋ณด๋‹ค ํฌ๋ฏ€๋กœ, 9๋ฅผ ์Šคํƒ์—์„œ ์ œ๊ฑฐ [1]
์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ(1)๊ฐ€ 4๋ณด๋‹ค ์ž‘์œผ๋ฏ€๋กœ, 4๋ฅผ ์Šคํƒ์— ์ถ”๊ฐ€ [4, 1]
์—ฌ์„ฏ๋ฒˆ์งธ ์š”์†Œ: 7 ์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ(4)๊ฐ€ 7๋ณด๋‹ค ์ž‘์œผ๋ฏ€๋กœ, 7์„ ์Šคํƒ์— ์ถ”๊ฐ€ [7, 4, 1]
์ผ๊ณฑ๋ฒˆ์งธ ์š”์†Œ: 2 ์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ(7)๊ฐ€ 2๋ณด๋‹ค ํฌ๋ฏ€๋กœ, 7์„ ์Šคํƒ์—์„œ ์ œ๊ฑฐ [4, 1]
์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ(4)๊ฐ€ 2๋ณด๋‹ค ํฌ๋ฏ€๋กœ, 4๋ฅผ ์Šคํƒ์—์„œ ์ œ๊ฑฐ [1]
์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ(1)๊ฐ€ 2๋ณด๋‹ค ์ž‘์œผ๋ฏ€๋กœ, 2๋ฅผ ์Šคํƒ์— ์ถ”๊ฐ€ [2, 1]
์—ฌ๋Ÿ๋ฒˆ์งธ ์š”์†Œ: 8 ์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ(2)๊ฐ€ 8๋ณด๋‹ค ์ž‘์œผ๋ฏ€๋กœ, 8์„ ์Šคํƒ์— ์ถ”๊ฐ€ [8, 2, 1]
์•„ํ™‰๋ฒˆ์งธ ์š”์†Œ: 5 ์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ(8)๊ฐ€ 5๋ณด๋‹ค ํฌ๋ฏ€๋กœ, 8์„ ์Šคํƒ์—์„œ ์ œ๊ฑฐ [2, 1]
์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ(2)๊ฐ€ 5๋ณด๋‹ค ์ž‘์œผ๋ฏ€๋กœ, 5๋ฅผ ์Šคํƒ์— ์ถ”๊ฐ€ [5, 2, 1]
์—ด๋ฒˆ์งธ ์š”์†Œ: 10 ์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ(5)๊ฐ€ 10๋ณด๋‹ค ์ž‘์œผ๋ฏ€๋กœ, 10์„ ์Šคํƒ์— ์ถ”๊ฐ€ [10, 5, 2, 1]

 

์ตœ์ข…์ ์œผ๋กœ ์Šคํƒ์„ ์ถœ๋ ฅํ•˜๋ฉด [10, 5, 2, 1] ์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ๊ฐ€ ํ˜„์žฌ ๋ฐฐ์—ด ์š”์†Œ๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™์œผ๋ฉด ์Šคํƒ์—์„œ ์ œ๊ฑฐํ•˜๊ณ , ํ˜„์žฌ ์š”์†Œ๋ฅผ ์Šคํƒ์— ์ถ”๊ฐ€ํ•˜๋ฉด์„œ ๋‹จ์กฐ์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

4. ๋ชจ๋…ธํ†ค ์Šคํƒ(Monotone stack) ๊ด€๋ จ ๋ฌธ์ œ

 

[๋ฐฑ์ค€] ํƒ‘ ๋ณด๊ธฐ - ์ž๋ฐ”(Java)

๋ฌธ์ œ ๋งํฌhttps://www.acmicpc.net/problem/22866๋ฌธ์ œ ์„ค๋ช…์ผ์ง์„ ์œผ๋กœ ๋‹ค์–‘ํ•œ ๋†’์ด์˜ ๊ฑด๋ฌผ์ด ์ด N๊ฐœ๊ฐ€ ์กด์žฌํ•œ๋‹ค. ๊ฐ ๊ฑด๋ฌผ ์˜ฅ์ƒ์—์„œ ์–‘ ์˜†์— ์กด์žฌํ•˜๋Š” ๊ฑด๋ฌผ์˜ ์˜†์„ ๋ช‡ ๊ฐœ ๋ณผ ์ˆ˜ ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ด์กŒ๋‹ค. i๋ฒˆ์งธ ๊ฑด

coding-vvon.tistory.com

 

 

์ฐธ๊ณ  ๋งํฌ

 

๋ชจ๋…ธํ†ค ์Šคํƒ, ํ,๋ฑ์— ๊ด€ํ•˜์—ฌ.

์„œ๋ก . ์Šคํƒ, ํ, ๋ฑ ๋ฌธ์ œ๋“ค์„ ํ‘ธ๋Š” ๋™์•ˆ ๋งŽ์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜๋“ค์ด ํ•ด๋‹น ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๋ณด์•˜๋‹ค ํ•˜๋‚˜๊ฐ™์ด ํ•ด๋‹น ํ˜•์‹์„ ๋”ฐ๋ฅด๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ๋ณด๊ณ  ๋ญ”๊ฐ€ ์ •ํ˜•ํ™”๋œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์žˆ๋‚˜? ์ƒ๊ฐ์ด ๋“ค์—ˆ๋Š”

velog.io

 

์ง€๋‚œ๋ฒˆ์— ํŠธ๋ผ์ด๋ฅผ ๊ณต๋ถ€ํ•˜๊ณ  ํฌ์ŠคํŒ…์œผ๋กœ ์ •๋ฆฌํ–ˆ๋Š”๋ฐ, ์•„๋ž˜ ํฌ์ŠคํŒ…์—์„œ๋Š” Map Interface๋กœ ๊ตฌํ˜„์„ ํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ๋ฐฑ์ค€ - ์ „์„ค(19585)์„ ํŠธ๋ผ์ด ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ํ’€์–ด๋„ ์‹œ๊ฐ„ ์ดˆ๊ณผ๊ฐ€ ๋‚˜๊ธธ๋ž˜ ๋” ์ฐพ์•„๋ณด๋‹ˆ Array๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ์‹๋„ ์žˆ์–ด์„œ ์ด๋ฒˆ์—๋Š” Array ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•œ ํŠธ๋ผ์ด๋„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.


ํŠธ๋ผ์ด(Trie)๋ž€?

ํŠธ๋ผ์ด(Trie)๋Š” ๋ฌธ์ž์—ด์„ ์ €์žฅํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ํƒ์ƒ‰ํ•˜๊ธฐ ์œ„ํ•œ ํŠธ๋ฆฌ ํ˜•ํƒœ์˜ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ, ์ž์„ธํ•œ๊ฑด ์ง€๋‚œ๋ฒˆ ํฌ์ŠคํŒ…์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

 

[์ž๋ฃŒ๊ตฌ์กฐ] ํŠธ๋ผ์ด(Trie)

1. ํŠธ๋ผ์ด(Trie)๋ž€?์›ํ•˜๋Š” ์š”์†Œ๋ฅผ ์ฐพ๊ธฐ์œ„ํ•ด ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ์ด์ง„ ๊ฒ€์ƒ‰ ํŠธ๋ฆฌ ๋“ฑ์—์„œ๋Š” ํƒ€๊ฒŸ ์š”์†Œ๋ฅผ ์ฐพ๋Š”๋ฐ์— O(logN)์˜ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค.ํ•˜์ง€๋งŒ ๋ฌธ์ž์—ด์˜ ๊ฒฝ์šฐ ๋‘ ๋ฌธ์ž์—ด์„ ๋น„๊ตํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฌธ์ž์—ด

coding-vvon.tistory.com

 

ํŠธ๋ผ์ด(Trie) ๊ตฌํ˜„ ๋ฐฉ์‹

ํŠธ๋ผ์ด(Trie)๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. Array๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ตฌํ˜„
  2. Map Interface๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ตฌํ˜„

Array๋กœ ๊ตฌํ˜„ํ•  ๊ฒฝ์šฐ, ๋น ๋ฅธ ์ €์žฅ๊ณผ ํƒ์ƒ‰์„ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์ง€๋งŒ ํ•„์š”ํ•œ ๋ฉ”๋ชจ๋ฆฌ์˜ ํฌ๊ธฐ๊ฐ€ ๋„ˆ๋ฌด ํฌ๋‹ค๋Š” ๊ฒƒ์ด ๋‹จ์ ์ž…๋‹ˆ๋‹ค.

Map Interface๋กœ ๊ตฌํ˜„ํ•  ๊ฒฝ์šฐ, ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋™์ ์œผ๋กœ ํ• ๋‹นํ•˜์—ฌ ํ•„์š” ๋…ธ๋“œ๋งŒ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์ง€๋งŒ ๋ฉ”๋ชจ๋ฆฌ ์ œํ•œ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ตœ์ ํ™” ์ž‘์—…์ด ๊ฝค ๊นŒ๋‹ค๋กญ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

1. Array๋กœ ๊ตฌํ˜„

Array๋กœ ๊ตฌํ˜„ํ•  ๊ฒฝ์šฐ, Trie์˜ Node๋ณ„ ์ž์‹ ๋…ธ๋“œ๋ฅผ Nodeํ˜• ๋ฐฐ์—ด๋กœ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. 

์ด๋•Œ, Trie Node์— ๋“ค์–ด๊ฐ€๋Š” ๋‹จ์–ด๋Š” ์˜์–ด ์†Œ๋ฌธ์ž๋งŒ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉฐ, ๊ฐ ๋…ธ๋“œ๋Š” ์˜์–ด ์†Œ๋ฌธ์ž๋ฅผ ์ •์ˆ˜ํ˜•(int)์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ธ๋ฑ์Šค๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

* ์ž์„ธํ•œ ์„ค๋ช…์€ ์ด์ „ ํฌ์ŠคํŒ…์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

 

[์ž๋ฃŒ๊ตฌ์กฐ] ํŠธ๋ผ์ด(Trie)

1. ํŠธ๋ผ์ด(Trie)๋ž€?์›ํ•˜๋Š” ์š”์†Œ๋ฅผ ์ฐพ๊ธฐ์œ„ํ•ด ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ์ด์ง„ ๊ฒ€์ƒ‰ ํŠธ๋ฆฌ ๋“ฑ์—์„œ๋Š” ํƒ€๊ฒŸ ์š”์†Œ๋ฅผ ์ฐพ๋Š”๋ฐ์— O(logN)์˜ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค.ํ•˜์ง€๋งŒ ๋ฌธ์ž์—ด์˜ ๊ฒฝ์šฐ ๋‘ ๋ฌธ์ž์—ด์„ ๋น„๊ตํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฌธ์ž์—ด

coding-vvon.tistory.com

 

Node ํด๋ž˜์Šค ์ƒ์„ฑ

Map์œผ๋กœ ๊ตฌํ˜„ํ•œ Trie ์˜ Node์™€ ๋‹ค๋ฅด๊ฒŒ ์ž์‹ ๋…ธ๋“œ๋ฅผ Node[] ๋กœ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

childNode์˜ ์ธ๋ฑ์Šค์— ์˜์–ด ์†Œ๋ฌธ์ž๋ฅผ ์ •์ˆ˜ํ˜•(int)๋กœ ๋ณ€ํ™˜ํ•œ ๊ฐ’์ด ๋“ค์–ด๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ž์‹ ๋…ธ๋“œ์˜ ์ˆ˜(childCnt)์™€ ํ•ด๋‹น ๋…ธ๋“œ์˜ ๋ฌธ์ž(val)๋„ ์ €์žฅํ•ด์ค๋‹ˆ๋‹ค.

static final int SIZE = 26; // ์˜์–ด ์†Œ๋ฌธ์ž๋Š” 26์ž
private class Node {
    Node[] childNode = new Node[SIZE]; // ์ž์‹ ๋…ธ๋“œ: ์˜์–ด ์†Œ๋ฌธ์ž๋ฅผ ์ธ๋ฑ์Šคํ™” ํ•˜์—ฌ ์ €์žฅ
    boolean endOfWord; // ๋‹จ์–ด์˜ ๋์ธ์ง€์— ๋Œ€ํ•œ ํ”Œ๋ž˜๊ทธ
    int childCnt = 0; // ์ž์‹ ๋…ธ๋“œ ์ˆ˜
    char val; // ๋…ธ๋“œ์˜ ๋ฌธ์ž
}

 

ํŠธ๋ผ์ด(Trie) ์ž๋ฃŒ๊ตฌ์กฐ ํด๋ž˜์Šค ์ƒ์„ฑ

public class TrieArray {
    private Node rootNode;
    public TrieArray() {
    	rootNode = new Node();
    }
}

๊ธฐ๋ณธ ๋ฉ”์„œ๋“œ

1) ๋…ธ๋“œ ์ถ”๊ฐ€(insert)

๋ฌธ์ž์—ด์˜ ๋ฌธ์ž๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ ํ•ด๋‹น ๋ฌธ์ž๊ฐ€ ์ž์‹๋…ธ๋“œ๋กœ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์—ฌ ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค. 

Map์œผ๋กœ ๊ตฌํ˜„ํ–ˆ์„๋•Œ์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ํ˜„ ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ null ์ด ์•„๋‹Œ์ง€, ์ฆ‰, ์ƒ์„ฑ๋˜์–ด์žˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•˜์—ฌ, ์—†๋‹ค๋ฉด ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. 

์ƒ์„ฑ์‹œ์—๋Š” ์ž์‹ ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ์ž์‹ ๋…ธ๋“œ์˜ ๋ฌธ์ž๋ฅผ ํ• ๋‹นํ•ด์ฃผ๊ณ , ํ˜„ ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ ์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ต๋‹ˆ๋‹ค.

public void insert(String word) {
    Node node = this.rootNode;
    // ๋‹จ์–ด์˜ ๋ฌธ์ž๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ ์ž์‹ ๋…ธ๋“œ ํ™•์ธ
    for (int i=0; i < word.length(); i++) {
        char c = word.charAt(i);
        // ๋‹จ์–ด์˜ ํŠน์ • ๋ฌธ์ž๋ฅผ ์ธ๋ฑ์Šค(int)๋กœ ๋ณ€ํ™˜
        int intVal = charToInt(c);
        // ํ˜„ ๋…ธ๋“œ์— ์ธ๋ฑ์Šค๋กœ ๋ณ€ํ™˜ํ•œ ๋ฌธ์ž๊ฐ€ ์ž์‹๋…ธ๋“œ๋กœ ์žˆ๋Š”์ง€ ํ™•์ธ
        if (node.childNode[intVal] == null) {
            // ์ž์‹ ๋…ธ๋“œ์— ์—†๋Š” ๋ฌธ์ž๋ผ๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑ
            node.childNode[intVal] = new Node();
            node.childNode[intVal].val = c;
            node.childCnt++;
        }
        // ๋‹ค์Œ ํƒ์ƒ‰ ๋…ธ๋“œ๋ฅผ ์ž์‹๋…ธ๋“œ๋กœ ๋ณ€๊ฒฝ
        node = node.childNode[intVal];
    }
    node.endOfWord = true; // ๋‹จ์–ด(word)์˜ ๋ฌธ์ž๋ฅผ ๋ชจ๋‘ ์ˆœํšŒํ•˜๋ฉด ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋Š” ๋ฆฌํ”„ ๋…ธ๋“œ(=๋งˆ์ง€๋ง‰ ๋ฌธ์ž)์ด๊ธฐ๋•Œ๋ฌธ์— endOfWord๋ฅผ true๋กœ ์„ค์ •
}

2) ํฌํ•จ ์—ฌ๋ถ€ ํ™•์ธ(contains)

๋ฌธ์ž์—ด์ด ํŠธ๋ผ์ด์— ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ๋กœ, ๋ฐฐ์—ด ๋ฐฉ์‹์— ๋งž๊ฒŒ ๊ตฌํ˜„ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

public boolean contains(String word) {
    Node node = this.rootNode;
    char c;
    for (int i=0; i<word.length(); i++) {
        c = word.charAt(i);
        int intVal = charToInt(c); // ๋ฌธ์ž๋ฅผ ์ธ๋ฑ์Šค๋กœ ๋ณ€ํ™˜
        if (node.childNode[intVal] == null) return false; // ํ˜„์žฌ ํƒ์ƒ‰ํ•˜๋Š” ๋ฌธ์ž๊ฐ€ ์ž์‹ ๋…ธ๋“œ์— ์—†๋‹ค๋ฉด ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋‹จ์–ด
        node = node.childNode[intVal];
    }
    return node != null && node.endOfWord; // ๋งˆ์ง€๋ง‰ ๋ฌธ์ž ์—ฌ๋ถ€๋ฅผ ๋ฐ˜ํ™˜
}

3) ๋…ธ๋“œ ์‚ญ์ œ(delete)

ํŠธ๋ผ์ด์— ์กด์žฌํ•˜๋Š” ๋ฌธ์ž์—ด์„ ์‚ญ์ œํ•˜๋Š” ๋ฉ”์„œ๋“œ๋กœ, ์‚ญ์ œ ์กฐ๊ฑด์— ๋งž์ถฐ ๋ฐฐ์—ด ๋ฐฉ์‹์— ๋งž๊ฒŒ ๊ตฌํ˜„ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

public void delete(String word) {
    delete(this.rootNode, word, 0);
}
// ์žฌ๊ท€ ํ˜ธ์ถœ์„ ์œ„ํ•œ ํ•จ์ˆ˜ ์˜ค๋ฒ„๋กœ๋”ฉ
public void delete(Node node, String word, int idx) {
    // ๋‹จ์–ด์˜ ๋งˆ์ง€๋ง‰์ธ ๊ฒฝ์šฐ
    if (idx == word.length()) {
        if (!node.endOfWord) throw new Error(word + " not exist"); // ๋‹จ์–ด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Œ
        node.endOfWord = false; // ๋‹จ์–ด์˜ ๋ ๋ฌธ์ž ํ‘œ์‹œ๋ฅผ false๋กœ ๋ณ€๊ฒฝ: ํ•ด๋‹น ๋ฌธ์ž ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•˜๊ธฐ ์œ„ํ•จ
        return; // ๋ฆฌํ”„ ๋…ธ๋“œ์˜ ๋ถ€๋ชจ ๋…ธ๋“œ๋กœ return
    } else {
        if (node.childCnt == 0) throw new Error(word + " not exist"); // ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ(=๋‹จ์–ด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ)
    }

    char c = word.charAt(idx); // ํ˜„์žฌ ํ™•์ธํ•ด์•ผํ•˜๋Š” ๋ฌธ์ž
    int intVal = charToInt(c); // ๋ฌธ์ž๋ฅผ ์ธ๋ฑ์Šค๋กœ ๋ณ€ํ™˜

    Node child = node.childNode[intVal]; // ์ž์‹ ๋…ธ๋“œ ๊ฐ€์ ธ์˜ค๊ธฐ
    // ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด ๋ฆฌํ”„ ๋…ธ๋“œ๊นŒ์ง€ ๋‚ด๋ ค๊ฐ€์•ผ ํ•˜๋ฏ€๋กœ ์žฌ๊ท€ ํ˜ธ์ถœ
    delete(child, word, idx+1);
    // ํ˜„ ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์‚ญ์ œ๋˜์—ˆ๋‹ค๋ฉด, ํ˜„ ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ ์ˆ˜ 1 ์ฐจ๊ฐ
    if (node.childNode[intVal] == null) node.childCnt--;
    // ํ˜„ ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ๋ฆฌํ”„ ๋…ธ๋“œ์ด๊ณ (=์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†์Œ), ๋‹จ์–ด์˜ ๋์ธ ๋ฌธ์ž๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ์‚ญ์ œ
    if (child.childCnt == 0 && !node.endOfWord) node = null;
}

 

๐Ÿงช ๊ตฌํ˜„ ํ…Œ์ŠคํŠธ

๊ตฌํ˜„ ํ…Œ์ŠคํŠธ๋Š” Map ๋ฐฉ์‹๊ณผ ๋™์ผํ•˜๋‹ˆ, ํ•ด๋‹น ํฌ์ŠคํŒ…์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š” :)

 

๐Ÿ’ก ์ „์ฒด ์ฝ”๋“œ(Array๋กœ ๊ตฌํ˜„)๋Š” ์•„๋ž˜ ๋งํฌ์—์„œ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

 

Algorithm/src/Trie/TrieArray.java at main · hywnj/Algorithm

Contribute to hywnj/Algorithm development by creating an account on GitHub.

github.com

 

2. Map Interface๋กœ ๊ตฌํ˜„

์•„๋ž˜ ์ฝ”๋“œ๋Š” Map Interface๋กœ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ์ด๋ฉฐ, ์ž์„ธํ•œ ์„ค๋ช…์€ ์ด์ „ ํฌ์ŠคํŒ…์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

 

[์ž๋ฃŒ๊ตฌ์กฐ] ํŠธ๋ผ์ด(Trie)

1. ํŠธ๋ผ์ด(Trie)๋ž€?์›ํ•˜๋Š” ์š”์†Œ๋ฅผ ์ฐพ๊ธฐ์œ„ํ•ด ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ์ด์ง„ ๊ฒ€์ƒ‰ ํŠธ๋ฆฌ ๋“ฑ์—์„œ๋Š” ํƒ€๊ฒŸ ์š”์†Œ๋ฅผ ์ฐพ๋Š”๋ฐ์— O(logN)์˜ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค.ํ•˜์ง€๋งŒ ๋ฌธ์ž์—ด์˜ ๊ฒฝ์šฐ ๋‘ ๋ฌธ์ž์—ด์„ ๋น„๊ตํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฌธ์ž์—ด

coding-vvon.tistory.com

 

 

๐Ÿ’ก Trie๋ฅผ Map, Array๋กœ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ๋Š” ์•„๋ž˜ ๋งํฌ์—์„œ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

 

Algorithm/src/Trie at main · hywnj/Algorithm

Contribute to hywnj/Algorithm development by creating an account on GitHub.

github.com

 

Reference

 

[์ž๋ฃŒ๊ตฌ์กฐ | Java] Trie(ํŠธ๋ผ์ด)

์ด๋ฒˆ ์‹œ๊ฐ„์—๋Š” ์ž๋ฃŒ๊ตฌ์กฐ ํŠธ๋ผ์ด์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. 1. ํŠธ๋ผ์ด(Trie)๋ž€? ํšจ์œจ์ ์ธ ๋ฌธ์ž์—ด ์ €์žฅ ๋ฐ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ๋งŒ๋“  ์ž๋ฃŒ๊ตฌ์กฐ ํ˜•ํƒœ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์ฝ”๋”ฉ์„ ํ•˜๋‹ค ๋ณด๋ฉด ์ˆ˜๋งŽ์€ ๋ฌธ

cdragon.tistory.com

1. ํŠธ๋ผ์ด(Trie)๋ž€?

์›ํ•˜๋Š” ์š”์†Œ๋ฅผ ์ฐพ๊ธฐ์œ„ํ•ด ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ์ด์ง„ ๊ฒ€์ƒ‰ ํŠธ๋ฆฌ ๋“ฑ์—์„œ๋Š” ํƒ€๊ฒŸ ์š”์†Œ๋ฅผ ์ฐพ๋Š”๋ฐ์— O(logN)์˜ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ๋ฌธ์ž์—ด์˜ ๊ฒฝ์šฐ ๋‘ ๋ฌธ์ž์—ด์„ ๋น„๊ตํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฌธ์ž์—ด์˜ ๊ธธ์ด๋งŒํผ์˜ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์—,
์›ํ•˜๋Š” ๋ฌธ์ž์—ด์„ ์ฐพ๊ธฐ ์œ„ํ•ด์„œ๋Š” O(MlogN)์˜ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ์ด ์ž‘์—…์„ ์—ฌ๋Ÿฌ๋ฒˆ ์ˆ˜ํ–‰ํ•œ๋‹ค๋ฉด ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 
์ด๋Ÿฌํ•œ ๋ฌธ์ž์—ด ๊ฒ€์ƒ‰์‹œ์˜ ๋‹จ์ ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋‚˜์˜จ ์ž๋ฃŒ๊ตฌ์กฐ๊ฐ€ ํŠธ๋ผ์ด(Trie)์ž…๋‹ˆ๋‹ค.

 

  • ํŠธ๋ผ์ด(Trie)๋Š” ๋ฌธ์ž์—ด์„ ์ €์žฅํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ํƒ์ƒ‰ํ•˜๊ธฐ ์œ„ํ•œ ํŠธ๋ฆฌ ํ˜•ํƒœ์˜ ์ž๋ฃŒ๊ตฌ์กฐ
  • ๊ตฌ๊ธ€์ด๋‚˜ ๋„ค์ด๋ฒ„ ๋“ฑ์— ๊ฒ€์ƒ‰์–ด๋ฅผ ๊ฒ€์ƒ‰ํ•  ๋•Œ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์ž๋™์™„์„ฑ ๊ธฐ๋Šฅ, ์‚ฌ์ „ ๊ฒ€์ƒ‰ ๋“ฑ ๋ฌธ์ž์—ด์„ ํƒ์ƒ‰ํ•˜๋Š”๋ฐ ํŠนํ™”๋˜์–ด์žˆ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ž˜๋”•์Šค ํŠธ๋ฆฌ(Radix Tree)๋‚˜ ์ ‘๋‘์‚ฌ ํŠธ๋ฆฌ(Prefix Tree), ํƒ์ƒ‰ ํŠธ๋ฆฌ(Retrieval Tree)๋ผ๊ณ ๋„ ํ•ฉ๋‹ˆ๋‹ค
    • ํŠธ๋ผ์ด(Trie)๋Š” Retrieval Tree์—์„œ ๋‚˜์˜จ ๋‹จ์–ด

์˜ˆ๋ฅผ ๋“ค์–ด 'Tistory'๋ผ๋Š” ๋‹จ์–ด๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•ด ์ œ์ผ ๋จผ์ € 'T'๋ฅผ ์ฐพ๊ณ , ๋‹ค์Œ์— 'i', 's', 't', ... ์˜ ์ˆœ๋Œ€๋กœ ์ฐพ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฐ ๊ฐœ๋…์„ ์ ์šฉํ•œ ์ž๋ฃŒ๊ตฌ์กฐ๊ฐ€ ํŠธ๋ผ์ด(Trie)์ž…๋‹ˆ๋‹ค.

 

2. ํŠธ๋ผ์ด(Trie)์˜ ์ž‘๋™ ์›๋ฆฌ

๋‹ค์Œ ๊ทธ๋ฆผ์€ ๋ฌธ์ž์—ด ์ง‘ํ•ฉ {"apple", "app", "dad", "dream", "age"}๋ฅผ ํŠธ๋ผ์ด๋กœ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

*ํŠธ๋ผ์ด(Trie)๋Š” ์ง‘ํ•ฉ์— ํฌํ•จ๋œ ๋ฌธ์ž์—ด์˜ ์ ‘๋‘์‚ฌ๋“ค์— ๋Œ€์‘๋˜๋Š” ๋…ธ๋“œ๋“ค์ด ์„œ๋กœ ์—ฐ๊ฒฐ๋œ ํŠธ๋ฆฌ์ž…๋‹ˆ๋‹ค.

 

[๊ณตํ†ต ์ ‘๋‘์–ด]

"apple"๊ณผ "app"์€ "app"๋ผ๋Š” ๊ณตํ†ต ์ ‘๋‘์–ด๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ๊ฐ™์€ ์„œ๋ธŒ ํŠธ๋ฆฌ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

์ฆ‰, "a"๋ผ๋Š” ๊ณตํ†ต ์ ‘๋‘์–ด๋ฅผ ๊ฐ€์ง„ "apple", "app", "age"๋Š” Head์˜ ์ž์‹ ๋…ธ๋“œ 'a'์—,

"d"๋ผ๋Š” ๊ณตํ†ต ์ ‘๋‘์–ด๋ฅผ ๊ฐ€์ง„ "dad", "dream"์€ Head์˜ ์ž์‹ ๋…ธ๋“œ 'd'์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

 

[Leaf Node]

๋ฆฌํ”„ ๋…ธ๋“œ๋Š” ๊ฐ ๋‹จ์–ด์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž๋ฅผ ์˜๋ฏธํ•˜๋ฏ€๋กœ, ๋‹จ์–ด์˜ ๋ ๋ฌธ์ž๋ผ๋Š” ํ‘œ์‹œ(endOfWord)๋ฅผ ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ๋ฆฌํ”„ ๋…ธ๋“œ์˜ ๊ฐœ์ˆ˜๋Š” ๋‹จ์–ด์˜ ๊ฐœ์ˆ˜๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

 

[ํŠธ๋ผ์ด(Trie) ์ƒ์„ฑ ๊ณผ์ •]

1. "apple"๋ฅผ ํŠธ๋ผ์ด์— ์‚ฝ์ž…

  • 'a': ์ฒซ๋ฒˆ์งธ ๋ฌธ์ž์ธ 'a'๋Š” ์ดˆ๊ธฐ์— ํŠธ๋ผ์ด ์ž๋ฃŒ๊ตฌ์กฐ ๋‚ด์— ์•„๋ฌด๊ฒƒ๋„ ์—†์œผ๋ฏ€๋กœ Head์˜ ์ž์‹๋…ธ๋“œ์— 'a'๋ฅผ ์ถ”๊ฐ€
  • 'p': 'a' ๋…ธ๋“œ์—๋„ ํ˜„์žฌ ์ž์‹์ด ํ•˜๋‚˜๋„ ์—†์œผ๋ฏ€๋กœ 'a'์˜ ์ž์‹๋…ธ๋“œ์— 'p'๋ฅผ ์ถ”๊ฐ€
  • 'p', 'l', 'e'์— ๋Œ€ํ•ด์„œ๋„ ์ž์‹๋…ธ๋“œ๋กœ ์ถ”๊ฐ€
  • 'l': "apple" ๋‹จ์–ด๊ฐ€ ๋๋‚จ์„ ์•Œ๊ธฐ ์œ„ํ•ด 'l' ๋…ธ๋“œ์— ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ(endOfWord)์ž„์„ ํ‘œ์‹œ

2. "app"๋ฅผ ํŠธ๋ผ์ด์— ์‚ฝ์ž…

  • 'a': ํ˜„์žฌ Head์˜ ์ž์‹ ๋…ธ๋“œ๋กœ 'a'๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— 'a' ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ  ๊ธฐ์กด์— ์žˆ๋Š” 'a'๋…ธ๋“œ๋กœ ์ด๋™
  • 'p': 'p'๋„ 'a'์˜ ์ž์‹ ๋…ธ๋“œ๋กœ ์žˆ์œผ๋ฏ€๋กœ 'p'๋กœ ์ด๋™
  • 'p': 'p'๋„ 'a'์˜ ์ž์‹ ๋…ธ๋“œ๋กœ ์žˆ์œผ๋ฏ€๋กœ 'p'๋กœ ์ด๋™ํ•˜๋ฉด์„œ, 'p'๋…ธ๋“œ์— ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ์ž„์„ ํ‘œ์‹œ

3. "dad", "dream",  "age"๋ฅผ ํŠธ๋ผ์ด์— ์‚ฝ์ž…

  • "dad"์™€ "dream"์˜ ์ฒซ ๋ฌธ์ž์ธ 'd'๋Š” Head์˜ ์ž์‹ ๋…ธ๋“œ๋กœ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€ํ•ด์„œ, ๊ฐ ๋‹จ์–ด๋ณ„๋กœ ๋ฌธ์ž๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ถ”๊ฐ€
  • "age"๋Š” Head์˜ ์ž์‹ ๋…ธ๋“œ๋กœ 'a'๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—,
    • 'a'๋กœ ์ด๋™ => 'a'์˜ ์ž์‹ ๋…ธ๋“œ์— 'g'๊ฐ€ ์—†์œผ๋ฏ€๋กœ 'g'๋ฅผ ์ถ”๊ฐ€ => 'e'๋„ 'g'์˜ ์ž์‹ ๋…ธ๋“œ๋กœ ์ถ”๊ฐ€ํ•œ ํ›„ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ ํ‘œ์‹œ

 

3. ํŠธ๋ผ์ด(Trie) ๊ตฌํ˜„(Java)

๊ทธ๋Ÿผ ํŠธ๋ผ์ด๋ฅผ Java๋กœ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ?

๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” Map Interface๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

Map์˜ Key๊ฐ’์—๋Š” ๋‹จ์–ด๋ฅผ ์ด๋ฃจ๋Š” ๊ฐ๊ฐ์˜ ๋ฌธ์ž๋“ค์ด ๋“ค์–ด๊ฐ€๊ณ , Value์—๋Š” ์ž์‹ ๋…ธ๋“œ ํด๋ž˜์Šค๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

 

์ด์ œ ์ˆœ์ฐจ์ ์œผ๋กœ ์ž๋ฐ”๋กœ ๊ตฌํ˜„์„ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Node ํด๋ž˜์Šค ์ƒ์„ฑ

Node ํด๋ž˜์Šค๋Š” ํ•ด๋‹น ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ์ •๋ณด์™€ ๋‹จ์–ด์˜ ๋์ธ์ง€๋ฅผ ํŒ๋‹จํ•˜๋Š” ๋ณ€์ˆ˜๋กœ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

private class Node {
    HashMap<Character, Node> childNode = new HashMap<>(); // ์ž์‹ ๋…ธ๋“œ
    boolean endOfWord; // ๋‹จ์–ด์˜ ๋์ธ์ง€์— ๋Œ€ํ•œ ํ”Œ๋ž˜๊ทธ
}

 

ํŠธ๋ผ์ด(Trie) ์ž๋ฃŒ๊ตฌ์กฐ ํด๋ž˜์Šค ์ƒ์„ฑ

๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฃจํŠธ ๋…ธ๋“œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด ์ค๋‹ˆ๋‹ค.

*๋ฃจํŠธ ๋…ธ๋“œ๋Š” 1) ํ•ญ์ƒ ๋น„์–ด์žˆ๊ณ  2) ๋ฃจํŠธ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ๋Š” ๊ฐ ๋‹จ์–ด์˜ ์ฒซ ๊ธ€์ž์ž…๋‹ˆ๋‹ค.

public class Trie {
    private Node rootNode;
    Trie() {
        // Trie ์ƒ์„ฑ์‹œ ๋ฃจํŠธ ๋…ธ๋“œ๋Š” ๊ธฐ๋ณธ์œผ๋กœ ์ƒ์„ฑ
        rootNode = new Node(); // ๋ฃจํŠธ ๋…ธ๋“œ๋Š” ๋นˆ ๋…ธ๋“œ
    }
}

 

๊ธฐ๋ณธ ๋ฉ”์„œ๋“œ

1) ๋…ธ๋“œ ์ถ”๊ฐ€(insert)

์ž…๋ ฅ ๋ฐ›์€ ๋‹จ์–ด๋ฅผ ๋ฌธ์ž ์ˆœ๋Œ€๋กœ ํŠธ๋ฆฌ ๊ณ„์ธต ๊ตฌ์กฐ์˜ ์ž์‹ ๋…ธ๋“œ๋กœ ์ƒ์„ฑํ•ด์„œ ๋„ฃ์Šต๋‹ˆ๋‹ค.

  • ๋ฌธ์ž๊ฐ€ ์ž์‹ ๋…ธ๋“œ์— ์กด์žฌํ•˜๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ์ž์‹ ๋…ธ๋“œ๋กœ ์ด๋™
  • ๋‹จ์–ด์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž์ธ ๋…ธ๋“œ๋ผ๋ฉด endOfWord = true๋กœ ์„ค์ •
public void insert(String word) {
    Node node = this.rootNode;
    // ๋‹จ์–ด์˜ ๋ฌธ์ž๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ ์ž์‹ ๋…ธ๋“œ๋ฅผ ํ™•์ธ
    //  1) ์ž์‹ ๋…ธ๋“œ์— ์žˆ๋Š” ๋ฌธ์ž๋ผ๋ฉด ์ž์‹ ๋…ธ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ด
    //  2) ์ž์‹ ๋…ธ๋“œ์— ์—†๋Š” ๋ฌธ์ž๋ผ๋ฉด ์ƒˆ๋กญ๊ฒŒ ์ƒ์„ฑ
    for (int i=0; i<word.length(); i++) node = node.childNode.computeIfAbsent(word.charAt(i), key -> new Node());
    node.endOfWord = true; // ๋‹จ์–ด(word)์˜ ๋ฌธ์ž๋ฅผ ๋ชจ๋‘ ์ˆœํšŒํ•˜๋ฉด ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋Š” ๋ฆฌํ”„ ๋…ธ๋“œ(=๋งˆ์ง€๋ง‰ ๋ฌธ์ž)์ด๊ธฐ๋•Œ๋ฌธ์— endOfWord๋ฅผ true๋กœ ์„ค์ •
}

 

2) ํฌํ•จ ์—ฌ๋ถ€ ํ™•์ธ(contains)

ํŠน์ • ๋‹จ์–ด๊ฐ€ ํŠธ๋ผ์ด์— ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

  • ๋ฃจํŠธ ๋…ธ๋“œ๋ถ€ํ„ฐ ๋‹จ์–ด์˜ ๋ฌธ์ž ์ˆœ๋Œ€๋กœ ์ผ์น˜ํ•˜๋Š” ์ž์‹ ๋…ธ๋“œ๊ฐ€ ๊ณ„์ธต์„ ์ด๋ฃจ๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธ
  • ๋‹จ์–ด์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž์— endOfWord๊ฐ€ true

๋‘ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ํŠธ๋ผ์ด์— ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

public boolean contains(String word) {
    Node node = this.rootNode;
    char c;
    for (int i=0; i<word.length(); i++) {
        c = word.charAt(i);
        if (!node.childNode.containsKey(c)) return false; // ํ˜„์žฌ ํƒ์ƒ‰ํ•˜๋Š” ๋ฌธ์ž๊ฐ€ ์ž์‹ ๋…ธ๋“œ์— ์—†๋‹ค๋ฉด ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋‹จ์–ด
        node = node.childNode.get(c); // ๋งˆ์ง€๋ง‰ ๋ฌธ์ž๋ฅผ node์— ์ €์žฅ
    }
    return node.endOfWord; // ๋งˆ์ง€๋ง‰ ๋ฌธ์ž ์—ฌ๋ถ€๋ฅผ ๋ฐ˜ํ™˜
}

 

3) ๋…ธ๋“œ ์‚ญ์ œ(delete)

ํŠธ๋ผ์ด์— ์ถ”๊ฐ€ํ–ˆ๋˜ ๋‹จ์–ด๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.

  • ๋ถ€๋ชจ ๋…ธ๋“œ์— ๋Œ€ํ•œ ์ •๋ณด๋Š” ์—†๊ธฐ ๋•Œ๋ฌธ์— ์‚ญ์ œํ•  ๋‹จ์–ด์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž๊นŒ์ง€ ์ด๋™ํ•ด์„œ ๋ฌธ์ž๋ฅผ ์‚ญ์ œํ•ด์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค. => ์žฌ๊ท€
  • ๋‹ค์Œ ๋ฌธ์ž์— ์กด์žฌํ•˜๋Š” ์ž์‹๋…ธ๋“œ๊ฐ€ ์žˆ๊ณ , ์‚ญ์ œ๋ฅผ ์‹œ์ž‘ํ•˜๋Š” ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ(๋ฆฌํ”„ ๋…ธ๋“œ)์—๋Š” endOfWord๊ฐ€ true๋กœ ๋˜์–ด์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 
    • ์ฆ‰, ์‚ญ์ œํ•  ๋‹จ์–ด๊ฐ€ ํŠธ๋ผ์ด์— ํฌํ•จ๋˜์–ด์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋‹จ์–ด ์‚ญ์ œ๋ฅผ ์œ„ํ•ด ๋งˆ์ง€๋ง‰ ๋ฌธ์ž ๋…ธ๋“œ์ธ ๋ฆฌํ”„ ๋…ธ๋“œ์˜ endOfWord๋ฅผ false๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ ์ˆœ์ฐจ์ ์œผ๋กœ ๊ฑฐ๊พธ๋กœ ์˜ฌ๋ผ๊ฐ€๋ฉด์„œ ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค. ๋‹จ, ์•„๋ž˜ ๋‘ ์กฐ๊ฑด์ด ์•„๋‹Œ ๊ฒฝ์šฐ์—๋งŒ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.
    • ํ•ด๋‹น ๋…ธ๋“œ์˜ ์ž์‹๋…ธ๋“œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ
      • ์ž์‹๋…ธ๋“œ๊ฐ€ ์žˆ๋‹ค๋Š” ๋œป์€ ๋‹ค๋ฅธ ๋‹จ์–ด์— ์‚ฌ์šฉ๋˜๋Š” ๋ฌธ์ž๋ผ๋Š” ๋œป์ด๋ฏ€๋กœ ์‚ญ์ œํ•˜๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค.
    • endOfWord๊ฐ€ true์ธ ๊ฒฝ์šฐ
      • ๋‹จ์–ด์˜ ๋์ธ ๋ฌธ์ž์ธ ๊ฒฝ์šฐ ๋‹ค๋ฅธ ๋‹จ์–ด์— ์‚ฌ์šฉ๋˜๋Š” ๋ฌธ์ž๋ผ๋Š” ๋œป์ด๋ฏ€๋กœ ์‚ญ์ œํ•˜๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค.
public void delete(String word) {
    delete(this.rootNode, word, 0);
}
// ์žฌ๊ท€ ํ˜ธ์ถœ์„ ์œ„ํ•œ ํ•จ์ˆ˜ ์˜ค๋ฒ„๋กœ๋”ฉ
private void delete(Node node, String word, int idx) {
    // ๋‹จ์–ด์˜ ๋งˆ์ง€๋ง‰ ์ธ๋ฑ์Šค์ธ ๊ฒฝ์šฐ
    if (idx == word.length()) {
        if (!node.endOfWord) throw new Error(word + " not exist"); // ๋‹จ์–ด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Œ
        node.endOfWord = false; // ๋‹จ์–ด์˜ ๋ ๋ฌธ์ž ํ‘œ์‹œ๋ฅผ false๋กœ ๋ณ€๊ฒฝ: ํ•ด๋‹น ๋ฌธ์ž ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•˜๊ธฐ ์œ„ํ•จ
        return; // ๋ฆฌํ”„ ๋…ธ๋“œ์˜ ๋ถ€๋ชจ ๋…ธ๋“œ๋กœ return
    }
    char c = word.charAt(idx); // ํ˜„์žฌ ํ™•์ธํ•ด์•ผํ•˜๋Š” ๋ฌธ์ž
    if (!node.childNode.containsKey(c)) throw new Error(word + " not exist"); // ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ(=๋‹จ์–ด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ)
    Node child = node.childNode.get(c); // ์ž์‹ ๋…ธ๋“œ ๊ฐ€์ ธ์˜ค๊ธฐ
    // ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด ๋ฆฌํ”„ ๋…ธ๋“œ๊นŒ์ง€ ๋‚ด๋ ค๊ฐ€์•ผ ํ•˜๋ฏ€๋กœ ์žฌ๊ท€ ํ˜ธ์ถœ
    delete(child, word, idx+1);
    // ํ˜„ ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ๋ฆฌํ”„ ๋…ธ๋“œ์ด๊ณ (=์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†์Œ), ๋‹จ์–ด์˜ ๋์ธ ๋ฌธ์ž๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ์‚ญ์ œ
    if (child.childNode.isEmpty() && !child.endOfWord) node.childNode.remove(c, child);
}

 

๐Ÿงช ๊ตฌํ˜„ ํ…Œ์ŠคํŠธ

public static void main(String[] args) {
        Trie trie = new Trie();
        // insert
        String[] arr = {"apple", "app", "dream", "dad", "age"};
        for (String word: arr) {
            trie.insert(word);
        }
        // delete
        trie.delete("app");
        trie.delete("dream");
        // contains
        System.out.println(trie.contains("apple")); // true
        System.out.println(trie.contains("app")); // ์‚ญ์ œํ–ˆ์œผ๋ฏ€๋กœ false
        System.out.println(trie.contains("age")); // true
        System.out.println(trie.contains("dream")); // ์‚ญ์ œํ–ˆ์œผ๋ฏ€๋กœ false
        System.out.println(trie.contains("dad")); // true
}

 

์œ„์—์„œ ์˜ˆ์‹œ๋กœ ๋“ค์—ˆ๋˜ ๋ฌธ์ž์—ด ๋ฐฐ์—ด์„ ๊ธฐ์ค€์œผ๋กœ ํŠธ๋ผ์ด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‚ญ์ œ, ํฌํ•จ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ’ก ์ „์ฒด ์ฝ”๋“œ๋Š” ์•„๋ž˜ ๋งํฌ์—์„œ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

 

Algorithm/src/Trie.java at main · hywnj/Algorithm

Contribute to hywnj/Algorithm development by creating an account on GitHub.

github.com

 

4. ํŠธ๋ผ์ด(Trie) ์‹œ๊ฐ„ ๋ณต์žก๋„

์ด ๋ฌธ์ž์˜ ๊ฐœ์ˆ˜๋ฅผ N, ๊ฐ€์žฅ ๊ธด ๋ฌธ์ž์—ด์˜ ๊ธธ์ด๊ฐ€ L์ด๋ผ๊ณ  ํ• ๋•Œ

  • ์ƒ์„ฑ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(N*L)
    • ๋ชจ๋“  ๋ฌธ์ž์—ด N๊ฐœ๋ฅผ ๋„ฃ์–ด์•ผํ•˜๊ณ , N๊ฐœ์— ๋Œ€ํ•ด ํŠธ๋ผ์ด์— ๋„ฃ๋Š” ๊ฑด ๊ฐ€์žฅ ๊ธด ๋ฌธ์ž์—ด ๊ธธ์ด์ธ L๋งŒํผ ๊ฑธ๋ฆฐ๋‹ค.
    • ์‚ฝ์ž…์€ O(L)๋งŒ ์†Œ์š”
  • ํƒ์ƒ‰ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(L)
    • ํŠธ๋ฆฌ๋ฅผ ๊ฐ€์žฅ ๊นŠ๊ฒŒ ํƒ์ƒ‰ํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ๊ฐ€์žฅ ๊ธด ๋ฌธ์ž์—ด ๊ธธ์ด์ธ L๊นŒ์ง€ ๋“ค์–ด๊ฐ€๋Š” ๊ฒƒ์ด๋ฏ€๋กœ O(L)

 

5. ํŠธ๋ผ์ด(Trie) ์žฅ๋‹จ์ 

  • ๋ฌธ์ž์—ด์— ๋Œ€ํ•œ ๊ฒ€์ƒ‰์„ ๋น ๋ฅด๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ๋ฌธ์ž์—ด์„ ์ง‘ํ•ฉ์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ๋ฌธ์ž์—ด์˜ ๊ธธ์ด๋งŒํผ ๋…ธ๋“œ๋ฅผ ๋”ฐ๋ผ๊ฐ€๊ฑฐ๋‚˜ ์ถ”๊ฐ€ํ•˜๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ž์—ด์˜ ์ถ”๊ฐ€์™€ ํƒ์ƒ‰ ๋ชจ๋‘ O(M)๋งŒ์— ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ํ•„์š”๋กœ ํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ์˜ ํฌ๊ธฐ๊ฐ€ ๋„ˆ๋ฌด ํฌ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
    • ๊ฐ ๋…ธ๋“œ์—์„œ ์ž์‹๋“ค์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ๋“ค์„ ๋ฐฐ์—ด๋กœ ๋ชจ๋‘ ์ €์žฅํ•˜๊ณ  ์žˆ๊ธฐ์— ์ €์žฅ๊ณต๊ฐ„์˜ ํฌ๊ธฐ๊ฐ€ ํฌ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
    • ๋ฌธ์ž์—ด์ด ๋ชจ๋‘ ์˜์†Œ๋ฌธ์ž๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์–ด๋„, ์ž์‹ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” 26๊ฐœ์˜ ํฌ์ธํ„ฐ๋ฅผ ์ €์ •ํ•ด์•ผํ•˜๋Š”๋ฐ
    • ์ตœ์•…์˜ ๊ฒฝ์šฐ์—๋Š” ์ง‘ํ•ฉ์— ํฌํ•จ๋˜๋Š” ๋ฌธ์ž์—ด์˜ ๊ธธ์ด์˜ ์ด ํ•ฉ๋งŒํผ์˜ ๋…ธ๋“œ๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ฉ”๋ชจ๋ฆฌ๋Š” O(ํฌ์ธํ„ฐ ํฌ๊ธฐ*ํฌ์ธํ„ฐ ๋ฐฐ์—ด ๊ฐœ์ˆ˜*์ด ๋…ธ๋“œ ๊ฐœ์ˆ˜)๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
      • ๋งŒ์•ฝ 1,000์ž๋ฆฌ์˜ ๋ฌธ์ž์—ด์ด 1,000๋งŒ๊ฐœ๊ฐ€ ์žˆ๋‹ค๋ฉด ์ด๋•Œ, 100๋งŒ๊ฐœ์˜ ๋…ธ๋“œ๊ฐ€ ํ•„์š”ํ•˜๊ณ  ํฌ์ธํ„ฐ์˜ ํฌ๊ธฐ๊ฐ€ 8Byte๋ผ ํ•˜๋ฉด ์•ฝ 200MB์˜ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

ํŠธ๋ผ์ด(Trie) ๋‹จ์  ํ•ด๊ฒฐ์„ ์œ„ํ•œ ๋ฐฉ๋ฒ•

'๋ฉ”๋ชจ๋ฆฌ์˜ ํฌ๊ธฐ๊ฐ€ ๋„ˆ๋ฌด ํฐ' ๋‹จ์ ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด, ๋ณดํ†ต map์ด๋‚˜ vector๋ฅผ ์ด์šฉํ•ด์„œ ํ•„์š”ํ•œ ๋…ธ๋“œ๋งŒ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Š” ๋ฉ”๋ชจ๋ฆฌ ์ œํ•œ์ด ํƒ€์ดํŠธํ•œ ๊ฒฝ์šฐ์—๋Š” ์ตœ์ ํ™”๊ฐ€ ๊นŒ๋‹ค๋กญ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ๋ฌธ์ œ์—์„œ ์ฃผ์–ด์ง„ ์กฐ๊ฑด์„ ๋ณด๊ณ  ํŠธ๋ผ์ด๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ์ธ์ง€ ํŒŒ์•…ํ•˜๋Š” ๊ฒƒ๋„ ์ค‘์š”ํ•˜๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

6. ํŠธ๋ผ์ด(Trie) ์ฝ”๋”ฉํ…Œ์ŠคํŠธ ๋ฌธ์ œ

 

์ฐธ๊ณ ํ•œ ๋งํฌ

๋„คํŠธ์›Œํฌ๋ฅผ ๊ณต๋ถ€ํ•˜๋ฉด ํ•„์ˆ˜๋กœ ์•Œ์•„์•ผํ•˜๋Š” ๊ฐœ๋…๋“ค์— ๋Œ€ํ•ด ๊ณต๋ถ€ํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.


๋„คํŠธ์›Œํฌ(Network)

๋„คํŠธ์›Œํฌ(Network)๋ž€ ๋…ธ๋“œ(Node)์™€ ๋งํฌ(Link)๊ฐ€ ์„œ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์œผ๋ฉฐ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ณต์œ ํ•˜๋Š” ์ง‘ํ•ฉ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  • ๋…ธ๋“œ: ์„œ๋ฒ„, ๋ผ์šฐํ„ฐ, ์Šค์œ„์น˜ ๋“ฑ์˜ ๋„คํŠธ์›Œํฌ ์žฅ์น˜
  • ๋งํฌ(=Edge): ์œ ์„  ๋˜๋Š” ๋ฌด์„ ๊ณผ ๊ฐ™์€ ์—ฐ๊ฒฐ๋งค์ฒด๋กœ, ์™€์ดํŒŒ์ด๋‚˜ LAN


ํŠธ๋ž˜ํ”ฝ(Traffic)

ํŠธ๋ž˜ํ”ฝ(Traffic)์€ ํŠน์ • ์‹œ์ ์— ๋งํฌ ๋‚ด์— ํ๋ฅด๋Š” ๋ฐ์ดํ„ฐ์˜ ์–‘, ์„œ๋ฒ„๋ฅผ ํ†ตํ•ด ์ตœ์ข… ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌ๋œ ๋ฐ์ดํ„ฐ์˜ ์–‘์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  • ex. ์„œ๋ฒ„์— ์ €์žฅ๋œ ํŒŒ์ผ(๋ฌธ์„œ, ์ด๋ฏธ์ง€ ๋“ฑ)์„ ํด๋ผ์ด์–ธํŠธ(์‚ฌ์šฉ์ž)๊ฐ€ ๋‹ค์šด๋กœ๋“œ์‹œ ๋ฐœ์ƒ๋˜๋Š” ๋ฐ์ดํ„ฐ์˜ ๋ˆ„์ ๋Ÿ‰
  • ๋‹จ์œ„: bps(bits per seconds)

ํŠธ๋ž˜ํ”ฝ ๊ณ„์‚ฐ

ํŠธ๋ž˜ํ”ฝ = ์šฉ๋Ÿ‰ * ์‚ฌ์šฉ์ž ์ˆ˜

 

Q. 4GB ์˜ํ™”๋ฅผ 10๋ช…์ด ๋‹ค์šด๋กœ๋“œ ๋ฐ›์„๋•Œ์˜ ํŠธ๋ž˜ํ”ฝ์€?

  • 4GB * 10๋ช… = 40GB

์ฒ˜๋ฆฌ๋Ÿ‰(Throughput)

์ฒ˜๋ฆฌ๋Ÿ‰(Throughput)์€ ๋งํฌ ๋‚ด์—์„œ ์„ฑ๊ณต์ ์œผ๋กœ ์ „๋‹ฌ๋œ ๋ฐ์ดํ„ฐ์˜ ์–‘์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๋ณดํ†ต ํŠธ๋ž˜ํ”ฝ ์ฒ˜๋ฆฌ๋Ÿ‰์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ๋งŽ์€ ํŠธ๋ž˜ํ”ฝ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค = ๋งŽ์€ ์ฒ˜๋ฆฌ๋Ÿ‰์„ ๊ฐ€์ง„๋‹ค๋Š” ์˜๋ฏธ์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๋‹จ์œ„: bps(bits per seconds) ์ดˆ๋‹น ์ „์†ก ๋˜๋Š” ์ˆ˜์‹ ๋˜๋Š” ๋น„ํŠธ์ˆ˜

์ฒ˜๋ฆฌ๋Ÿ‰์€ ์‚ฌ์šฉ์ž๋“ค์ด ๋งŽ์ด ์ ‘์†ํ• ๋•Œ๋งˆ๋‹ค ์ปค์ง€๋Š” ํŠธ๋ž˜ํ”ฝ, ๋„คํŠธ์›Œํฌ ์žฅ์น˜๊ฐ„์˜ ๋Œ€์—ญํญ, ๋„คํŠธ์›Œํฌ ์ค‘๊ฐ„์— ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ, ์žฅ์น˜์˜ ํ•˜๋“œ์›จ์–ด ์ŠคํŽ™์— ์˜ํ–ฅ์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.

 

๐Ÿ’ก ํŠธ๋ž˜ํ”ฝ๊ณผ ์ฒ˜๋ฆฌ๋Ÿ‰์€ ํ—ท๊ฐˆ๋ฆด ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ ‡๊ฒŒ ์ดํ•ดํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

  • "ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ์•„์กŒ๋‹ค" = ํ๋ฅด๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์•„์กŒ๋‹ค.
  • "์ฒ˜๋ฆฌ๋Ÿ‰์ด ๋งŽ์•„์กŒ๋‹ค" = ์ฒ˜๋ฆฌ๋˜๋Š” ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ์•„์กŒ๋‹ค.

๋Œ€์—ญํญ(Bandwidth)

๋Œ€์—ญํญ(Bandwidth)์€ ์ฃผ์–ด์ง„ ์‹œ๊ฐ„ ๋™์•ˆ ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ์„ ํ†ตํ•ด ํ๋ฅผ ์ˆ˜ ์žˆ๋Š” ์ตœ๋Œ€ ๋น„ํŠธ์ˆ˜์ด๋ฉฐ, ์ตœ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ํŠธ๋ž˜ํ”ฝ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  • ๋Œ€์—ญํญ์ด ๋†’์„์ˆ˜๋ก ์‚ฌ์šฉ์ž์—๊ฒŒ ๋น ๋ฅธ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณต
    • ex. ๊ณ ์†๋„๋กœ์˜ ์ฐจ์„ ์ด 2์ฐจ์„ ์ผ๋•Œ๋ณด๋‹ค 8์ฐจ์„ ์ผ ๋•Œ ๋”์šฑ ์›ํ™œํ•œ ๊ตํ†ต์ด ์ด๋ฃจ์–ด์ง
  • ๋Œ€๋žต์ ์ธ ์ตœ๋Œ€ ๋™์‹œ ์ ‘์†์ž ์ˆ˜๋ฅผ ์œ ์ถ”ํ•˜๋Š” ์ฒ™๋„
  • ๋‹จ์œ„: bps(bits per seconds) ์ดˆ๋‹น ์ „์†ก ๋˜๋Š” ์ˆ˜์‹ ๋˜๋Š” ๋น„ํŠธ์ˆ˜ (์ดˆ๋‹น bit๋‹จ์œ„์˜ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋Ÿ‰)

๋Œ€์—ญํญ ๊ณ„์‚ฐ

๋Œ€์—ญํญ(bps) = (์šฉ๋Ÿ‰ * ์‚ฌ์šฉ์ž์ˆ˜ * 8bits) / ์ฒ˜๋ฆฌ์‹œ๊ฐ„

  • bps ๊ณ„์‚ฐ์‹ = ๋ฐ์ดํ„ฐํฌ๊ธฐ(bits ๋‹จ์œ„) / ์†Œ์š”์‹œ๊ฐ„(์ดˆ ๋‹จ์œ„)
  • 8bits๋Š” Byte์—์„œ bit(๋Œ€์—ญํญ์˜ ๋‹จ์œ„๋Š” bps์ด๊ธฐ ๋•Œ๋ฌธ)๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ’ 

Q1. 20,000๋ช…์ด ํ™ˆํŽ˜์ด์ง€์— ์ ‘์†ํ• ๋•Œ ์ ‘์†์‹œ๋งˆ๋‹ค 4MB์˜ ์šฉ๋Ÿ‰์„ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์•„์•ผํ•˜๊ณ , ์ด ์š”์ฒญ์ด 10๋ถ„๋‚ด์— ์™„๋ฃŒ๋˜์–ด์•ผ ํ•  ๋•Œ, ๋Œ€์—ญํญ์€?

  • ํŠธ๋ž˜ํ”ฝ =  (20,000๋ช… * 4MB * 1๊ฐœ) = 80,000MB
  • ๋Œ€์—ญํญ = (20,000 * 4MB * 8 = 640,000) /  (10๋ถ„ * 60์ดˆ ) =1066Mbps = 1.066Gbps = ์•ฝ 1Gbps์˜ ๋Œ€์—ญํญ ํ•„์š”

Q2. 100Mbps ๋Œ€์—ญํญ์˜ ์„œ๋ฒ„๋กœ ํ•œ ์‚ฌ์šฉ์ž๋‹น 100kbps๋กœ ๋™์˜์ƒ ํŒŒ์ผ์„ ์š”์ฒญํ• ๋•Œ, ์ตœ๋Œ€ ๋™์ ‘์ž์ˆ˜๋Š”?

  • 100Mbps / 100kbps = ์•ฝ 1,000๋ช…

ํŠธ๋ž˜ํ”ฝ vs ์ฒ˜๋ฆฌ๋Ÿ‰ vs ๋Œ€์—ญํญ

ํŠธ๋ž˜ํ”ฝ์€ ํ๋ฅด๋ ค๋Š”, ์ด๋™ํ•˜๋ ค๋Š” ๋ฐ์ดํ„ฐ ์–‘์„ ์˜๋ฏธํ•˜๋ฉฐ, ์ด ํŠธ๋ž˜ํ”ฝ์„ ์ฒ˜๋ฆฌํ•  ๋•Œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ƒ๊ฐํ•˜๋ฉด ์ฒ˜๋ฆฌ๋Ÿ‰๊ณผ ๋Œ€์—ญํญ์„ ์‰ฝ๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋Œ€์—ญํญ : ๋„คํŠธ์›Œํฌ์˜ '๋„๋กœ ํญ'๊ณผ ๊ฐ™์œผ๋ฉฐ, ์ด '๋„๋กœ'๋ฅผ ํ†ตํ•ด ํ•œ ๋ฒˆ์— ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๋ฐ์ดํ„ฐ(ํŠธ๋ž˜ํ”ฝ)๊ฐ€ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  • ์ฒ˜๋ฆฌ๋Ÿ‰ : ํŠน์ • ์‹œ์ ์—์„œ '๋„๋กœ'๋ฅผ ํ†ต๊ณผํ•˜๋Š” ์ฐจ๋Ÿ‰์˜ ์ˆ˜์— ํ•ด๋‹นํ•˜๋ฉฐ, ๋‹ค์–‘ํ•œ ์š”์ธ์— ์˜ํ•ด ์˜ํ–ฅ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (๋„คํŠธ์›Œํฌ ํ˜ผ์žก, ํ•˜๋“œ์›จ์–ด ์ œํ•œ ๋“ฑ๊ณผ ๊ฐ™์€ ์™ธ๋ถ€ ์š”์ธ)

 

์ฐธ๊ณ  ๊ฐ•์˜ ๋ฐ ์‚ฌ์ดํŠธ

๋ฐฑ์—”๋“œ ์›น๊ฐœ๋ฐœ์ž๋กœ ์ผ์„ ํ•˜๋‹ค๊ฐ€ ์‹ ์ž… ๊ณต์ฑ„์‹œ์žฅ์— ๋›ฐ์–ด๋“ค๊ฒŒ ๋˜๋ฉด์„œ ์ „๊ณต์ง€์‹์„ ๋” ๊ณต๋ถ€ํ•ด์•ผ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์„ ํ•œ ํ›„ ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ–ˆ์–ด์š”. 

์ง์ ‘ ํ•„๊ธฐํ•˜๋ฉด์„œ ๊ณต๋ถ€ํ•˜๋Š” ๊ฒƒ๋„ ๋„์›€์ด ๋งŽ์ด ๋˜์ง€๋งŒ, ๋งค๋ฒˆ ์ฐพ์•„๋ดค๋˜๊ฑธ ๋‹ค์‹œ ๊ฒ€์ƒ‰ํ•˜๋Š”๊ฒŒ ์‹œ๊ฐ„์ด ๋” ๋“ค๊ธธ๋ž˜ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜์ค‘์— ํ™•์ธํ•  ์šฉ๋„์ด๊ธด ํ•˜์ง€๋งŒ, ํ˜น์‹œ ์ž˜๋ชป๋œ ๋ถ€๋ถ„์ด ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€๋กœ ์•Œ๋ ค์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค ๐Ÿ™‡๐Ÿป

*๊ณต๋ถ€ํ•˜๋ฉด์„œ ๊ณ„์† ์ถ”๊ฐ€ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

 

๐Ÿง‘‍๐Ÿซ ๊ฐ•์˜

 

+ Recent posts