【剑指 Offer】第 8 天

112 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

一、前言

刷题啊!!!

开始刷 “剑指 Offer” 31天。刷完时间:2022.3.6 ~ 2022.3.20。



二、题目

题目:

  • 斐波那契数列
  • 青蛙跳台阶问题
  • 股票的最大利润

(1)剑指 Offer 10- I. 斐波那契数列

题目描述


写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:

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

斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

示例 1:

输入:n = 2
输出:1
示例 2:

输入:n = 5
输出:5

提示:0 <= n <= 100

题解


这类题也是常见的:

  1. 思路一:首先能想到的是,按照公式走:但这种方法容易超时
class Solution {
    public int fib(int n) {
        if (n == 0) return 0;
        if (n == 1) return 1;

        return fib(n - 1) + fib(n - 2);
    }
}
  1. 思路二:在思路一的基础上,记录下已经计算过的值(避免重复计算)
// 此方法已 AC
// % 1000000007 只是为了防止超出数值
class Solution {
    public int fib(int n) {
        if (n == 0) return 0;
        if (n == 1) return 1;

        int [] num = new int[n + 1];
        num[0] = 0;
        num[1] = 1;

        for (int i = 2; i < n + 1; ++i) {
            num[i] = (num[i - 1] + num[i - 2]) % 1000000007;
        }
        return num[n] % 1000000007 ;
    }
}
  1. 思路三:在思路二基础能否再优化?

我们看到,实际只需要 3 个变量就能表示。

AC 代码如下:

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;
    }
}

(2)剑指 Offer 10- II. 青蛙跳台阶问题

题目描述


一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

示例 1:
输入:n = 2
输出:2

示例 2:
输入:n = 7
输出:21

示例 3:
输入:n = 0
输出:1

提示:0 <= n <= 100

题解


斐波那契数列变体应用。

思路和斐波那契数列类似,只不过要注意下 %1000000007

AC 代码如下:

class Solution {
    public int numWays(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;
    }
}

(3)剑指 Offer 63. 股票的最大利润

题目描述


假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?

示例 1:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

限制:0 <= 数组长度 <= 10^5

题解


既然做 DP,就尽量不要考虑暴力法。

题意:只要找到前天比当前小的对。

  • 每日更新最低价格,转移方程:cost = min(cost, prices[i])
  • 每日最大利润,转移方程:profit = max(profit, prices[i] - min(cost, prices[i]))

AC 代码如下:

class Solution {
    public int maxProfit(int[] prices) {
        int p = Integer.MAX_VALUE, sum = 0;
        for (int price : prices) {
            p = Math.min(p, price);
            sum = Math.max(sum, price - p);
        }
        return sum;
    }
}