from typing import List


def dynamic_programming_run(steps: List[int]) -> bool:
    """
    Use dynamic programming to build an array to determine the minimum number of hops (hops[i]) to get from position
    0 to position i.
    :param steps: the list of hops we can make from each position
    :return: True if we can reach the end, and False otherwise.

    >>> dynamic_programming_run([])
    False
    >>> dynamic_programming_run([1])
    True
    >>> dynamic_programming_run([0])
    True
    >>> dynamic_programming_run([2, 0, 1, 0])
    True
    >>> dynamic_programming_run([1, 1, 0, 1])
    False
    """
    # No steps means no movement: fail.
    if not steps:
        return False

    def accessible(n):
        """
        Determine if position n is accessible from position 0.
        :param n: the position
        :return: True if accessible, and false otherwise.
        """

        if n == 0:
            return True
        if steps[0] == 0:
            return False

        hops = [False] * (len(steps) + 1)
        hops[0] = True

        # Find for all positions [1,n] if they can be accessed.
        for i in range(1, n + 1):
            # Check position j < i to see if it can reach position i.
            for j in range(i):
                if i <= j + steps[j] and hops[j]:
                    hops[i] = True
                    break
        return hops[n]

    return accessible(len(steps)-1)