Skip to content

[alphaorderly] WEEK 08 Solutions - #2810

Open
alphaorderly wants to merge 4 commits into
DaleStudy:mainfrom
alphaorderly:main
Open

[alphaorderly] WEEK 08 Solutions#2810
alphaorderly wants to merge 4 commits into
DaleStudy:mainfrom
alphaorderly:main

Conversation

@alphaorderly

@alphaorderly alphaorderly commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

๋‹ต์•ˆ ์ œ์ถœ ๋ฌธ์ œ

์ž‘์„ฑ์ž ์ฒดํฌ ๋ฆฌ์ŠคํŠธ

  • Projects์˜ ์˜ค๋ฅธ์ชฝ ๋ฒ„ํŠผ(โ–ผ)์„ ๋ˆŒ๋Ÿฌ ํ™•์žฅํ•œ ๋’ค, Week๋ฅผ ํ˜„์žฌ ์ฃผ์ฐจ๋กœ ์„ค์ •ํ•ด์ฃผ์„ธ์š”.
  • ๋ฌธ์ œ๋ฅผ ๋ชจ๋‘ ํ‘ธ์‹œ๋ฉด ํ”„๋กœ์ ํŠธ์—์„œ Status๋ฅผ In Review๋กœ ์„ค์ •ํ•ด์ฃผ์„ธ์š”.
  • ์ฝ”๋“œ ๊ฒ€ํ† ์ž 1๋ถ„ ์ด์ƒ์œผ๋กœ๋ถ€ํ„ฐ ์Šน์ธ์„ ๋ฐ›์œผ์…จ๋‹ค๋ฉด PR์„ ๋ณ‘ํ•ฉํ•ด์ฃผ์„ธ์š”.

๊ฒ€ํ† ์ž ์ฒดํฌ ๋ฆฌ์ŠคํŠธ

Important

๋ณธ์ธ ๋‹ต์•ˆ ์ œ์ถœ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋‹ค๋ฅธ ๋ถ„ PR ํ•˜๋‚˜ ์ด์ƒ์„ ๋ฐ˜๋“œ์‹œ ๊ฒ€ํ† ๋ฅผ ํ•ด์ฃผ์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค!

  • ๋ฐ”๋กœ ์ด์ „์— ์˜ฌ๋ผ์˜จ PR์— ๋ณธ์ธ์„ ์ฝ”๋“œ ๋ฆฌ๋ทฐ์–ด๋กœ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.
  • ๋ณธ์ธ์ด ๊ฒ€ํ† ํ•ด์•ผํ•˜๋Š” PR์˜ ๋‹ต์•ˆ ์ฝ”๋“œ์— ํ”ผ๋“œ๋ฐฑ์„ ์ฃผ์„ธ์š”.
  • ํ† ์š”์ผ ์ „๊นŒ์ง€ PR์„ ๋ณ‘ํ•ฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์Šน์ธํ•ด์ฃผ์„ธ์š”.

@dalestudy

dalestudy Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

๐Ÿ“Š alphaorderly ๋‹˜์˜ ํ•™์Šต ํ˜„ํ™ฉ

์ด๋ฒˆ ์ฃผ ์ œ์ถœ ๋ฌธ์ œ

๋ฌธ์ œ ๋‚œ์ด๋„ ์œ ํ˜• ๋ถ„์„
clone-graph Medium โœ… ์˜๋„ํ•œ ์œ ํ˜•
longest-common-subsequence Medium โœ… ์˜๋„ํ•œ ์œ ํ˜•
longest-repeating-character-replacement Medium โœ… ์˜๋„ํ•œ ์œ ํ˜•
palindromic-substrings Medium โœ… ์˜๋„ํ•œ ์œ ํ˜•
reverse-bits Easy โœ… ์˜๋„ํ•œ ์œ ํ˜•

๋ˆ„์  ํ•™์Šต ์š”์•ฝ

  • ํ’€์ดํ•œ ๋ฌธ์ œ: 35 / 75๊ฐœ
  • ์ด๋ฒˆ ์ฃผ ์œ ํ˜• ์ผ์น˜์œจ: 100% (5๋ฌธ์ œ ์ค‘ 5๋ฌธ์ œ ์ผ์น˜)

๋ฌธ์ œ ํ’€์ด ํ˜„ํ™ฉ

์นดํ…Œ๊ณ ๋ฆฌ ์ง„ํ–‰๋„ ์™„๋ฃŒ
Array โ– โ– โ– โ– โ– โ– โ–ก 8 / 10 (Medium 5, Easy 3)
Matrix โ– โ– โ– โ– โ– โ–กโ–ก 3 / 4 (Medium 3)
Dynamic Programming โ– โ– โ– โ– โ– โ–กโ–ก 8 / 11 (Easy 1, Medium 7)
String โ– โ– โ– โ– โ–กโ–กโ–ก 6 / 10 (Medium 3, Easy 3)
Linked List โ– โ– โ–กโ–กโ–กโ–กโ–ก 2 / 6 (Easy 2)
Heap โ– โ– โ–กโ–กโ–กโ–กโ–ก 1 / 3 (Medium 1)
Tree โ– โ– โ–กโ–กโ–กโ–กโ–ก 4 / 14 (Medium 3, Easy 1)
Graph โ– โ– โ–กโ–กโ–กโ–กโ–ก 2 / 8 (Medium 2)
Binary โ– โ–กโ–กโ–กโ–กโ–กโ–ก 1 / 5 (Easy 1)
Interval โ–กโ–กโ–กโ–กโ–กโ–กโ–ก 0 / 5 โ† ์•„์ง ์‹œ์ž‘ ์•ˆ ํ•จ

๐Ÿค– ์ด ๋Œ“๊ธ€์€ GitHub App์„ ํ†ตํ•ด ์ž๋™์œผ๋กœ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ”ข API ์‚ฌ์šฉ๋Ÿ‰ (gpt-5-nano)
์š”์ฒญ ์ž…๋ ฅ ํ† ํฐ ์ถœ๋ ฅ ํ† ํฐ ํ•ฉ๊ณ„ ๋น„์šฉ
1 3,252 212 3,464 $0.000247
2 3,482 197 3,679 $0.000253
3 3,466 184 3,650 $0.000247
4 3,466 235 3,701 $0.000267
5 3,466 246 3,712 $0.000272
6 3,466 201 3,667 $0.000254
ํ•ฉ๊ณ„ 20,598 1,275 21,873 $0.001540

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿท๏ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํŒจํ„ด ๋ถ„์„

