动态规划
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];
}
}