[LeetCode]Unique Paths

Icarus<Wing>ยท2024๋…„ 8์›” 9์ผ
post-thumbnail

https://leetcode.com/problems/unique-paths/description/

๐Ÿ“œ๋ฌธ์ œ ํ•ด์„

์ด ๋ฌธ์ œ๋Š” ์ด์ „์— ํ’€์—ˆ๋˜, Shortest Path in Binary Matrix์™€ ๋งค์šฐ ์œ ์‚ฌํ•œ๋ฐ ์ฃผ์–ด์ง„ ๋ฐ์ดํ„ฐ๊ฐ€ grid๋ผ๋Š” ๊ฒƒ๊ณผ ๊ฒฝ๋กœ๊ฐ€ (0,0) -> (m-1,n-1)๋กœ ์ •ํ•ด์กŒ๋‹ค๋Š” ์ ์ด๋‹ค.

ํ•˜์ง€๋งŒ, ๋‹ค๋ฅธ ์ ์€ 8-direction์—์„œ ์˜ค์ง ์˜ค๋ฅธ์ชฝ๊ณผ ์•„๋ž˜ ๋ฐฉํ–ฅ์œผ๋กœ๋งŒ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋˜ํ•œ, 0์œผ๋กœ ํ‘œ์‹œ๋œ visited cell๋กœ๋งŒ ๊ฐ€์•ผ ํ•œ๋‹ค๋Š” ์ œ์•ฝ ์กฐ๊ฑด์ด ์—†๊ณ  length๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, unique path์˜ ๊ฒฝ์šฐ์˜ ์ˆ˜๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค๋Š” ์ ์—์„œ๋„ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

๐Ÿšง์ œ์•ฝ ์กฐ๊ฑด

1 <= m, n <= 100
โฐ๏ธŽ์‹œ๊ฐ„๋ณต์žก๋„: O(2*10^9)๋ณด๋‹ค ์ž‘์•„์•ผํ•จ.

โš™๏ธ์ฝ”๋“œ ์„ค๊ณ„

์กฐํ•ฉ๋ก ์„ ์‚ฌ์šฉ


์œ„์˜ ๋ฌธ์ œ๋ฅผ ์‚ดํŽด๋ณด์ž. ํ•™์ฐฝ ์‹œ์ ˆ๋•Œ ํ’€์—ˆ๋˜ ์ตœ๋‹จ๊ฒฝ๋กœ ์ฐพ๊ธฐ ๋ฌธ์ œ์™€ ๊ต‰์žฅํžˆ ๋น„์Šทํ•˜์ง€ ์•Š์€๊ฐ€? ๊ทธ๋ ‡๋‹ค! ์ด ๋ฌธ์ œ๋Š” mississippi์™€ ๊ฐ™์ด ๊ฐ™์€ ๋ฌธ์ž๋ฅผ ํฌํ•จํ•œ ์ˆ˜๋กœ ๋‚˜๋ˆ ์„œ 11!/(4!4!2!)์™€ ๊ฐ™์ด ์ˆ˜์‹์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, example 1๋กœ ๋ดค์„ ๋•Œ๋Š”, ->->->->->->โ†“โ†“์˜ ๋ฐฉ๋ฒ• 1๊ฐ€์ง€๊ฐ€ ๋‚˜์˜ค๋Š”๋ฐ, ์ด๋ฅผ ์ˆ˜์‹์œผ๋กœ ํ‘œํ˜„ํ•˜๋ฉด (7-1+3-1)! / (7-1)! * (3-1)! ์ด๋‹ค.

์ด๋ฅผ ์ผ๋ฐ˜ํ™” ํ•˜๋ฉด, (n+m-2)! / (n-1)! * (m-1)!๊ฐ€ ๋œ๋‹ค.
์ด ์ˆ˜์‹์„ ๊ทธ๋Œ€๋กœ ๋ฆฌํ„ดํ•˜๋ฉด 1์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, factorial์€ ์žฌ๊ท€ํ•จ์ˆ˜๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋Š”๋ฐ, m๊ณผ n์˜ ๋ฐ์ดํ„ฐ ๊ฐ’๋งŒํผ ํ˜ธ์ถœํ•˜๋ฏ€๋กœ ์ด O(m+n)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง„๋‹ค. (์™œ๋ƒํ•˜๋ฉด ๋‚˜๋ˆ—์…ˆ ์—ฐ์‚ฐ์€ ์ƒ์ˆ˜ ์‹œ๊ฐ„์œผ๋กœ ์ทจ๊ธ‰ํ•˜๊ธฐ ๋•Œ๋ฌธ)