clone-graph/alphaorderly.py
"""
์‹œ๊ฐ„๋ณต์žก๋„ : O(V + E)
๊ณต๊ฐ„๋ณต์žก๋„ : O(V)

1. made ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
2. copy_node ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•œ๋‹ค.
3. copy_node ํ•จ์ˆ˜๋Š” target ๋…ธ๋“œ๋ฅผ ๋ณต์‚ฌํ•œ ํ›„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
4. ์ด๋ฏธ ๋ณต์‚ฌํ•œ ๋…ธ๋“œ๋Š” made์—์„œ ์žฌ์‚ฌ์šฉํ•œ๋‹ค.
5. ๋ณต์‚ฌํ•œ ๋…ธ๋“œ์˜ ์ด์›ƒ๋“ค ๋˜ํ•œ copy_node๋ฅผ ์ด์šฉํ•ด ์žฌ๊ท€์ ์œผ๋กœ ๋ณต์‚ฌํ•œ๋‹ค.
6. ์ตœ์ข…์ ์œผ๋กœ ๋ณต์ œ๋œ ๊ทธ๋ž˜ํ”„์˜ ์‹œ์ž‘ ๋…ธ๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
"""
class Solution:
    def cloneGraph(self, node: Optional["Node"]) -> Optional["Node"]:

        made = dict()

        def copy_node(target: Node) -> Node:
            if not target:
                return None

            copied = Node(target.val)
            made[target.val] = copied

            for nei in target.neighbors:
                if nei.val in made:
                    copied.neighbors.append(made[nei.val])
                else:
                    copied.neighbors.append(copy_node(nei))

            return copied

        return copy_node(node)
  • ํŒจํ„ด: Depth-First Search, Hash Map / Hash Set
  • ์„ค๋ช…: ๊ทธ๋ž˜ํ”„์˜ ๊ฐ ๋…ธ๋“œ๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ๋ฐฉ๋ฌธํ•˜๋ฉฐ ์ด์›ƒ ๋…ธ๋“œ๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ๋ณต์ œํ•œ๋‹ค. ์ด๋ฏธ ๋ณต์ œ๋œ ๋…ธ๋“œ๋ฅผ ํ•ด์‹œ ๋งต์œผ๋กœ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ์ˆœํ™˜๊ณผ ์ค‘๋ณต ๋ฐฉ๋ฌธ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.

๐Ÿ“Š ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„ ๋ถ„์„

๋ณต์žก๋„
Time O(V + E)
Space O(V)

ํ”ผ๋“œ๋ฐฑ: ๊ฐ ๋…ธ๋“œ๋ฅผ ํ•œ ๋ฒˆ์”ฉ ๋ฐฉ๋ฌธํ•˜๊ณ  ์ด์›ƒ ๋…ธ๋“œ๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ๋ณต์ œํ•˜๋ฏ€๋กœ ์ „์ฒด ๊ทธ๋ž˜ํ”„์˜ ๋…ธ๋“œ ์ˆ˜์™€ ๊ฐ„์„  ์ˆ˜์— ๋น„๋ก€ํ•˜๋Š” ์‹œ๊ฐ„ ๋ณต์žก๋„์™€ ๋…ธ๋“œ ์ˆ˜์— ๋น„๋ก€ํ•˜๋Š” ์ถ”๊ฐ€ ๊ณต๊ฐ„์ด ํ•„์š”ํ•˜๋‹ค.

๊ฐœ์„  ์ œ์•ˆ: ํ˜„์žฌ ๊ตฌํ˜„์ด ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

๐Ÿ’ก ํ’€์ด์— ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„๋ฅผ ์ฃผ์„์œผ๋กœ ๋‚จ๊ฒจ๋ณด์„ธ์š”!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿท๏ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํŒจํ„ด ๋ถ„์„

longest-common-subsequence/alphaorderly.py
"""
์‹œ๊ฐ„๋ณต์žก๋„ : O(T1 * T2)
๊ณต๊ฐ„๋ณต์žก๋„ : O(T1) # T1์— ์งง์€ ๋ฌธ์ž์—ด์„ ์„ค์ •ํ–ˆ๊ธฐ์— ๊ณต๊ฐ„๋ณต์žก๋„๋Š” T1์ด ๋œ๋‹ค.

1. text1๊ณผ text2 ์ค‘ ๋” ์งง์€ ์ชฝ์„ text1์œผ๋กœ ์„ค์ •ํ•œ๋‹ค.
2. T1๊ณผ T2๋ฅผ ๊ฐ๊ฐ text1๊ณผ text2์˜ ๊ธธ์ด๋กœ ์„ค์ •ํ•œ๋‹ค.
3. dp ๋ฐฐ์—ด์„ T1 + 1 ํฌ๊ธฐ๋กœ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
4. text2์˜ ๊ฐ ๋ฌธ์ž(i)๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ ๋น„๊ตํ•œ๋‹ค.
5. new_dp ๋ฐฐ์—ด์„ T1 + 1 ํฌ๊ธฐ๋กœ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
6. text1์˜ ๊ฐ ๋ฌธ์ž(j)์— ๋Œ€ํ•ด ์ˆœํšŒํ•˜๋ฉด์„œ ๋น„๊ตํ•œ๋‹ค.
7. text2[i - 1]๊ณผ text1[j - 1]๊ฐ€ ๊ฐ™์œผ๋ฉด, new_dp[j]๋ฅผ dp[j - 1] + 1๋กœ ์„ค์ •ํ•œ๋‹ค.
8. ๋‹ค๋ฅด๋ฉด, new_dp[j]๋ฅผ max(new_dp[j - 1], dp[j])๋กœ ์„ค์ •ํ•œ๋‹ค.
9. dp๋ฅผ new_dp๋กœ ๊ฐฑ์‹ ํ•˜๊ณ , ๋งˆ์ง€๋ง‰ ์›์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
"""
class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        if len(text1) > len(text2):
            text1, text2 = text1, text2

        T1, T2 = len(text1), len(text2)
        dp = [0] * (T1 + 1)

        for i in range(1, T2 + 1):
            new_dp = [0] * (T1 + 1)

            for j in range(1, T1 + 1):
                if text2[i - 1] == text1[j - 1]:
                    new_dp[j] = dp[j - 1] + 1
                else:
                    new_dp[j] = max(new_dp[j - 1], dp[j])

            dp = new_dp

        return dp[-1]
  • ํŒจํ„ด: Dynamic Programming, Two Pointers
  • ์„ค๋ช…: ๋‘ ๋ฌธ์ž์—ด์˜ ๋ถ€๋ถ„์ˆ˜์—ด ๋ฌธ์ œ๋ฅผ DP๋กœ ํ•ด๊ฒฐํ•˜๋Š” ์ „ํ˜•์ ์ธ ํŒจํ„ด์œผ๋กœ, ๊ฐ ์œ„์น˜์˜ ๋ถ€๋ถ„๋ฌธ์ž์—ด ์กฐํ•ฉ์— ๋Œ€ํ•œ ์ตœ์žฅ ๊ณตํ†ต ๋ถ€๋ถ„์ˆ˜์—ด ๊ธธ์ด๋ฅผ ์ ์ง„์ ์œผ๋กœ ๊ณ„์‚ฐํ•œ๋‹ค. ๋˜ํ•œ ๊ธธ์ด๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ๋‘ ๋ฌธ์ž์—ด์— ๋Œ€ํ•ด ๊ฐ„์ ‘์ ์œผ๋กœ ๋‘ ํฌ์ธํ„ฐ์ฒ˜๋Ÿผ ์ธ๋ฑ์Šค ์ˆœํšŒ์™€ DP ๋ฐฐ์—ด ๊ฐฑ์‹ ์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.

๐Ÿ“Š ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„ ๋ถ„์„

๋ณต์žก๋„
Time O(T1 * T2)
Space O(T1)

ํ”ผ๋“œ๋ฐฑ: ๊ณต๊ฐ„์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ๋‘ ์—ด ๋ฐฐ์—ด์„ ๊ต์ฒดํ•˜๋ฉฐ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๋‘ ๋ฌธ์ž์—ด ๊ธธ์ด์˜ ๊ณฑ์ด๋‹ค.

๊ฐœ์„  ์ œ์•ˆ: ํ˜„์žฌ ๊ตฌํ˜„์ด ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

๐Ÿ’ก ํ’€์ด์— ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„๋ฅผ ์ฃผ์„์œผ๋กœ ๋‚จ๊ฒจ๋ณด์„ธ์š”!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿท๏ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํŒจํ„ด ๋ถ„์„

