๐Ÿ”ฅ ์ด์ง„ ํƒ์ƒ‰์œผ๋กœ ๋น ๋ฅด๊ฒŒ ํ‘ธ๋Š” ์ตœ์žฅ ์ฆ๊ฐ€ ๋ถ€๋ถ„ ์ˆ˜์—ด (LIS) ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋Œ€๊ณต๊ฐœ! ๐Ÿš€

๊น€์ƒ์šฑยท2024๋…„ 12์›” 15์ผ
0
post-thumbnail

์•ˆ๋…•ํ•˜์„ธ์š”, ์—ฌ๋Ÿฌ๋ถ„! ์˜ค๋Š˜์€ ์ตœ์žฅ ์ฆ๊ฐ€ ๋ถ€๋ถ„ ์ˆ˜์—ด(Longest Increasing Subsequence, LIS) ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ด์ง„ ํƒ์ƒ‰์„ ์ด์šฉํ•ด ํšจ์œจ์ ์œผ๋กœ ํ‘ธ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿง โœจ ์ดˆ๋ณด์ž๋„ ์‰ฝ๊ฒŒ ๋”ฐ๋ผ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋‚˜ํ•˜๋‚˜ ๋‹จ๊ณ„๋ณ„๋กœ ์„ค๋ช…๋“œ๋ฆด ํ…Œ๋‹ˆ ๋๊นŒ์ง€ ํ•จ๊ป˜ ํ•ด์ฃผ์„ธ์š”!


๐Ÿ“š LIS ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ž€?

์ตœ์žฅ ์ฆ๊ฐ€ ๋ถ€๋ถ„ ์ˆ˜์—ด(LIS)์€ ์ฃผ์–ด์ง„ ์ˆ˜์—ด์—์„œ ์ฆ๊ฐ€ํ•˜๋Š” ๋ถ€๋ถ„ ์ˆ˜์—ด ์ค‘ ๊ฐ€์žฅ ๊ธด ๊ฒƒ์„ ์ฐพ๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ˆ˜์—ด [10, 20, 10, 30, 20, 50]์˜ LIS๋Š” [10, 20, 30, 50]์œผ๋กœ ๊ธธ์ด๋Š” 4์ž…๋‹ˆ๋‹ค.


๐Ÿ›  ์ด์ง„ ํƒ์ƒ‰์„ ์ด์šฉํ•œ LIS ์•Œ๊ณ ๋ฆฌ์ฆ˜

์ด์ง„ ํƒ์ƒ‰์„ ํ™œ์šฉํ•˜๋ฉด LIS ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋ฅผ O(n log n)์œผ๋กœ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ๊ฐ€๋Šฅํ•œ์ง€ ํ•จ๊ป˜ ์•Œ์•„๋ณผ๊นŒ์š”?

1๏ธโƒฃ ์ดˆ๊ธฐํ™”

  • ๋นˆ tails ๋ฐฐ์—ด ์ƒ์„ฑ: ํ˜„์žฌ๊นŒ์ง€ ๊ฐ€๋Šฅํ•œ LIS์˜ ๋งˆ์ง€๋ง‰ ์›์†Œ๋“ค์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • tails_idx ๋ฐฐ์—ด ์ƒ์„ฑ: tails์— ์ €์žฅ๋œ ์›์†Œ๋“ค์ด ์›๋ž˜ ์ˆ˜์—ด์—์„œ ์–ด๋””์— ์œ„์น˜ํ•˜๋Š”์ง€ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.
  • prev_idx ๋ฐฐ์—ด ์ƒ์„ฑ: ๊ฐ ์›์†Œ์˜ ์ด์ „ ์›์†Œ์˜ ์ธ๋ฑ์Šค๋ฅผ ์ €์žฅํ•˜์—ฌ, ์ตœ์ข…์ ์œผ๋กœ ์ˆ˜์—ด์„ ์—ญ์ถ”์ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
import bisect

def lis(sequence):
    n = len(sequence)
    tails = []
    tails_idx = []
    prev_idx = [-1] * n

2๏ธโƒฃ ์ˆ˜์—ด ์ˆœํšŒ ๋ฐ ์—…๋ฐ์ดํŠธ

์ˆ˜์—ด์˜ ๊ฐ ์›์†Œ num๊ณผ ๊ทธ ์ธ๋ฑ์Šค i์— ๋Œ€ํ•ด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค:

  1. ์ด์ง„ ํƒ์ƒ‰์œผ๋กœ ์œ„์น˜ ์ฐพ๊ธฐ: pos = bisect.bisect_left(tails, num)
  2. tails ์—…๋ฐ์ดํŠธ:
    • pos๊ฐ€ tails์˜ ๊ธธ์ด์™€ ๊ฐ™์œผ๋ฉด num์„ tails์— ์ถ”๊ฐ€
    • ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด tails[pos]๋ฅผ num์œผ๋กœ ๋Œ€์ฒด
  3. ์ธ๋ฑ์Šค ๊ธฐ๋ก:
    • tails_idx[pos]๋ฅผ ํ˜„์žฌ ์ธ๋ฑ์Šค i๋กœ ์—…๋ฐ์ดํŠธ
    • prev_idx[i]๋Š” pos > 0์ผ ๋•Œ tails_idx[pos - 1]๋กœ ์„ค์ •
    for i in range(n):
        num = sequence[i]
        pos = bisect.bisect_left(tails, num)

        if pos == len(tails):
            tails.append(num)
            tails_idx.append(i)
        else:
            tails[pos] = num
            tails_idx[pos] = i

        if pos > 0:
            prev_idx[i] = tails_idx[pos - 1]