์ด์ œ, ์œ„์™€ ์ˆ˜์‹๊ณผ factorial ์žฌ๊ท€ ํ•จ์ˆ˜๋ฅผ ์กฐํ•ฉํ•ด์„œ ์ฝ”๋“œ๋กœ ๋…น์ด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

class Solution(object):
    def uniquePaths(self, m, n):
        def fact(x):
            # base condition: 0!=1, 1!=1
            if x <= 1:
                return 1
            return fact(x - 1) * x
        
        return fact(n + m - 2) / (fact(n-1) * fact(m-1))

์ด๋ ‡๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ง  ๋‹ค์Œ ์ œ์ถœํ•˜๋ฉด ๋Ÿฐํƒ€์ž„ ํ•˜์œ„๊ถŒ์— ๊ธฐ๋ก๋  ์ˆ˜ ์žˆ๋‹ค ๐Ÿ˜ญ

๐Ÿค”DP๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์‹œ๊ฐ„๋ณต์žก๋„ ๋‚ฎ์ถ”๊ธฐ

1. Top-down

๋‹จ์ˆœํ•˜๊ฒŒ top-down ์ฝ”๋“œ ํ”Œ๋žซํผ์„ ์œ„์˜ ์ฝ”๋“œ์— ์ ์šฉํ•ด์„œ ํ’€์–ด๋ณด์•˜๋‹ค.

class Solution(object):
    def uniquePaths(self, m, n):
        memo = {}

        def dp(i, j):
            # base condition
            if i <= 1 or j <= 1:
                return 1
            # x๊ฐ€ memo์— ์—†์œผ๋ฉด fact๋ฅผ ํ˜ธ์ถœ
            if (i,j) not in memo:
                memo[(i,j)] = fact(n + m - 2) / (fact(n - 1) * fact(m - 1))
            # ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด memo์˜ value๋ฅผ ๋ฆฌํ„ด
            return memo[(i,j)]

        def fact(x):
            # base condition: 0!=1, 1!=1
            if x <= 1:
                return 1
            return fact(x - 1) * x
        
        return dp(m,n)

๊ทธ๋Ÿฐ๋ฐ, chatgptํ•œํ…Œ ๋ฌผ์–ด๋ดค๋”๋‹ˆ, ์ด ๋ฐฉ์‹ ์—ญ์‹œ factorial ํ•จ์ˆ˜๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์— ์ง€๋‚˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•œ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์• ์ดˆ์— ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋ฅผ memo์— ์ €์žฅํ•ด์„œ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ๋ฐ”๋กœ fact๋ฅผ ํ˜ธ์ถœํ•ด์„œ memo[(i, j)]์— ์ €์žฅํ•œ ๋‹ค์Œ, ๊ทธ ๊ฐ’์„ ๋ฆฌํ„ดํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๐Ÿ’ก์ˆ˜์ •์‚ฌํ•ญ: ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ๋””์Šค์ฝ”๋“œ ์ฑ„๋„์— ์˜ฌ๋ฆฐ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ–ˆ๋Š”๋ฐ, ๊ทธ ๋ถ„์€ factorial ํ•จ์ˆ˜ ํ˜ธ์ถœ์—์„œ ์ค‘๋ณต๋˜๋Š” ์—ฐ์‚ฐ์„ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•ด์„œ dp๋ฅผ ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

class Solution(object):
  def uniquePaths(self, m, n):
      memo = {}
      def fact(x):
          if x <= 1:
              return 1
          if x not in memo: 
              memo[x] = fact(x - 1) * x # factorial์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ
          return memo[x]
      return fact(m + n - 2) / (fact(m - 1) * fact(n - 1)) 
      # fact(m + n - 2) ๋ถ€๋ถ„๋งŒ ํ˜ธ์ถœํ•˜๊ณ , ๋ถ„๋ชจ๋Š” ์บ์‹ฑํ•˜๋ฏ€๋กœ ์‹œ๊ฐ„๋ณต์žก๋„๋Š” O(M+N)