longest-repeating-character-replacement/alphaorderly.py
"""
์‹œ๊ฐ„๋ณต์žก๋„ : O(N)
๊ณต๊ฐ„๋ณต์žก๋„ : O(1)

1. freq ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
2. s์˜ ๊ฐ ๋ฌธ์ž(value)์— ๋Œ€ํ•ด ๋ฃจํ”„๋ฅผ ๋ˆ๋‹ค.
3. freq[value]๋ฅผ 1 ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.
4. maxima๋ฅผ ํ˜„์žฌ ์œˆ๋„์šฐ์—์„œ ๊ฐ€์žฅ ๋นˆ๋„๊ฐ€ ๋†’์€ ๋ฌธ์ž ๋นˆ๋„๋กœ ๊ฐฑ์‹ ํ•œ๋‹ค.
5. ์œˆ๋„์šฐ ํฌ๊ธฐ์—์„œ maxima์˜ ๊ฐ’๋งŒํผ์„ ๋บ€ ๊ฐ’์ด k๋ณด๋‹ค ํฌ๋ฉด,
6. freq[s[left]]๋ฅผ 1 ๊ฐ์†Œ์‹œํ‚ค๊ณ  left๋ฅผ 1 ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.
7. ans๋ฅผ ์œˆ๋„์šฐ์˜ ์ตœ๋Œ€ ๊ธธ์ด๋กœ ๊ฐฑ์‹ ํ•œ๋‹ค.
8. ๋งˆ์ง€๋ง‰์œผ๋กœ ans๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
"""
class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        freq = defaultdict(int)
        # maxima : ํ˜„์žฌ ์œˆ๋„์šฐ ๋‚ด์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ๋“ฑ์žฅํ•œ ๋ฌธ์ž์˜ ๋นˆ๋„์ˆ˜
        maxima = left = ans = 0

        for right, value in enumerate(s):
            freq[value] += 1
            maxima = max(maxima, freq[value])

            while (right - left + 1) - maxima > k:
                freq[s[left]] -= 1
                left += 1

            ans = max(ans, right - left + 1)

        return ans

"""
์‹œ๊ฐ„๋ณต์žก๋„ : O(log N)
๊ณต๊ฐ„๋ณต์žก๋„ : O(N)

### ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ๊ตฌํ˜„ ### (์œˆ๋„์šฐ ๋‚ด ์ „์ฒด๋งŒ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ query ๊ตฌํ˜„ ์—†์Œ)

#### ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ์›๋ฆฌ
- ๊ฐ ์•ŒํŒŒ๋ฒณ ๋นˆ๋„ ํ•ฉ๊ณผ ๋นˆ๋„๊ฐ€ ๊ฐ€์žฅ ๋†’์€ ๋ฌธ์ž์˜ ๋นˆ๋„๋ฅผ ์ €์žฅํ•˜๋Š” ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

#### ์ฝ”๋“œ ์„ค๋ช…
- window.update๋กœ ์•ŒํŒŒ๋ฒณ ๊ฐœ์ˆ˜๋ฅผ ๊ฐฑ์‹ ํ•˜๋ฉฐ,
- window.tree[1][0]์—์„œ ํ˜„์žฌ ์œˆ๋„์šฐ ๋‚ด ์ „์ฒด ๋ฌธ์ž ์ˆ˜,
- window.tree[1][1]์—์„œ ์œˆ๋„์šฐ ๋‚ด ๋“ฑ์žฅ ๋นˆ๋„๊ฐ€ ๊ฐ€์žฅ ๋†’์€ ๋ฌธ์ž์˜ ๊ฐœ์ˆ˜๋ฅผ ๊ตฌํ•œ๋‹ค.
- ์œˆ๋„์šฐ ํฌ๊ธฐ - ์ตœ๋Œ€ ๋นˆ๋„๊ฐ€ k๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด left๋ฅผ ์˜ฎ๊ธฐ๋ฉฐ ์œˆ๋„์šฐ๋ฅผ ์ค„์ธ๋‹ค.

> ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋ณต์žกํ•œ ๊ตฌํ˜„์ด์ง€๋งŒ, ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ๋ฅผ ๊ณต๋ถ€ํ•˜๊ธฐ์—” ์ข‹์€ ์˜ˆ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.
"""
class SegTree:
    def __init__(self):
        # [๋ฌธ์ž ๊ฐœ์ˆ˜ ํ•ฉ, ์ตœ๋Œ€๊ฐ’]
        self.tree = [[0, 0] for _ in range(26 * 4 + 1)]

    def _update(
        self,
        node_index: int,
        target_index: int,
        target_update: int,
        seg_left: int,
        seg_right: int,
    ):
        if seg_left == seg_right:
            self.tree[node_index][0] += target_update
            self.tree[node_index][1] += target_update
            return

        mid = (seg_left + seg_right) // 2

        if target_index <= mid:
            self._update(node_index * 2, target_index, target_update, seg_left, mid)
        else:
            self._update(
                node_index * 2 + 1, target_index, target_update, mid + 1, seg_right
            )

        self.tree[node_index][0] = (
            self.tree[node_index * 2][0] + self.tree[node_index * 2 + 1][0]
        )
        self.tree[node_index][1] = max(
            self.tree[node_index * 2][1], self.tree[node_index * 2 + 1][1]
        )

    def update(self, target: str, update: int):
        self._update(1, ord(target) - ord("A"), update, 0, 25)


class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        left = 0
        window = SegTree()
        ans = 0

        for right, value in enumerate(s):
            window.update(value, 1)

            while window.tree[1][0] > 0 and window.tree[1][0] - window.tree[1][1] > k:
                window.update(s[left], -1)
                left += 1

            ans = max(ans, right - left + 1)

        return ans
  • ํŒจํ„ด: Sliding Window, Greedy
  • ์„ค๋ช…: ์ฒซ ๋ฒˆ์งธ ๊ตฌํ˜„์€ ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ๋ฅผ ์ด์šฉํ•ด ๋ฌธ์ž ๋นˆ๋„ ์ฐจ์ด๋ฅผ k ์ดํ•˜๋กœ ์œ ์ง€ํ•˜๋ฉฐ ์œˆ๋„์šฐ ๊ธธ์ด๋ฅผ ํ™•์žฅํ•˜๋Š” ํŒจํ„ด์ด๊ณ , ๋‘ ๋ฒˆ์งธ ๊ตฌํ˜„๋„ ์œˆ๋„์šฐ ํฌ๊ธฐ๋ฅผ ์กฐ์ ˆํ•˜๋ฉฐ ์ตœ๋Œ€ ๋นˆ๋„์™€์˜ ์ฐจ์ด๊ฐ€ k๋ฅผ ๋„˜์ง€ ์•Š๋„๋ก ์™ผ์ชฝ ํฌ์ธํ„ฐ๋ฅผ ์ด๋™ํ•˜๋Š” ๊ทธ๋ฆฌ๋”” ์„ฑ๊ฒฉ์˜ ์ ‘๊ทผ์ด๋‹ค. ๋‘ ๋ฐฉ๋ฒ• ๋ชจ๋‘ ๋ฌธ์ž์—ด ๋‚ด ์ ์ ˆํ•œ ๋ถ€๋ถ„๋ฌธ์ž์—ด ๊ธธ์ด๋ฅผ ์ตœ์ ํ™”ํ•œ๋‹ค.

๐Ÿ“Š ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„ ๋ถ„์„

โ„น๏ธ ์ด ํŒŒ์ผ์—๋Š” 2๊ฐ€์ง€ ํ’€์ด๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์–ด ๊ฐ๊ฐ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค.

ํ’€์ด 1: Solution.characterReplacement โ€” Time: O(N) / Space: O(1)
๋ณต์žก๋„
Time O(N)
Space O(1)

