比LeetCode的“爬楼梯”更好的深度优先搜索解决方案

时间:2018-02-19 18:41:50

标签: python algorithm depth-first-search asymptotic-complexity

我在LeetCode Climbing Stairs上遇到了问题,其内容如下:

enter image description here

我想出了基于深度优先搜索的以下解决方案:

class Solution:
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        stack = [Node()]
        ways = 0
        while stack:
            node = stack.pop()
            if node.reached_top(n):
                ways += 1
            stack.extend(node.get_neighbors(n))
        return ways


class Node(tuple):
    def get_neighbors(self, n):
        return [Node(list(self) + [steps]) for steps in (1, 2) if sum(self) + steps <= n]

    def reached_top(self, n):
        return sum(self) == n

因此,例如,Solution().climbStairs(2) == 2Solution().climbStairs(3) == 3根据需要。问题是此解决方案超出了输入35

的时间限制

enter image description here

深度优先搜索似乎是解决此问题的一种相当有效的算法,但显然,它不是;关于如何改进我的解决方案的任何想法?

3 个答案:

答案 0 :(得分:2)

最简单的方法是根据solution(n) = solution(n-1) + solution(n-2)的事实计算每个答案。从solution(1) = 1solution(2) = 2这一事实开始,您可以轻松计算出solution(3)solution(4)等。根据需要计算出该数组。

这段代码足够快。

Google实施后的指示是&#34;动态编程&#34;和&#34;斐波那契序列&#34;。在这两者中,动态编程是更重要的学习内容。

答案 1 :(得分:1)

要扩展btilly的答案,假设达到n步骤的方式数量为solution(n)。在第一步,您可以采取步长1并保持solution(n-1)种方式,或采取一段2步,并保留solution(n-2)种方法。由于两者是互斥的,因此剩余的总方式为solution(n-1) + solution(n-2)

我决定使用简单的递归函数,而不是使用https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize中的memoize类来使用memoization,而不是他所描述的“自下而上”的动态编程方法。这是我的解决方案:

import collections
import functools


class memoized(object):
    '''Decorator. Caches a function's return value each time it is called.
    If called later with the same arguments, the cached value is returned
    (not reevaluated).
    '''
    def __init__(self, func):
       self.func = func
       self.cache = {}
    def __call__(self, *args):
       if not isinstance(args, collections.Hashable):
          # uncacheable. a list, for instance.
          # better to not cache than blow up.
          return self.func(*args)
       if args in self.cache:
          return self.cache[args]
       else:
          value = self.func(*args)
          self.cache[args] = value
          return value
    def __repr__(self):
       '''Return the function's docstring.'''
       return self.func.__doc__
    def __get__(self, obj, objtype):
       '''Support instance methods.'''
       return functools.partial(self.__call__, obj)


class Solution(object):
    @memoized
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n == 1:
            return 1
        elif n == 2:
            return 2
        else:
            return self.climbStairs(n-1) + self.climbStairs(n-2)

LeetCode接受此解决方案:

enter image description here

答案 2 :(得分:0)

在上面的解决方案中,您通过生成它们来计算每种可能性。如果您计算recyclerView,那么它应该等于climbStairs(35)。所以这里让我们假设你的函数是14930352,它计算爬上阶梯N的可能方法。 说明:解决方案中发生了什么:

f(n)

所以在这里你可以看到你一次又一次地计算相同的部分,比如// assuming f(x) = 0 where x <= 0 // and f(1) = 1 && f(2) = 2; f(n) = f(n-1) + f(n-2); f(n-1) = f(n-2) + f(n-3); f(n-2) = f(n-3) + f(n-4); . . . f(2) = 2; f(1) = 1; f(n-1)

您可以通过保存可能的组合来到达特定的楼梯X来避免这些重新计算。这是我在Java中的解决方案。使用“动态编程”方法。要计算f(n-2),它总共执行 35 步骤(而不是8位数的大数)。

climbStairs(35)