๐Ÿง์ฐธ๊ณ ๋กœ, ์ด ์ฝ”๋“œ์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋Š” O(M+N)์ด๊ธฐ ๋•Œ๋ฌธ์— O(M*N)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ–๋Š” dfs๋กœ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ๋ณด๋‹ค ๋” ํšจ์œจ์ ์ด๋‹ค.

2. Bottom-up

์—ญ์‹œ bottom-up ์ฝ”๋“œ ํ…œํ”Œ๋ฆฟ์„ fact ํ•จ์ˆ˜์— ๊ทธ๋Œ€๋กœ ์ ์šฉํ•˜๋ฉด ๋œ๋‹ค.

class Solution(object):
   def uniquePaths(self, m, n):
       table = {0: 1, 1: 1}

       def fact(x):  # 0! or 1! = 1
           for i in range(2, x + 1):  # ์šฐ๋ฆฌ๊ฐ€ ์ตœ์ข…์ ์œผ๋กœ ์›ํ•˜๋Š” ๊ฐ’์€ table[x]๊ธฐ ๋•Œ๋ฌธ์— initial step์„ 2๋กœ ํ•˜๋“  1๋กœ ํ•˜๋“  ์ƒ๊ด€ ์—†์Œ
               table[i] = table[i - 1] * i
           return table[x]
       # ํ•จ์ˆ˜๋ฅผ ๋จผ์ € ์ •์˜ํ•ด์•ผ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Œ
       return fact(m + n - 2) // (fact(m - 1) * fact(n - 1))

๐Ÿง์ƒˆ๋กœ ์•Œ๊ฒŒ๋œ ์ : python 3๋ถ€ํ„ฐ๋Š” ๊ฒฐ๊ณผ๊ฐ€ ํ•ญ์ƒ ์ •์ˆ˜๊ฐ€ ๋˜๋„๋ก ๋ณด์žฅํ•˜๋ ค๋ฉด ์ •์ˆ˜ ๋‚˜๋ˆ—์…ˆ //์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๊ณ  ํ•จ.


๐Ÿ‘จโ€๐Ÿซ๊ทธ๋ž˜์„œ ํŒจ๋ฐฐ๋ฅผ ์ธ์ •ํ•˜๊ณ , ๊ฐ•์˜๋ฅผ ๋“ค์–ด์„œ ์–ด๋–ป๊ฒŒ top-down์„ ๋ฌธ์ œ์— ์ ์šฉํ•˜์˜€๋Š”์ง€ ํ•™์Šตํ•˜์˜€๋‹ค.
๊ฐ•์˜ ๋งํฌ: https://www.inflearn.com/course/lecture?courseSlug=%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%9E%85%EB%AC%B8-%ED%8C%8C%EC%9D%B4%EC%8D%AC&unitId=140229

๋ฌธ์ œ ๋ถ„์„

"ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋Š” ๋‹ต์ด 2*10^9์ดํ•˜๊ฐ€ ๋˜๋„๋ก ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค" -> ์™„์ „ํƒ์ƒ‰์„ ์“ฐ๋ฉด, ์‹œ๊ฐ„์ดˆ๊ณผ!
"๋„๋‹ฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅํ•œ unique paths์˜ ์ˆ˜" -> ~๋ฐฉ๋ฒ•์˜ ์ˆ˜๋Š” dp๋ฅผ ํ™œ์šฉ!

์ ‘๊ทผ ๋ฐฉ๋ฒ•

์™„์ „ํƒ์ƒ‰(DFS): grid๋Š” ์•”์‹œ์  graph๋กœ ์ƒ๊ฐ์ด ๊ฐ€๋Šฅ

ํ™”์‚ดํ‘œ(์•„๋ž˜, ์˜ค๋ฅธ์ชฝ)์˜ ์กฐํ•ฉ; nCr=n!/r!โˆ—(nโˆ’r)!nCr = n! / r!*(n-r)!

์ œ์•ฝ์กฐ๊ฑด์ด 1<= m, n <= 100์ด๋ฏ€๋กœ, ์ตœ๋Œ€ ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋กœ ๊ณ„์‚ฐํ•˜๋ฉด 2*10^58์ด๋ฏ€๋กœ ์™„์ „ํƒ์ƒ‰์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

DFS ์ฝ”๋“œ(1): ์‹œ์ž‘์ ์„ ๊ธฐ์ค€์œผ๋กœ ํ•œ ์ฝ”๋“œ