ํ”ผ๋“œ๋ฐฑ: ์œˆ๋„์šฐ ์•ˆ์˜ ๋ฌธ์ž ๋นˆ๋„์ˆ˜ ์ถ”์ ์œผ๋กœ ์ตœ๋Œ€ ๊ธธ์ด๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค. ์ตœ๋Œ€ ๋นˆ๋„์ˆ˜๋ฅผ ์œ ์ง€ํ•˜๋Š” ๋ฐฉ์‹์ด ํ•ต์‹ฌ์ด๋‹ค.

๊ฐœ์„  ์ œ์•ˆ: ํ˜„์žฌ ๊ตฌํ˜„์ด ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

ํ’€์ด 2: SegTree โ€” Time: O(log N) / Space: O(N)
๋ณต์žก๋„
Time O(log N)
Space O(N)

ํ”ผ๋“œ๋ฐฑ: ๋ณต์žก๋„๊ฐ€ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์ปค์ง€๋Š” ์˜ˆ์ œ์ง€๋งŒ ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ํ•™์Šต์— ์œ ์šฉํ•˜๋‹ค.

๊ฐœ์„  ์ œ์•ˆ: ํ˜„์žฌ ๊ตฌํ˜„์ด ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

๐Ÿ’ก ํ’€์ด์— ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„๋ฅผ ์ฃผ์„์œผ๋กœ ๋‚จ๊ฒจ๋ณด์„ธ์š”!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿท๏ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํŒจํ„ด ๋ถ„์„

palindromic-substrings/alphaorderly.py
"""
์‹œ๊ฐ„๋ณต์žก๋„ : O(N^2)
๊ณต๊ฐ„๋ณต์žก๋„ : O(1)

1. n์„ s์˜ ๊ธธ์ด๋กœ ์„ค์ •ํ•œ๋‹ค.
2. count๋ฅผ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
3. ๊ฐ ๋ฌธ์ž๋ฅผ ์ค‘์‹ฌ(center)์œผ๋กœ ํ™•์žฅํ•˜์—ฌ ํ™€์ˆ˜ ๊ธธ์ด์˜ ํŒฐ๋ฆฐ๋“œ๋กฌ์„ ์„ผ๋‹ค.
   - radius๋ฅผ 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด, center - radius >= 0, center + radius < n ์ด๊ณ  s[center - radius] == s[center + radius]์ธ ๋™์•ˆ count๋ฅผ 1 ์ฆ๊ฐ€, radius += 1 ํ•œ๋‹ค.
4. ๊ฐ ๋ฌธ์ž ์Œ(center, center+1)์„ ์ค‘์‹ฌ์œผ๋กœ ํ™•์žฅํ•˜์—ฌ ์ง์ˆ˜ ๊ธธ์ด์˜ ํŒฐ๋ฆฐ๋“œ๋กฌ์„ ์„ผ๋‹ค.
   - radius๋ฅผ 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด, center - radius >= 0, center + radius + 1 < n ์ด๊ณ  s[center - radius] == s[center + radius + 1]์ธ ๋™์•ˆ count๋ฅผ 1 ์ฆ๊ฐ€, radius += 1 ํ•œ๋‹ค.
5. ์ด ํŒฐ๋ฆฐ๋“œ๋กฌ ๋ถ€๋ถ„ ๋ฌธ์ž์—ด ๊ฐœ์ˆ˜์ธ count๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
"""
class Solution:
    def countSubstrings(self, s: str) -> int:
        n = len(s)
        count = 0

        for center in range(n):
            radius = 0
            # ํ™€์ˆ˜ ๊ธธ์ด ํŒฐ๋ฆฐ๋“œ๋กฌ (center๋ฅผ ๊ธฐ์ค€)
            while (
                center - radius >= 0
                and center + radius < n
                and s[center - radius] == s[center + radius]
            ):
                count += 1
                radius += 1

            radius = 0
            # ์ง์ˆ˜ ๊ธธ์ด ํŒฐ๋ฆฐ๋“œ๋กฌ (center, center+1์„ ๊ธฐ์ค€)
            while (
                center - radius >= 0
                and center + radius + 1 < n
                and s[center - radius] == s[center + radius + 1]
            ):
                count += 1
                radius += 1

        return count
  • ํŒจํ„ด: Two Pointers, Monotonic Stack, Dynamic Programming
  • ์„ค๋ช…: ๋ฌธ์ž์—ด์˜ ์ค‘์‹ฌ์—์„œ ํ™•์žฅํ•˜๋ฉฐ ํŒฐ๋ฆฐ๋“œ๋กฌ์„ ํƒ์ƒ‰ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ, ํ™€์ˆ˜/์ง์ˆ˜ ์ค‘์‹ฌ์„ ๊ฐ๊ฐ ํ™•์žฅํ•˜๋Š” ๋‘ ํฌ์ธํ„ฐ(์„ผํ„ฐ-ํ™•์žฅ) ๊ธฐ๋ฒ•์ด๋‹ค. ๊ฐ ํ™•์žฅ์—์„œ ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋ฉฐ ์นด์šดํŠธ๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋ฏ€๋กœ ํ•œ ์œ„์น˜์—์„œ์˜ ๋น„๊ต๋กœ ์ „์ฒด๋ฅผ ํƒ์ƒ‰ํ•œ๋‹ค.

๐Ÿ“Š ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„ ๋ถ„์„

๋ณต์žก๋„
Time O(N^2)
Space O(1)

ํ”ผ๋“œ๋ฐฑ: ๊ฐ€์šด๋ฐ๋ฅผ ํ™•์žฅํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ชจ๋“  ํ™€/์ง์ˆ˜ ๊ธธ์ด ํŒฐ๋ฆฐ๋“œ๋กฌ์„ ํƒ์ง€ํ•œ๋‹ค.

๊ฐœ์„  ์ œ์•ˆ: ํ˜„์žฌ ๊ตฌํ˜„์ด ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

๐Ÿ’ก ํ’€์ด์— ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„๋ฅผ ์ฃผ์„์œผ๋กœ ๋‚จ๊ฒจ๋ณด์„ธ์š”!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿท๏ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํŒจํ„ด ๋ถ„์„

reverse-bits/alphaorderly.py
"""
์‹œ๊ฐ„๋ณต์žก๋„: O(1)  # 32๋ฒˆ๋งŒ ๋ฐ˜๋ณตํ•˜๋ฏ€๋กœ ํ•ญ์ƒ ์ƒ์ˆ˜ ์‹œ๊ฐ„ ๋ณต์žก๋„์ž„
๊ณต๊ฐ„๋ณต์žก๋„: O(1)

1. ans๋ฅผ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
3. ans๋ฅผ ์™ผ์ชฝ์œผ๋กœ 1๋น„ํŠธ ์‹œํ”„ํŠธํ•œ ํ›„, n์˜ ๋งˆ์ง€๋ง‰ ๋น„ํŠธ๋ฅผ OR ์—ฐ์‚ฐํ•œ๋‹ค.
4. n์„ ์˜ค๋ฅธ์ชฝ์œผ๋กœ 1๋น„ํŠธ ์‹œํ”„ํŠธํ•œ๋‹ค.
- 3, 4 ๊ณผ์ •์„ 32๋ฒˆ ๋ฐ˜๋ณตํ•œ๋‹ค.
5. ans๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
"""
class Solution:
    def reverseBits(self, n: int) -> int:
        ans = 0

        for _ in range(32):
            ans = (ans << 1) | (n & 1)
            n >>= 1

        return ans
  • ํŒจํ„ด: Bit Manipulation, Divide and Conquer, Greedy
  • ์„ค๋ช…: ๋น„ํŠธ ์กฐ์ž‘์œผ๋กœ ๊ฐ ๋น„ํŠธ๋ฅผ ์ขŒ์šฐ๋กœ ์ด๋™์‹œํ‚ค๋ฉฐ ๊ฒฐ๊ณผ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ํŒจํ„ด์œผ๋กœ, ๋ฐ˜๋ณต๋ฌธ ๋‚ด์—์„œ ๋น„ํŠธ๋ฅผ shift/OR๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋น„ํŠธ ์—ฐ์‚ฐ ๊ธฐ๋ฒ•์ด๋‹ค. ์ž…๋ ฅ ๋น„ํŠธ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ด ์ตœ์ข… ๊ฐ’์„ ์–ป๋Š” ๋ฐฉ์‹์€ ๋‹จ์ˆœํ•˜๊ณ  ๋ช…์‹œ์ ์ด๋‹ค.

