【38】斐波那契数 | 凑零钱问题(LC 509 | 322)

动态规划

动态规划详解

解题思路

将待求解问题分解成若干个不独立的子问题,求出子问题的解并记录在表中,当需要再次求解此子问题时,可以通过查表获得该子问题的解而不用再次求解,从而避免了大量的重复计算。最后结合这些子问题的解即可得到原问题的解。

解题步骤:

①分析问题的最优子结构性质:一个最优策略的子策略总是最优的
②建立递归关系(状态转移方程)

建立状态转移方程:
明确「状态」 -> 定义 dp 数组/函数的含义 -> 明确「选择」-> 明确 base case。

③自下而上计算最优值
④根据计算最优值时得到的信息,构造最优解

斐波那契数列

问题描述

斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1

给你 n ,请计算 F(n) 。

题解

递归

class Solution {
    public int fib(int n) {
        if(n == 0) return 0;
        if(n == 1) return 1;
        return fib(n-1) + fib(n-2);
    }
}

时间复杂度:O(2^n)
空间复杂度:O(2^n)

带备忘录的递归解法(自顶向下)

递归解法产生了大量的重复计算,时间效率不高,所以可以用一个备忘录来存储每次的结算结果,当计算一个值时先查看备忘录中是否有结果,若没有再计算。

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

    public int helper(int memo[],int n){
        if(n == 0 || n == 1) return n;
        if(memo[n] != 0) return memo[n];
        memo[n] = helper(memo,n-1) + helper(memo,n-2);
        return memo[n];
    }
}

时间复杂度:O(n)
空间复杂度:O(n)

动态规划(自底向上)

令dp[i]为f(i)的值。

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

凑零钱问题

问题描述

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

你可以认为每种硬币的数量是无限的。

题解

①因为硬币的数量是无限的,因此每个硬币需要的最少数量问题是相互独立的,且最少需要的硬币数需要每种硬币都是最少的(如果要证明一般用数学归纳法证明),因此具有最优子结构性质,可以用动态规划求解。

②找递归关系,写出状态转移方程:

设dp[i]表示当目标金额为i时至少需要的硬币数为dp[i],当需要选择一种硬币时先进行判断,是选择当前硬币后最优还是不选择最优,做出最优的选择。
在这里插入图片描述

public class Solution {
    public int coinChange(int[] coins, int amount) {
        int[] dp = new int[amount + 1];
        Arrays.fill(dp, amount+1);
        dp[0] = 0;
        for (int i = 1; i <= amount; i++) {
            for (int j = 0; j < coins.length; j++) {
                if (coins[j] <= i) {
                    dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }
        return dp[amount] > amount ? -1 : dp[amount];
    }
}

时间复杂度:O(n^k)(n指要凑的总数,k指硬币的种数)
空间复杂度:O(n)

# 写在最后
浪了两天继续刷题,新年快乐!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值