def dfs(r, c):
	if r == 2 and c == 6: # ์ข…์ ์— ๋„๋‹ฌํ•˜๋ฉด ์ข…๋ฃŒ
    	return 1
    unique_paths = 0
    
    # ๊ฒฝ๊ณ„๊ฐ’ ๋ฒ”์œ„ ์ด๋‚ด ์ด๋™ ์กฐ๊ฑด
    if r + 1 < 3:
    	unique_paths += dfs(r + 1, c) # ์•„๋ž˜๋กœ ์ด๋™
    if c + 1 < 7:
    	unique_paths += dfs(r, c + 1) # ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์ด๋™
    return unique_paths

๊ทธ๋Ÿฐ๋ฐ, ์ด์ „์— ํ•™์Šตํ•œ min-cost climbing stairs์˜ ์•„์ด๋””์–ด๋ฅผ ํ™œ์šฉํ•ด์„œ ์ข…์ ์„ ๊ธฐ์ค€์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์งค ์ˆ˜๋„ ์žˆ๋‹ค.

DFS ์ฝ”๋“œ(2): ์ข…์ ์„ ๊ธฐ์ค€์œผ๋กœ ํ•œ ์ฝ”๋“œ

min-cost climbing stairs ๋ฌธ์ œ๋Š” n๋ฒˆ์งธ๊นŒ์ง€ ์˜ค๋ฅด๋Š” ๋น„์šฉ์„ (n-1)๋ฒˆ์งธ ๋น„์šฉ๊ณผ (n-2) ๋น„์šฉ์„ ํ•ฉ์ณ์„œ ๊ตฌํ–ˆ๋‹ค.
์ด์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ์ข…์ ์„ n๋ฒˆ์งธ๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ณ , ์ด๋ฅผ ์ž‘์€ ๋ฌธ์ œ๋“ค๋กœ ๋‚˜๋ˆ„์–ด์„œ ์•„๋ž˜์— ํ•ด๋‹นํ•˜๋Š” (r-1, c)์™€ ์˜ค๋ฅธ์ชฝ์— ํ•ด๋‹นํ•˜๋Š” (r, c-1)์˜ ํ•ฉ์œผ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

(r,c)=(rโˆ’1,c)+(r,cโˆ’1)(r,c)=(r-1,c)+(r,c-1)

์ด ์•„์ด๋””์–ด๋ฅผ ์ฝ”๋“œ๋กœ ์งœ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

def dfs(r, c):
	if r == 0 and c == 0: # base condition
    	return 1 # ์ž‘์€ ๋ฌธ์ œ๊ฐ€ ์‹œ์ ์— ๋„๋‹ฌํ•˜๋ฉด 1์„ ๋ฆฌํ„ด
    unique_paths = 0
    
    # ๊ฒฝ๊ณ„๊ฐ’ ๋ฒ”์œ„ ์ด๋‚ด ์ด๋™ ์กฐ๊ฑด
    if r - 1 >= 0:
    	unique_paths += dfs(r - 1, c)
    if c - 1 >= 0:
    	unique_paths += dfs(r, c - 1)
    return unique_paths

โš ๏ธ์ด ์ฝ”๋“œ๋Š” ํ”ผ๋ณด๋‚˜์น˜์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ž‘์€ ๋ฌธ์ œ์— ํ•ด๋‹นํ•˜๋Š” ์žฌ๊ท€ ๋ถ€๋ถ„์— overlapping subproblem(์ค‘๋ณต ํ•˜์œ„ ๋ฌธ์ œ)๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ์กด์žฌํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด๊ฒƒ์ด ๋ถˆํ•„์š”ํ•œ ์—ฐ์‚ฐ์„ ํ•ด์„œ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๋†’์ด๋ฏ€๋กœ, DP๋ฅผ ํ™œ์šฉํ•ด์„œ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๋‚ฎ์ถœ ์ˆ˜๊ฐ€ ์žˆ๋‹ค.


top-down ์ฝ”๋“œ ํ”Œ๋žซํผ์„ ์œ„์˜ ์•„์ด๋””์–ด์— ์ ์šฉํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์งœ๋ณด์•˜๋‹ค.

(1) ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋งŒ๋“  ์ฝ”๋“œ