3๏ธโƒฃ LIS ์ˆ˜์—ด ๋ณต์›

tails_idx์˜ ๋งˆ์ง€๋ง‰ ์ธ๋ฑ์Šค๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ prev_idx๋ฅผ ๋”ฐ๋ผ๊ฐ€๋ฉฐ LIS ์ˆ˜์—ด์„ ๋ณต์›ํ•ฉ๋‹ˆ๋‹ค.

    lis_length = len(tails)

    lis_sequence = []
    k = tails_idx[-1] if tails_idx else -1
    while k != -1:
        lis_sequence.append(sequence[k])
        k = prev_idx[k]
    lis_sequence.reverse()

    return lis_length, lis_sequence

๐Ÿ’ก ์ „์ฒด ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ฝ”๋“œ

import bisect

def lis(sequence):
    n = len(sequence)
    tails = []
    tails_idx = []
    prev_idx = [-1] * n

    for i in range(n):
        num = sequence[i]
        pos = bisect.bisect_left(tails, num)

        if pos == len(tails):
            tails.append(num)
            tails_idx.append(i)
        else:
            tails[pos] = num
            tails_idx[pos] = i

        if pos > 0:
            prev_idx[i] = tails_idx[pos - 1]

    lis_length = len(tails)

    lis_sequence = []
    k = tails_idx[-1] if tails_idx else -1
    while k != -1:
        lis_sequence.append(sequence[k])
        k = prev_idx[k]
    lis_sequence.reverse()

    return lis_length, lis_sequence

# ๐Ÿ” ์˜ˆ์ œ ์‚ฌ์šฉ
sequence = [10, 20, 10, 30, 20, 50]
length, subsequence = lis(sequence)
print("LIS์˜ ๊ธธ์ด:", length)          # ์ถœ๋ ฅ: 4
print("LIS ์ˆ˜์—ด:", subsequence)      # ์ถœ๋ ฅ: [10, 20, 30, 50]

# ๐Ÿ“ˆ ์ถ”๊ฐ€ ์˜ˆ์ œ
sequence2 = [3, 10, 2, 1, 20]
length2, subsequence2 = lis(sequence2)
print("LIS์˜ ๊ธธ์ด:", length2)         # ์ถœ๋ ฅ: 3
print("LIS ์ˆ˜์—ด:", subsequence2)     # ์ถœ๋ ฅ: [3, 10, 20]

๐Ÿงฎ ์˜ˆ์ œ ๋ถ„์„: [10, 20, 10, 30, 20, 50]

์ดˆ๊ธฐ ์ƒํƒœ

tails: []
tails_idx: []
prev_idx: [-1, -1, -1, -1, -1, -1]

์—…๋ฐ์ดํŠธ ๊ณผ์ •

  1. 10 (i = 0):

    • tails: [10]
    • tails_idx: [0]
    • prev_idx: [-1, -1, -1, -1, -1, -1]
  2. 20 (i = 1):

    • tails: [10, 20]
    • tails_idx: [0, 1]
    • prev_idx: [-1, 0, -1, -1, -1, -1]
  3. 10 (i = 2):

    • tails: [10, 20]
    • tails_idx: [2, 1]
    • prev_idx: [-1, 0, -1, -1, -1, -1]
  4. 30 (i = 3):

    • tails: [10, 20, 30]
    • tails_idx: [2, 1, 3]
    • prev_idx: [-1, 0, -1, 1, -1, -1]
  5. 20 (i = 4):

    • tails: [10, 20, 30]
    • tails_idx: [2, 4, 3]
    • prev_idx: [-1, 0, -1, 1, 2, -1]
  6. 50 (i = 5):

    • tails: [10, 20, 30, 50]
    • tails_idx: [2, 4, 3, 5]
    • prev_idx: [-1, 0, -1, 1, 2, 3]

์ตœ์ข… ์ƒํƒœ

tails: [10, 20, 30, 50]
tails_idx: [2, 4, 3, 5]
prev_idx: [-1, 0, -1, 1, 2, 3]
  • LIS์˜ ๊ธธ์ด: 4
  • ๋ณต์›๋œ LIS ์ˆ˜์—ด: [10, 20, 30, 50]

๐ŸŽฏ ๊ฒฐ๋ก 

์ด์ง„ ํƒ์ƒ‰์„ ํ™œ์šฉํ•œ LIS ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ํšจ์œจ์ ์ด๊ณ  ์ง๊ด€์ ์ž…๋‹ˆ๋‹ค. tails ๋ฐฐ์—ด์„ ์œ ์ง€ํ•˜๋ฉฐ ๊ฐ€๋Šฅํ•œ ์ž‘์€ ๊ฐ’์œผ๋กœ LIS๋ฅผ ํ™•์žฅํ•จ์œผ๋กœ์จ ๋” ๊ธด LIS๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ๋ฅผ ๊ทน๋Œ€ํ™”ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, tails_idx์™€ prev_idx๋ฅผ ํ™œ์šฉํ•ด ์‹ค์ œ LIS ์ˆ˜์—ด์„ ๋ณต์›ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ํฌ์ŠคํŒ…์„ ํ†ตํ•ด O(n log n) ์‹œ๊ฐ„ ๋ณต์žก๋„๋กœ LIS๋ฅผ ๊ตฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ดํ•ดํ•˜์…จ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๐Ÿ’ช ๋‹ค์Œ์—๋„ ์œ ์šฉํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ๋‹ค์‹œ ์ฐพ์•„๋ต™๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๐Ÿ˜Š

0๊ฐœ์˜ ๋Œ“๊ธ€