๐Ÿ“Š ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„ ๋ถ„์„

๋ณต์žก๋„
Time O(1)
Space O(1)

ํ”ผ๋“œ๋ฐฑ: ๊ณ ์ •๋œ ๋น„ํŠธ ์ˆ˜๋ฅผ ๋ฐ˜๋ณตํ•˜๋ฉฐ ๋น„ํŠธ๋ฅผ ๋’ค์ง‘๋Š”๋‹ค.

๊ฐœ์„  ์ œ์•ˆ: ํ˜„์žฌ ๊ตฌํ˜„์ด ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

๐Ÿ’ก ํ’€์ด์— ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„๋ฅผ ์ฃผ์„์œผ๋กœ ๋‚จ๊ฒจ๋ณด์„ธ์š”!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿท๏ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํŒจํ„ด ๋ถ„์„

longest-repeating-character-replacement/alphaorderly.py
"""
์‹œ๊ฐ„๋ณต์žก๋„ : O(N)
๊ณต๊ฐ„๋ณต์žก๋„ : O(1)

1. freq ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
2. s์˜ ๊ฐ ๋ฌธ์ž(value)์— ๋Œ€ํ•ด ๋ฃจํ”„๋ฅผ ๋ˆ๋‹ค.
3. freq[value]๋ฅผ 1 ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.
4. maxima๋ฅผ ํ˜„์žฌ ์œˆ๋„์šฐ์—์„œ ๊ฐ€์žฅ ๋นˆ๋„๊ฐ€ ๋†’์€ ๋ฌธ์ž ๋นˆ๋„๋กœ ๊ฐฑ์‹ ํ•œ๋‹ค.
5. ์œˆ๋„์šฐ ํฌ๊ธฐ์—์„œ maxima์˜ ๊ฐ’๋งŒํผ์„ ๋บ€ ๊ฐ’์ด k๋ณด๋‹ค ํฌ๋ฉด,
6. freq[s[left]]๋ฅผ 1 ๊ฐ์†Œ์‹œํ‚ค๊ณ  left๋ฅผ 1 ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.
7. ans๋ฅผ ์œˆ๋„์šฐ์˜ ์ตœ๋Œ€ ๊ธธ์ด๋กœ ๊ฐฑ์‹ ํ•œ๋‹ค.
8. ๋งˆ์ง€๋ง‰์œผ๋กœ ans๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
"""
class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        freq = defaultdict(int)
        # maxima : ํ˜„์žฌ ์œˆ๋„์šฐ ๋‚ด์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ๋“ฑ์žฅํ•œ ๋ฌธ์ž์˜ ๋นˆ๋„์ˆ˜
        maxima = left = ans = 0

        for right, value in enumerate(s):
            freq[value] += 1
            maxima = max(maxima, freq[value])

            while (right - left + 1) - maxima > k:
                freq[s[left]] -= 1
                left += 1

            ans = max(ans, right - left + 1)

        return ans

"""
์‹œ๊ฐ„๋ณต์žก๋„: O(NlogN)
  - ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ํ•œ ๋ฒˆ ์—…๋ฐ์ดํŠธ: O(logN)
  - ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ ์˜ค๋ฅธ์ชฝ ํฌ์ธํ„ฐ ํ•œ ๋ฒˆ์”ฉ ์ „์ง„: O(N)
๊ณต๊ฐ„๋ณต์žก๋„: O(N)
  - ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ํฌ๊ธฐ: O(N) (์•ŒํŒŒ๋ฒณ 26๊ฐœ์— ๋Œ€ํ•ด 4N+1 ๋…ธ๋“œ)

[์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ๊ฐœ์š”]
- ๊ฐ ์•ŒํŒŒ๋ฒณ(A~Z)์˜ ๋นˆ๋„์ˆ˜๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ๋ฅผ ๊ตฌํ˜„ํ•จ.
- ๊ฐ ํŠธ๋ฆฌ ๋…ธ๋“œ๋Š” ๊ตฌ๊ฐ„ ๋‚ด ํ˜„์žฌ ์•ŒํŒŒ๋ฒณ ๋นˆ๋„ ์ดํ•ฉ๊ณผ ๊ทธ ๊ตฌ๊ฐ„ ๋‚ด ์ตœ๋นˆ๊ฐ’(๊ฐ€์žฅ ๋งŽ์ด ๋“ฑ์žฅํ•œ ์•ŒํŒŒ๋ฒณ์˜ ๋นˆ๋„)์„ ์ €์žฅํ•จ.
- ์ด์ง„ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ๊ฐ ์•ŒํŒŒ๋ฒณ ์ธ๋ฑ์Šค๋ฅผ ๋ฆฌํ”„ ๋…ธ๋“œ(0~25)์— ๋งคํ•‘.

[ํ•ต์‹ฌ ๋™์ž‘ ์„ค๋ช…]
- window.update(๋ฌธ์ž, ยฑ1): ํ˜„์žฌ ์œˆ๋„์šฐ์— ์ƒˆ ๋ฌธ์ž๋ฅผ ์ถ”๊ฐ€/์ œ๊ฑฐํ•  ๋•Œ ํ•ด๋‹น ์•ŒํŒŒ๋ฒณ์˜ ๋นˆ๋„์ˆ˜๋ฅผ O(logN)์— ๊ฐฑ์‹ .
- window.tree[1][0]: ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ๋ฃจํŠธ์˜ ์ฒซ ๋ฒˆ์งธ ๊ฐ’์œผ๋กœ, ํ˜„์žฌ ์œˆ๋„์šฐ ๋‚ด ์ „์ฒด ๋ฌธ์ž ๊ฐœ์ˆ˜(์œˆ๋„์šฐ ๊ธธ์ด)๋ฅผ ์˜๋ฏธ.
- window.tree[1][1]: ๋ฃจํŠธ์˜ ๋‘ ๋ฒˆ์งธ ๊ฐ’์œผ๋กœ, ํ˜„์žฌ ์œˆ๋„์šฐ ๋‚ด์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ๋“ฑ์žฅํ•œ ๋ฌธ์ž์˜ ๋“ฑ์žฅ ํšŸ์ˆ˜๋ฅผ ์˜๋ฏธ.
- (์œˆ๋„์šฐ ์ „์ฒด๊ธธ์ด - ์ตœ๋นˆ๊ฐ’) > k ๋ฅผ ๋งŒ์กฑํ•  ๋•Œ๊นŒ์ง€ ์™ผ์ชฝ ํฌ์ธํ„ฐ๋ฅผ ์˜ฎ๊ธฐ๋ฉฐ(=์™ผ์ชฝ ๋ฌธ์ž ์ œ๊ฑฐ), ์œˆ๋„์šฐ๊ฐ€ k๊ฐœ ์ดํ•˜์˜ ๋ฌธ์ž๋งŒ ๋ฐ”๊พธ๋ฉด ๋ชจ๋‘ ๋™์ผํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๋ฒ”์œ„๋กœ ์ถ•์†Œ.
- ๋งค ๋ฐ˜๋ณต๋งˆ๋‹ค ans๋ฅผ ์ตœ๋Œ€ ์œˆ๋„์šฐ ํฌ๊ธฐ๋กœ ๊ฐฑ์‹ .

โ€ป ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ์‚ฌ์šฉ์€ ์ด ๋ฌธ์ œ์— ์ตœ์ ํ•ด๋Š” ์•„๋‹ˆ๋‚˜, ์ž๋ฃŒ๊ตฌ์กฐ ํ•™์Šต์—๋Š” ์ข‹์€ ์—ฐ์Šต ์˜ˆ์ œ.
"""
class SegTree:
    def __init__(self):
        # [๋ฌธ์ž ๊ฐœ์ˆ˜ ํ•ฉ, ์ตœ๋Œ€๊ฐ’]
        self.tree = [[0, 0] for _ in range(26 * 4 + 1)]

    def _update(
        self,
        node_index: int,
        target_index: int,
        target_update: int,
        seg_left: int,
        seg_right: int,
    ):
        if seg_left == seg_right:
            self.tree[node_index][0] += target_update
            self.tree[node_index][1] += target_update
            return

        mid = (seg_left + seg_right) // 2

        if target_index <= mid:
            self._update(node_index * 2, target_index, target_update, seg_left, mid)
        else:
            self._update(
                node_index * 2 + 1, target_index, target_update, mid + 1, seg_right
            )

        self.tree[node_index][0] = (
            self.tree[node_index * 2][0] + self.tree[node_index * 2 + 1][0]
        )
        self.tree[node_index][1] = max(
            self.tree[node_index * 2][1], self.tree[node_index * 2 + 1][1]
        )

    def update(self, target: str, update: int):
        self._update(1, ord(target) - ord("A"), update, 0, 25)