class Solution(object):
    def uniquePaths(self, m, n):
        memo = {}

        def dfs(r, c):
            if (r, c) == (0, 0): # base condition
                return 1
            if (r, c) not in memo:
            	unique_paths = 0
    # ๊ฒฝ๊ณ„๊ฐ’์„ ๋”ฐ๋กœ ์„ค์ •ํ•ด์ค˜์•ผํ•จ(์•ˆ๊ทธ๋Ÿฌ๋ฉด, ๊ฐ€์žฅ์ž๋ฆฌ์— ์žˆ์„๋•Œ ํ•ญ์ƒ ๊ฑฐ์ง“์ด๋˜์„œ NoneType์„ ๋ฐ˜ํ™˜)
            	if r - 1 >= 0: # ์œ„์ชฝ ์…€์—์„œ ์˜ค๋Š” ๊ฒฝ์šฐ
                	unique_paths += dfs(r - 1, c)
                if c - 1 >= 0: # ์™ผ์ชฝ ์…€์—์„œ ์˜ค๋Š” ๊ฒฝ์šฐ
                	unique_paths += dfs(r, c - 1)
                memo[(r, c)] = unique_paths
            return memo[(r, c)]
        return dfs(m - 1, n - 1)

์˜ˆ๋ฅผ ๋“ค์–ด, m=3, n=7์ด๋ฉด ๊ฐ๊ฐ 1์„ ๋นผ์•ผ unique path ์กฐ๊ฑด์— ์ถฉ์กฑํ•˜๋ฏ€๋กœ dfs ์ธ์ž์— 1์„ ๊ฐ๊ฐ ๋บ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ, ๋”•์…”๋„ˆ๋ฆฌ ๋Œ€์‹  ์ด์ค‘๋ฆฌ์ŠคํŠธ ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์งค ์ˆ˜๋„ ์žˆ๋‹ค.

๐Ÿง์Šค์Šค๋กœ ๊ทธ๋ฆผ์„ ๊ทธ๋ ค๋ณด๋ฉด์„œ ์ง  ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

dfs(r-1, c)๋ฅผ ๊ณ„์†ํ•ด์„œ ํ˜ธ์ถœํ•˜๋Š”๋ฐ ๊ฒฝ๊ณ„ ๋ฒ”์œ„๋ฅผ ๋„˜์–ด๊ฐ€๋ฉด 0์„ ๋ฆฌํ„ดํ•˜๋„๋ก ํ•ด์„œ ๊ทธ ๊ฐ’์„ ๋”ํ•ด์ฃผ๊ฒŒ ํ•˜์˜€๋‹ค.( dfs(r, c-1)๋„ ๋งˆ์ฐฌ๊ฐ€์ง€ )

์œ„์˜ ๊ทธ๋ฆผ์„ ์ž์„ธํžˆ ์‚ดํŽด๋ณด์ž. ์•„๋ž˜์— ํ•ด๋‹นํ•˜๋Š” ์…€์ด ๊ฒฝ๊ณ„ ๋ฒ”์œ„๋ฅผ ๋„˜์–ด๊ฐ€์„œ ํ˜ธ์ถœ์ด ์ข…๋ฃŒ๋˜๋ฉด, ์˜ค๋ฅธ์ชฝ ์…€์ด ๊ทธ๋•Œ ํ˜ธ์ถœ๋˜๊ณ , (0,0)์— ๋„๋‹ฌํ•  ๋•Œ๊นŒ์ง€ ๊ณ„์† ํ˜ธ์ถœ๋œ๋‹ค.
๊ทธ ํ›„์—, ์žฌ๊ท€์˜ ์„ฑ์งˆ ๋•Œ๋ฌธ์— ๋ฆฌํ„ดํ•œ ๊ฐ’์„ ๊ณ„์†ํ•ด์„œ ์ด์ „์— ํ˜ธ์ถœ๋œ ํ•จ์ˆ˜์— ์ „๋‹ฌํ•ด์ค€๋‹ค.

  • ๊ทธ๋ž˜์„œ ์œ„์˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด ๋ชจ์„œ๋ฆฌ๊ฐ€ 1๋กœ ์ฑ„์›Œ์ง€๋Š”๊ฑฐ์ž„.

๋นจ๊ฐ„์ƒ‰ ๋™๊ทธ๋ผ๋ฏธ ์นœ r=0์˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ์ข…๋ฃŒ๋˜๋ฉด, ๊ทธ์ œ์„œ์•ผ r=1์˜ ํ•จ์ˆ˜๋“ค์ด ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœ๋˜๋Š”๋ฐ, ์ด๋•Œ memoization์œผ๋กœ ์ด๋ฏธ ๊ฐ’์„ ์ €์žฅํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—(์„ธ๋ชจ ๋ถ€๋ถ„) ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋˜ ํ˜ธ์ถœํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

