lc 动态规划 509、322

509. 斐波那契数

写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

输入:n = 5
输出:5

带备忘录(数组or哈希表)暴力递归 “自顶向下”
时间复杂度 O(N)

class Solution {
    public int fib(int n) 
    {
        if(n==0) return 0;
    int[] dp=new int[n+1];
    return helper(dp, n);
    }

    public int helper(int[] dp,int N) {
    dp[0] = 0;
    dp[1] = 1;
    dp[2] = 1;
    if (dp[N]!=0)  return dp[N]%1000000007;
    dp[N]=helper(dp,N-1)%1000000007+helper(dp,N-2)%1000000007;
    return dp[N]%1000000007;
    }
}

动态规划-自底向上

class Solution {
    public int fib(int n) {
        if(n==0) return 0;
        int i;
    int[] dp=new int[n+1];
    dp[0] = 0;
    dp[1] = 1;
    for(i=2;i<=n;i++)
    dp[i]=dp[i-1]%1000000007+dp[i-2]%1000000007;
    return dp[n]%1000000007;
    }
}

循环求余法:
时间复杂度 O(N) ; 空间复杂度 O(1)

class Solution {
    public int fib(int n) {
        int a = 0, b = 1, sum;
        for(int i = 0; i < n; i++){
            sum = (a + b) % 1000000007;
            a = b;
            b = sum;
        }
        return a;
    }
}

322、零钱兑换*

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
可以认为每种硬币的数量是无限的。

输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1

动态规划-自顶而下
状态转移方程:在这里插入图片描述
避免计算重复,将每个子问题的答案存在一个数组中进行记忆化,如果下次还要计算这个问题的值直接从数组中取出返回即可,这样能保证每个子问题最多只被计算一次。

public class Solution {
  public int coinChange(int[] coins, int amount) {
    if (amount < 1) return 0;
    return coinChange(coins, amount, new int[amount]);
  }
  private int coinChange(int[] coins, int rem, int[] count) {
    if (rem < 0) return -1;
    if (rem == 0) return 0;
    if (count[rem - 1] != 0) return count[rem - 1];
    int min = Integer.MAX_VALUE;
    for (int coin : coins) {
      int res = coinChange(coins, rem - coin, count);
      if (res >= 0 && res < min)
        min = 1 + res;
    }
    count[rem - 1] = (min == Integer.MAX_VALUE) ? -1 : min;
    return count[rem - 1];
  }
}

动态规划-自底向上
1、预设一个0位方便后续计算,组成0的最少硬币数是0,所以dp[0] = 0
2、给每一个数预设一个最小值amount+1,因为硬币面额最小为整数1,所以只要有解,最小硬币数必然小于amount+1

for (循环变量类型 循环变量名称 : 要被遍历的对象) 循环体

class Solution {
    public int coinChange(int[] coins, int amount) {
        int[] dp = new int[amount+1];
        for(int i=0; i<amount+1; i++) {
            dp[i] = i == 0 ? 0 : amount+1;
            for(int coin : coins) {
                if(i >= coin) {
                    dp[i] = Math.min(dp[i-coin] + 1, dp[i]);
                }
            }
        }
        return dp[amount] == amount+1 ? -1 : dp[amount];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值