class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        left = 0
        window = SegTree()
        ans = 0

        for right, value in enumerate(s):
            window.update(value, 1)

            while window.tree[1][0] > 0 and window.tree[1][0] - window.tree[1][1] > k:
                window.update(s[left], -1)
                left += 1

            ans = max(ans, right - left + 1)

        return ans
  • ํŒจํ„ด: Sliding Window, Hash Map / Hash Set, Divide and Conquer
  • ์„ค๋ช…: ์ฒซ ๋ฒˆ์งธ ๊ตฌํ˜„์€ ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ๋กœ ์—ฐ์† ๋ถ€๋ถ„ ๋ฌธ์ž์—ด์—์„œ ํ•„์š” ๋ฌธ์ž ๊ฐฑ์‹  ํšŸ์ˆ˜๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค. freq ํ•ด์‹œ ๋งต์œผ๋กœ ๋ฌธ์ž ๋นˆ๋„๋ฅผ ์ถ”์ ํ•˜๊ณ  ์œˆ๋„์šฐ๋ฅผ ์ขŒ์šฐ ํฌ์ธํ„ฐ๋กœ ์กฐ์ •ํ•˜๋Š” ํŒจํ„ด์ด ํ•ต์‹ฌ์ด๋‹ค. ๋‘ ๋ฒˆ์งธ ๊ตฌํ˜„์€ ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ๋กœ ์œˆ๋„์šฐ ๋‚ด๋ถ€ ๋นˆ๋„์™€ ์ตœ๋นˆ๊ฐ’์„ ๊ด€๋ฆฌํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ์œˆ๋„์šฐ ํ™•์žฅ/์ถ•์†Œ์˜ ํ๋ฆ„์€ Sliding Window์— ๊ฐ€๊น๋‹ค.

๐Ÿ“Š ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„ ๋ถ„์„

๋ณต์žก๋„
Time O(N)
Space O(1)

ํ”ผ๋“œ๋ฐฑ: ํ•ด๋‹น ํ’€์ด์—์„œ๋Š” ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ step์—์„œ ํ•„์š” ์ตœ์†Œํ•œ์˜ ์ •๋ณด๋ฅผ ์œ ์ง€ํ•œ๋‹ค. ๋‹ค๋งŒ ์ฃผ์„์— ์ œ์‹œ๋œ ์‹œ๊ฐ„/๊ณต๊ฐ„ ํ‘œ๊ธฐ๊ฐ€ ์‹ค์ œ ๊ตฌํ˜„๊ณผ ๋‹ค๋ฅด๋ฏ€๋กœ ๊ตฌํ˜„์˜ ๋™์ž‘์— ์ง‘์ค‘ํ•˜๋ฉด ๋œ๋‹ค.

๊ฐœ์„  ์ œ์•ˆ: ํ˜„์žฌ ๊ตฌํ˜„์ด ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

๐Ÿ’ก ํ’€์ด์— ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„๋ฅผ ์ฃผ์„์œผ๋กœ ๋‚จ๊ฒจ๋ณด์„ธ์š”!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿท๏ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํŒจํ„ด ๋ถ„์„

longest-repeating-character-replacement/alphaorderly.py
"""
์‹œ๊ฐ„๋ณต์žก๋„ : O(N)
๊ณต๊ฐ„๋ณต์žก๋„ : O(1)

1. freq ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
2. s์˜ ๊ฐ ๋ฌธ์ž(value)์— ๋Œ€ํ•ด ๋ฃจํ”„๋ฅผ ๋ˆ๋‹ค.
3. freq[value]๋ฅผ 1 ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.
4. maxima๋ฅผ ํ˜„์žฌ ์œˆ๋„์šฐ์—์„œ ๊ฐ€์žฅ ๋นˆ๋„๊ฐ€ ๋†’์€ ๋ฌธ์ž ๋นˆ๋„๋กœ ๊ฐฑ์‹ ํ•œ๋‹ค.
5. ์œˆ๋„์šฐ ํฌ๊ธฐ์—์„œ maxima์˜ ๊ฐ’๋งŒํผ์„ ๋บ€ ๊ฐ’์ด k๋ณด๋‹ค ํฌ๋ฉด,
6. freq[s[left]]๋ฅผ 1 ๊ฐ์†Œ์‹œํ‚ค๊ณ  left๋ฅผ 1 ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.
7. ans๋ฅผ ์œˆ๋„์šฐ์˜ ์ตœ๋Œ€ ๊ธธ์ด๋กœ ๊ฐฑ์‹ ํ•œ๋‹ค.
8. ๋งˆ์ง€๋ง‰์œผ๋กœ ans๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
"""
class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        freq = defaultdict(int)
        # maxima : ํ˜„์žฌ ์œˆ๋„์šฐ ๋‚ด์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ๋“ฑ์žฅํ•œ ๋ฌธ์ž์˜ ๋นˆ๋„์ˆ˜
        maxima = left = ans = 0

        for right, value in enumerate(s):
            freq[value] += 1
            maxima = max(maxima, freq[value])

            while (right - left + 1) - maxima > k:
                freq[s[left]] -= 1
                left += 1

            ans = max(ans, right - left + 1)

        return ans