r=1๋ถ€ํ„ฐ๋Š” ๋ชจ์„œ๋ฆฌ ๋ถ€๋ถ„๊ณผ ๋‹ฌ๋ฆฌ, (r, c) = ์•„๋ž˜ + ์˜ค๋ฅธ์ชฝ์œผ๋กœ ๊ณ„์†ํ•ด์„œ ๊ฐ’์„ ๋”ํ•ด๊ฐ„๋‹ค.

๐Ÿ’ป์ด์ œ ์œ„์˜ ๊ทธ๋ฆผ ๋ถ€๋ถ„์„ ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ํ•ด๋ณด์ž.

class Solution(object):
   def uniquePaths(self, m, n):  # (m,n)์€ row x col
       memo = {}

       def dfs(r, c):  # (r,c)๋Š” ๋‚ด๋ถ€์˜ ์„ฑ๋ถ„
           # ๊ฒฝ๊ณ„๊ฐ’ ์„ค์ •(์•ˆ๊ทธ๋Ÿฌ๋ฉด stack_over_flow)
           if r < 0 or c < 0:
               return 0 # ํ™”์‚ดํ‘œ๊ฐ€ ์—†์œผ๋‹ˆ๊นŒ 0 ์ฒ˜๋ฆฌ
           if (r, c) == (0, 0):  # ์‹œ์ž‘์ ์ด๋ฉด
               return 1  # 1๊ฐ€์ง€๋ฅผ ๋ฆฌํ„ด(๊ทธ๋ž˜์•ผ ๋”ํ•ด์ง€๋‹ˆ๊นŒ)
           if (r, c) not in memo:
               memo[(r, c)] = dfs(r - 1, c) + dfs(r, c - 1)
           return memo[(r, c)]

       return dfs(m - 1, n - 1)  # ์ข…์ ์˜ ์ขŒํ‘œ๋ถ€ํ„ฐ ์‹œ์ž‘

(2) ์ด์ฐจ์› ๋ฐฐ์—ด์„ ํ™œ์šฉํ•˜์—ฌ ๋งŒ๋“  ์ฝ”๋“œ

class Solution(object):
   def uniquePaths(self, m, n):
       memo = [[-1] * n for _ in range(m)] # col 1์ฐจ์› ๋ฐฐ์—ด์„ ๋จผ์ € ๋งŒ๋“ค๊ณ , row๋กœ iterate

       def dfs(r, c):
           if (r, c) == (0, 0): # base condition
               return 1
           if memo[r][c] == -1:
           	unique_paths = 0
   # ๊ฒฝ๊ณ„๊ฐ’์„ ๋”ฐ๋กœ ์„ค์ •ํ•ด์ค˜์•ผํ•จ(์•ˆ๊ทธ๋Ÿฌ๋ฉด, ๊ฐ€์žฅ์ž๋ฆฌ์— ์žˆ์„๋•Œ ํ•ญ์ƒ ๊ฑฐ์ง“์ด๋˜์„œ NoneType์„ ๋ฐ˜ํ™˜)
           	if r - 1 >= 0: # ์œ„์ชฝ ์…€์—์„œ ์˜ค๋Š” ๊ฒฝ์šฐ
               	unique_paths += dfs(r - 1, c)
               if c - 1 >= 0: # ์™ผ์ชฝ ์…€์—์„œ ์˜ค๋Š” ๊ฒฝ์šฐ
               	unique_paths += dfs(r, c - 1)
               memo[r][c] = unique_paths
           return memo[r][c]
       return dfs(m - 1, n - 1)

์—ฌ๊ธฐ์„œ [-1]์€ ์ดˆ๊ธฐ๊ฐ’์„ ์˜๋ฏธํ•˜๊ณ , ์ž‘๋™ ์›๋ฆฌ๋Š” (1)๊ณผ ๋˜‘๊ฐ™๋‹ค.

โฐ๏ธtop-down ์‹œ๊ฐ„๋ณต์žก๋„: ์ด๋ฏธ ๊ณ„์‚ฐํ•œ ๊ฐ’์€ memo์— ์ €์žฅํ•ด๋‘๊ณ , ๊ฒฐ๊ณผ์ ์œผ๋กœ grid์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’๋งŒ ๊ณ„์‚ฐํ•˜๋ฏ€๋กœ O(M*N)

