def num_coin_changes_dp(amount, coins):
    """Number of coin changes by bottom-up dynamic programming.

    Time complexity: O(a*n), where a is amount, and n is number of coins.
    Space complexity: O(a*n).
    """
    # Apply bottom-up DP with memoization tabular T: (n+1)x(amount+1).
    n = len(coins)
    T = [[0] * (amount + 1) for c in range(n + 1)]

    # For amount 0, set T[c][0] equal 1.
    for c in range(1, n + 1):
        T[c][0] = 1

    for c in range(1, n + 1):
        for a in range(1, amount + 1):
            if coins[c - 1] <= a:
                # If can change, sum num of ways with coin n included & excluded.
                T[c][a] = T[c][a - coins[c - 1]] + T[c - 1][a]
            else:
                # Cannot make a change by coin c.
                T[c][a] = T[c - 1][a]

    return T[-1][-1]