"""
์‹œ๊ฐ„๋ณต์žก๋„: O(NlogN)
  - ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ํ•œ ๋ฒˆ ์—…๋ฐ์ดํŠธ: O(logN)
  - ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ ์˜ค๋ฅธ์ชฝ ํฌ์ธํ„ฐ ํ•œ ๋ฒˆ์”ฉ ์ „์ง„: O(N)
๊ณต๊ฐ„๋ณต์žก๋„: O(N)
  - ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ํฌ๊ธฐ: O(N) (์•ŒํŒŒ๋ฒณ 26๊ฐœ์— ๋Œ€ํ•ด 4N+1 ๋…ธ๋“œ)

[์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ๊ฐœ์š”]
- ๊ฐ ์•ŒํŒŒ๋ฒณ(A~Z)์˜ ๋นˆ๋„์ˆ˜๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ๋ฅผ ๊ตฌํ˜„ํ•จ.
- ๊ฐ ํŠธ๋ฆฌ ๋…ธ๋“œ๋Š” ๊ตฌ๊ฐ„ ๋‚ด ํ˜„์žฌ ์•ŒํŒŒ๋ฒณ ๋นˆ๋„ ์ดํ•ฉ๊ณผ ๊ทธ ๊ตฌ๊ฐ„ ๋‚ด ์ตœ๋นˆ๊ฐ’(๊ฐ€์žฅ ๋งŽ์ด ๋“ฑ์žฅํ•œ ์•ŒํŒŒ๋ฒณ์˜ ๋นˆ๋„)์„ ์ €์žฅํ•จ.
- ์ด์ง„ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ๊ฐ ์•ŒํŒŒ๋ฒณ ์ธ๋ฑ์Šค๋ฅผ ๋ฆฌํ”„ ๋…ธ๋“œ(0~25)์— ๋งคํ•‘.

[ํ•ต์‹ฌ ๋™์ž‘ ์„ค๋ช…]
- window.update(๋ฌธ์ž, ยฑ1): ํ˜„์žฌ ์œˆ๋„์šฐ์— ์ƒˆ ๋ฌธ์ž๋ฅผ ์ถ”๊ฐ€/์ œ๊ฑฐํ•  ๋•Œ ํ•ด๋‹น ์•ŒํŒŒ๋ฒณ์˜ ๋นˆ๋„์ˆ˜๋ฅผ O(logN)์— ๊ฐฑ์‹ .
- window.tree[1][0]: ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ๋ฃจํŠธ์˜ ์ฒซ ๋ฒˆ์งธ ๊ฐ’์œผ๋กœ, ํ˜„์žฌ ์œˆ๋„์šฐ ๋‚ด ์ „์ฒด ๋ฌธ์ž ๊ฐœ์ˆ˜(์œˆ๋„์šฐ ๊ธธ์ด)๋ฅผ ์˜๋ฏธ.
- window.tree[1][1]: ๋ฃจํŠธ์˜ ๋‘ ๋ฒˆ์งธ ๊ฐ’์œผ๋กœ, ํ˜„์žฌ ์œˆ๋„์šฐ ๋‚ด์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ๋“ฑ์žฅํ•œ ๋ฌธ์ž์˜ ๋“ฑ์žฅ ํšŸ์ˆ˜๋ฅผ ์˜๋ฏธ.
- (์œˆ๋„์šฐ ์ „์ฒด๊ธธ์ด - ์ตœ๋นˆ๊ฐ’) > k ๋ฅผ ๋งŒ์กฑํ•  ๋•Œ๊นŒ์ง€ ์™ผ์ชฝ ํฌ์ธํ„ฐ๋ฅผ ์˜ฎ๊ธฐ๋ฉฐ(=์™ผ์ชฝ ๋ฌธ์ž ์ œ๊ฑฐ), ์œˆ๋„์šฐ๊ฐ€ k๊ฐœ ์ดํ•˜์˜ ๋ฌธ์ž๋งŒ ๋ฐ”๊พธ๋ฉด ๋ชจ๋‘ ๋™์ผํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๋ฒ”์œ„๋กœ ์ถ•์†Œ.
- ๋งค ๋ฐ˜๋ณต๋งˆ๋‹ค ans๋ฅผ ์ตœ๋Œ€ ์œˆ๋„์šฐ ํฌ๊ธฐ๋กœ ๊ฐฑ์‹ .

โ€ป ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ์‚ฌ์šฉ์€ ์ด ๋ฌธ์ œ์— ์ตœ์ ํ•ด๋Š” ์•„๋‹ˆ๋‚˜, ์ž๋ฃŒ๊ตฌ์กฐ ํ•™์Šต์—๋Š” ์ข‹์€ ์—ฐ์Šต ์˜ˆ์ œ.
"""
class SegTree:
    def __init__(self):
        # summation, largest
        self.tree = [[0, 0] for _ in range(26 * 4 + 1)]

    def _update(
        self,
        node_index: int,
        target_index: int,
        target_update: int,
        seg_left: int,
        seg_right: int,
    ):
        if seg_left == seg_right:
            self.tree[node_index][0] += target_update
            self.tree[node_index][1] += target_update
            return

        mid = (seg_left + seg_right) // 2

        if target_index <= mid:
            self._update(node_index * 2, target_index, target_update, seg_left, mid)
        else:
            self._update(
                node_index * 2 + 1, target_index, target_update, mid + 1, seg_right
            )

        self.tree[node_index][0] = (
            self.tree[node_index * 2][0] + self.tree[node_index * 2 + 1][0]
        )
        self.tree[node_index][1] = max(
            self.tree[node_index * 2][1], self.tree[node_index * 2 + 1][1]
        )

    def update(self, target: str, update: int):
        self._update(1, ord(target) - ord("A"), update, 0, 25)


class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        left = 0
        window = SegTree()
        ans = 0

        for right, value in enumerate(s):
            window.update(value, 1)

            while window.tree[1][0] - window.tree[1][1] > k:
                window.update(s[left], -1)
                left += 1

            ans = max(ans, right - left + 1)

        return ans
  • ํŒจํ„ด: Sliding Window, Hash Map / Hash Set, Dynamic Programming
  • ์„ค๋ช…: ์ฒซ ๋ฒˆ์งธ ์ฝ”๋“œ์—์„œ ์œˆ๋„์šฐ ํฌ๊ธฐ๋ฅผ ๋ณ€๋™์‹œํ‚ค๋ฉฐ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ตœ๋Œ€ ๊ธธ์ด๋ฅผ ์ฐพ๋Š” Sliding Window ํŒจํ„ด์ด๋‹ค. freq๋กœ ๋ฌธ์ž ๋นˆ๋„๋ฅผ ์ถ”์ ํ•˜๋‚˜ ํ•ด์‹œ ๋งต/ํ•ด์‹œ์…‹์œผ๋กœ ๊ตฌํ˜„๋œ ํ•ต์‹ฌ ์•„์ด๋””์–ด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๋‘ ๋ฒˆ์งธ ์ฝ”๋“œ๋Š” ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ๋กœ ์œˆ๋„์šฐ ๋‚ด ์ดํ•ฉ๊ณผ ์ตœ๋นˆ๊ฐ’์„ ๊ด€๋ฆฌํ•˜๋‚˜, ์œˆ๋„์šฐ๋ฅผ ์ขŒ์šฐ๋กœ ํ™•์žฅ/์ถ•์†Œํ•˜๋Š” ํ๋ฆ„์€ Sliding Window์˜ ํ™•์žฅ์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“Š ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„ ๋ถ„์„

โ„น๏ธ ์ด ํŒŒ์ผ์—๋Š” 2๊ฐ€์ง€ ํ’€์ด๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์–ด ๊ฐ๊ฐ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค.

ํ’€์ด 1: Solution.characterReplacement โ€” Time: O(n) / Space: O(1)
๋ณต์žก๋„
Time O(n)
Space O(1)

ํ”ผ๋“œ๋ฐฑ: ๋‹จ์ผ ๋ฃจํ”„์™€ ์ƒ์ˆ˜ ๊ฐœ์˜ ์ถ”๊ฐ€ ๋ณ€์ˆ˜๋กœ ๊ตฌ์„ฑ๋˜์–ด ์‹œ๊ฐ„๋ณต์žก๋„๋Š” ์„ ํ˜•์ด๋ฉฐ, ๊ณต๊ฐ„์€ ๊ณ ์ •๋œ ์ƒ์ˆ˜ ํฌ๊ธฐ์˜ ๋ณ€์ˆ˜๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค.