2. Bottom-up

top-down ๋ฐฉ์‹์—์„œ๋Š” ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋ฉด์„œ (0,0)์— ๋„๋‹ฌํ•˜๋ฉด 1์„ ๋ฆฌํ„ดํ•˜๋Š”๋ฐ, ์ด๊ฒƒ์„ ํ˜ธ์ถœํ•œ ํ•จ์ˆ˜๋กœ ๊ณ„์†ํ•ด์„œ ์ „๋‹ฌํ•˜๋ฏ€๋กœ ์ตœ์ข…์ ์œผ๋กœ ๊ฐ€์žฅ์ž๋ฆฌ๊ฐ€ 1๋กœ ์ฑ„์›Œ์ง€๋Š” ๊ทธ๋ฆผ์ด ๋œ๋‹ค.

class Solution(object):
    def uniquePaths(self, m, n):
        table = [[-1] * n for _ in range(m)]

        # top-down์—์„œ ๊ฐ€์žฅ์ž๋ฆฌ 1๋กœ ์ฑ„์šด ์•„์ด๋””์–ด ํ™œ์šฉ
        for r in range(m):
            table[r][0] = 1
        for c in range(n):
            table[0][c] = 1

        # ์ž‘์€ ๋ฌธ์ œ๋“ค์„ ๊ณ„์†ํ•ด์„œ ํ•ฉํ•ด์„œ ํฐ ๋ฌธ์ œ๋กœ ๋‚˜์•„๊ฐ
        for r in range(1, m):
            for c in range(1, n):
                table[r][c] = table[r - 1][c] = table[r][c - 1]
        return table[m - 1][n - 1]

์—ฌ๊ธฐ์—์„œ๋Š” ๊ฒฝ๊ณ„๊ฐ’ ๋ฒ”์œ„ ์กฐ๊ฑด์„ ์ด๋ฏธ 1๋กœ ์ฑ„์šด ๊ฐ€์žฅ์ž๋ฆฌ์™€ ์ด์ค‘ for๋ฌธ์œผ๋กœ ๋Œ€์ฒดํ•˜์˜€๋‹ค.


๐Ÿง์Šค์Šค๋กœ ๊ทธ๋ฆผ์„ ๊ทธ๋ ค๋ณด๋ฉด์„œ ์ง  ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