๊ฐœ์„  ์ œ์•ˆ: ํ˜„์žฌ ๊ตฌํ˜„์ด ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

ํ’€์ด 2: SegTree.characterReplacement โ€” Time: O(n log N) / Space: O(N)
๋ณต์žก๋„
Time O(n log N)
Space O(N)

ํ”ผ๋“œ๋ฐฑ: ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ๋กœ ๊ตฌํ˜„ํ–ˆ์ง€๋งŒ ๋ฌธ์ œ์˜ ์ตœ์ ํ•ด๋Š” ์•„๋‹ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ์˜ ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„์— ๋น„ํ•ด ๋น„ํšจ์œจ์ ์ผ ์ˆ˜ ์žˆ๋‹ค. ํŠธ๋ฆฌ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋งค ๋ฌธ์ž๋งˆ๋‹ค ํ•„์š”ํ•˜๋‹ค.

๊ฐœ์„  ์ œ์•ˆ: ๊ณ ๋ คํ•ด๋ณผ ๋งŒํ•œ ๋Œ€์•ˆ: ๊ฐ„๋‹จํ•œ ํ•ด์‹œ๋งต+์œˆ๋„์šฐ ๋ฐฉ์‹์œผ๋กœ O(n) ์‹œ๊ฐ„๊ณผ O(1) ๊ณต๊ฐ„์— ๋” ๊ฐ€๊นŒ์šด ๊ตฌํ˜„์„ ์šฐ์„  ์‹œ๋„ํ•ด๋ณผ ๊ฒƒ.

๐Ÿ’ก ํ’€์ด์— ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„๋ฅผ ์ฃผ์„์œผ๋กœ ๋‚จ๊ฒจ๋ณด์„ธ์š”!

@parkhojeong

Copy link
Copy Markdown
Contributor

์ด๋ฒˆ ์ฃผ์ฐจ์™€ ์ƒ๊ด€์—†๋Š” ์ปค๋ฐ‹ ๋กœ๊ทธ๋Š” ์ •๋ฆฌ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.


"""
์‹œ๊ฐ„๋ณต์žก๋„: O(NlogN)
- ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ํ•œ ๋ฒˆ ์—…๋ฐ์ดํŠธ: O(logN)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

์ด๊ฑฐ ์ƒ์ˆ˜๋ผ 1์ด๋„ค์š”, O(N)์ด ์‹œ๊ฐ„๋ณต์žก๋„์ž…๋‹ˆ๋‹ค.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿท๏ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํŒจํ„ด ๋ถ„์„

longest-common-subsequence/alphaorderly.py
"""
์‹œ๊ฐ„๋ณต์žก๋„ : O(T1 * T2)
๊ณต๊ฐ„๋ณต์žก๋„ : O(T1) # T1์— ์งง์€ ๋ฌธ์ž์—ด์„ ์„ค์ •ํ–ˆ๊ธฐ์— ๊ณต๊ฐ„๋ณต์žก๋„๋Š” T1์ด ๋œ๋‹ค.

1. text1๊ณผ text2 ์ค‘ ๋” ์งง์€ ์ชฝ์„ text1์œผ๋กœ ์„ค์ •ํ•œ๋‹ค.
2. T1๊ณผ T2๋ฅผ ๊ฐ๊ฐ text1๊ณผ text2์˜ ๊ธธ์ด๋กœ ์„ค์ •ํ•œ๋‹ค.
3. dp ๋ฐฐ์—ด์„ T1 + 1 ํฌ๊ธฐ๋กœ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
4. text2์˜ ๊ฐ ๋ฌธ์ž(i)๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ ๋น„๊ตํ•œ๋‹ค.
5. new_dp ๋ฐฐ์—ด์„ T1 + 1 ํฌ๊ธฐ๋กœ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
6. text1์˜ ๊ฐ ๋ฌธ์ž(j)์— ๋Œ€ํ•ด ์ˆœํšŒํ•˜๋ฉด์„œ ๋น„๊ตํ•œ๋‹ค.
7. text2[i - 1]๊ณผ text1[j - 1]๊ฐ€ ๊ฐ™์œผ๋ฉด, new_dp[j]๋ฅผ dp[j - 1] + 1๋กœ ์„ค์ •ํ•œ๋‹ค.
8. ๋‹ค๋ฅด๋ฉด, new_dp[j]๋ฅผ max(new_dp[j - 1], dp[j])๋กœ ์„ค์ •ํ•œ๋‹ค.
9. dp๋ฅผ new_dp๋กœ ๊ฐฑ์‹ ํ•˜๊ณ , ๋งˆ์ง€๋ง‰ ์›์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
"""
class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        if len(text1) > len(text2):
            text1, text2 = text2, text1

        T1, T2 = len(text1), len(text2)
        dp = [0] * (T1 + 1)

        for i in range(1, T2 + 1):
            new_dp = [0] * (T1 + 1)

            for j in range(1, T1 + 1):
                if text2[i - 1] == text1[j - 1]:
                    new_dp[j] = dp[j - 1] + 1
                else:
                    new_dp[j] = max(new_dp[j - 1], dp[j])

            dp = new_dp

        return dp[-1]
  • ํŒจํ„ด: Dynamic Programming, Two Pointers
  • ์„ค๋ช…: ๋‘ ๋ฌธ์ž์—ด์˜ LCS๋ฅผ ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด ๋ถ€๋ถ„๋ฌธ์ œ์˜ ํ•ด๋ฅผ ์ด์šฉํ•ด ์ˆœ์ฐจ์ ์œผ๋กœ dp๋ฅผ ๊ฐฑ์‹ ํ•˜๋Š” ์ „ํ˜•์ ์ธ ๋‹ค์ด๋‚˜๋ฏน ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํŒจํ„ด์ด๋ฉฐ, ๊ณต๊ฐ„ ์ ˆ์•ฝ์„ ์œ„ํ•ด ํ˜„์žฌ์™€ ์ด์ „ ํ–‰๋งŒ ์‚ฌ์šฉํ•˜๋Š” ์ ์—์„œ ์ ์ง„์  ๊ฐฑ์‹ ์ด ํ•ต์‹ฌ์ด๋‹ค.

๐Ÿ“Š ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„ ๋ถ„์„

๋ณต์žก๋„
Time O(T1 * T2)
Space O(T1)

ํ”ผ๋“œ๋ฐฑ: ๋‘ ๋ฌธ์ž์—ด ๊ธธ์ด์— ๋น„๋ก€ํ•˜๋Š” ์ด์ค‘ ๋ฃจํ”„์™€ ํ•œ ์ค„์˜ ๋ณด์กฐ ๋ฐฐ์—ด ์‚ฌ์šฉ์œผ๋กœ ๊ณต๊ฐ„์„ ์ตœ์ ํ™”ํ–ˆ๋‹ค.

๊ฐœ์„  ์ œ์•ˆ: ํ˜„์žฌ ๊ตฌํ˜„์ด ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

๐Ÿ’ก ํ’€์ด์— ์‹œ๊ฐ„/๊ณต๊ฐ„ ๋ณต์žก๋„๋ฅผ ์ฃผ์„์œผ๋กœ ๋‚จ๊ฒจ๋ณด์„ธ์š”!

@dahyeong-yun
dahyeong-yun self-requested a review August 11, 2026 07:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Development

Successfully merging this pull request may close these issues.

2 participants