โš™๏ธ์ฝ”๋“œ ์„ค๊ณ„

  1. base condition์ธ if(r, c) == (0, 0):์„ ๋”•์…”๋„ˆ๋ฆฌ ์ž๋ฃŒ๊ตฌ์กฐ์ธ table์— ๋ฏธ๋ฆฌ ์ฑ„์›Œ๋„ฃ์Œ
  2. ์œ„์˜ ๋นจ๊ฐ„์ƒ‰ ๋™๊ทธ๋ผ๋ฏธ์— ํ•ด๋‹นํ•˜๋Š” ๋ชจ์„œ๋ฆฌ๋ฅผ ๋ชจ๋‘ 1๋กœ ์ฑ„์šด๋‹ค.
  3. r >= 1์„ for loop๋กœ ๋Œ๋ ค์„œ ์œ„์˜ ๋ชจ์„œ๋ฆฌ 1๊ฐ’๊ณผ ๊ณ„์†ํ•ด์„œ ๋”ํ•ด์ค€๋‹ค.
  4. return table[(r, c]๋ฅผ ํ•˜๋ฉด ์ตœ์ข…์ ์ธ ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์œ„์˜ ์ƒ‰์น ๋œ ๋ถ€๋ถ„์„ ์œ ์‹ฌํžˆ ์‚ดํŽด๋ณด์ž. ์ด์ค‘ for๋ฌธ์œผ๋กœ ์š”์†Œ๋“ค์„ ์ˆœํšŒํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์œ„์˜ ๋ชจ์„œ๋ฆฌ ๋ถ€๋ถ„์„ ์ง‘ํ•ฉ A, ์™ผ์ชฝ ๋ชจ์„œ๋ฆฌ๋ฅผ ์ง‘ํ•ฉ B, ๊ทธ๋ฆฌ๊ณ  top-down์ฒ˜๋Ÿผ ์•„๋ž˜ ์…€ + ์˜ค๋ฅธ์ชฝ ์…€ ๋ถ€๋ถ„์„ ์ง‘ํ•ฉ C๋ผ๊ณ  ํ•˜์ž.

์ฆ‰, if AโˆชB:์™€ if C:๋ฅผ ์ด์ค‘ for๋ฌธ์—์„œ ๋ณ‘๋ ฌ์ ์œผ๋กœ ๋ฐฐ์น˜ํ•˜๋ฉด ๋œ๋‹ค.

๐Ÿ’ป์ฝ”๋“œ ๊ตฌํ˜„

class Solution(object):
    def uniquePaths(self, m, n):
        table = {(0, 0): 1}  # converted from if (r, c) == (0,0):

        def dp(r, c):  # (2, 6)
            # Don't have to set bounded range because no recursive calls are made to r-1 or c-1
            for i in range(r + 1):
                for j in range(c + 1):
                    if i == 0 or j == 0:  # Fill both the 1st row and col with 1 (corresponds to A โˆช B)
                        table[(i, j)] = table[(0, 0)]
                    if i > 0 and j > 0: # Combine the cell below and the cell to the right (corresponds to C)
                        table[(i, j)] = table[(i - 1, j)] + table[(i, j - 1)]
            return table[(r, c)]
        return dp(m - 1, n - 1)

โœ…์ˆ˜์ •์‚ฌํ•ญ(ํ˜ผ์ž ํž˜ -> ๊ฐ•์˜ ์ฝ”๋“œ)

  1. r=0 ๋˜๋Š” c=0๊ณผ ๊ฐ™์ด ๊ณ ์ •๋œ ์ขŒํ‘œ๋ฅผ ๊ฐ€์ง„ ์„ฑ๋ถ„๋“ค์„ ๋ชจ๋‘ 1 ๊ฐ’์œผ๋กœ ์ฑ„์šฐ๋Š” ๊ฒƒ์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์งœ๋ฉด ๋œ๋‹ค.
for r in range(m):
    table[r][0] = 1
for c in range(n):
    table[0][c] = 1

๐Ÿค”๊ทธ๋Ÿฐ๋ฐ, ๊ฒฐ๊ตญ์€ ๊ณ ์ •๋œ ์ธ๋ฑ์Šค์—์„œ ๋ชจ๋‘ 1๊ฐ’์œผ๋กœ ์ฑ„์šฐ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋™์ผํ•˜๋‹ˆ ๋‚ด๊ฐ€ ์Šค์Šค๋กœ ์งฐ๋˜ ๋ฐฉ์‹์œผ๋กœ ํ•ด๋„ ์ƒ๊ด€ ์—†์„ ๋“ฏ ํ•˜๋‹ค.

  1. ์•„๋ž˜ ์…€ + ์˜ค๋ฅธ์ชฝ ์…€์˜ ์•„์ด๋””์–ด๋Š” row์™€ col์˜ ๋ชจ๋‘ 1 ์ด์ƒ์ผ ๋•Œ(ํŒŒ๋ž€์ƒ‰ ์ •์‚ฌ๊ฐํ˜• ๋ถ€๋ถ„) ๋ˆ„์ ํ•˜๋ฉด์„œ ์ˆœํšŒํ•˜๊ธฐ ๋•Œ๋ฌธ์—
for r in range(1, m):
	for c in range(1, n):
    	table[r][c] = table[r - 1][c] = table[r][c - 1]

์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ๋‚˜์™”๋‹ค. ์ฆ‰, range(1, m)์œผ๋กœ 1๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

๐Ÿค”์ด ๋ถ€๋ถ„ ์—ญ์‹œ 1๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์€ ๋™์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์—, if i > 0 and j > 0:๋กœ ์งœ๋„ ๋ฌด๋ฐฉํ•˜๋‹ค.

โฐ๏ธbottom-up ์‹œ๊ฐ„๋ณต์žก๋„: grid๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ ๊ฐ’์„ ์ฑ„์›Œ๋‚˜๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— O(M*N)

profile
๋ชจ๋“  ์ฝ”๋“œ์—๋Š” ์ด์œ ๊ฐ€ ์žˆ๊ธฐ์— ์›์ธ์„ ํŒŒ์•…ํ•  ๋•Œ๊นŒ์ง€ ์ง‘์š”ํ•˜๊ฒŒ ํƒ๊ตฌํ•˜๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค.

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