2021-11-02 剑指offer--动态规划

这篇博客探讨了多种动态规划和递归的应用,包括寻找连续子数组的最大和、计算跳台阶的不同方法、斐波那契数列的求解以及扩展的跳跃问题。每道题目都提供了时间复杂度为O(n)的解决方案,并通过空间优化达到O(1)。此外,还介绍了矩形覆盖问题,通过观察规律得出高效算法。
摘要由CSDN通过智能技术生成

JZ42 连续子数组的最大和

题目地址
描述
输入一个长度为n的整型数组array,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
数据范围:
1 <= n <= 10^5
-100 <= a[i] <= 100
要求:时间复杂度为 O(n),空间复杂度为 O(n)
进阶:时间复杂度为 O(n),空间复杂度为 O(1)
示例1

输入:
[1,-2,3,10,-4,7,2,-5]
返回值:
18
说明:
经分析可知,输入数组的子数组[3,10,-4,7,2]可以求得最大和为18     

示例2

输入:
[2]
返回值:
2

示例3

输入:
[-10]
返回值:
-10

代码
在代码中,dp[i]表示包含第i个数字,连续子数组和的最大值。

import java.util.*;
public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        int[] sum=new int[array.length];
        sum[0]=array[0];
        int maxVal=array[0];
        for(int i=1;i<sum.length;i++){
            sum[i]=Math.max(array[i],array[i]+sum[i-1]);
            maxVal=Math.max(maxVal,sum[i]);
        }
        return maxVal;
    }
}

JZ69 跳台阶

题目地址
描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

数据范围:0≤n≤40
要求:时间复杂度:O(n) ,空间复杂度: O(1)
示例1

输入:
2
返回值:
2
说明:
青蛙要跳上两级台阶有两种跳法,分别是:先跳一级,再跳一级或者直接跳两级。因此答案为2     

示例2

输入:
7
返回值:
21

示例3

输入:
0
返回值:
0

代码
先给出题目的递推解法,然后将递归改为动态规划的写法。

public class Solution {
    public int jumpFloor(int target) {
        if(target==0){
            return 0;
        }
        return jump(target);
        //return jump(0,target);
    }
    //递归的话
    public int jump(int nowLevel,int target){// 0 -> target
        if(nowLevel==target){
            return 1;
        }else if(nowLevel>target){
            return 0;
        }
        return jump(nowLevel+1,target)+jump(nowLevel+2,target);
    }
    //动态规划的话
    public int jump(int target){
        if(target==0){
            return 0;
        }
        int[] dp=new int[target+2];
        dp[target]=1;
        dp[target+1]=0;
        for(int i=target-1;i>=0;i--){
            dp[i]=dp[i+1]+dp[i+2];
        }
        return dp[0];
    }
}

JZ10 斐波那契数列

题目地址
描述
大家都知道斐波那契数列,现在要求输入一个正整数 n ,请你输出斐波那契数列的第 n 项。
斐波那契数列是一个满足fib(x) = fib(x−1)+fib(x−2) 且 fib(1)=fib(2)=1;
数据范围:1≤n≤39
要求:空间复杂度 O(1),时间复杂度 O(n) ,本题也有时间复杂度 O(logn)的解法

输入描述:
一个正整数n
返回值描述:
输出一个正整数。
示例1

输入:
4
返回值:
3
说明:
根据斐波那契数列的定义可知,fib(1)=1,fib(2)=1,fib(3)=fib(3-1)+fib(3-2)=2,fib(4)=fib(4-1)+fib(4-2)=3,所以答案为4。  

示例2

输入:
1
返回值:
1

示例3

输入:
2
返回值:
1

代码

public class Solution {
    public int Fibonacci(int n) {
        return Fib1(n);
    }
    //时间复杂度0(n)的解法
    public int Fib1(int n){
        if(n==1 || n==2){
            return 1;
        }
        //now = pre1 + pre2 ,如fib(3)=fib(2)+fib(1)
        int now=0,pre1=1,pre2=1;
        for(int i=3;i<=n;i++){
            now=pre1+pre2;
            pre2=pre1;
            pre1=now;
        }
        return now;
    }
}

JZ71 跳台阶扩展问题

题目地址
描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶(n为正整数)总共有多少种跳法。

数据范围:1≤n≤20
进阶:空间复杂度 O(1) , 时间复杂度 O(1)
示例1

输入:
3
返回值:
4

示例2

输入:
1
返回值:
1

代码

public class Solution {
    public int jumpFloorII(int target) {
        if(target==1){
            return 1;
        }
        //return jump(0,target);
        //return jumpDp(target);
        return jump3(target);
    }
    //方法一:递归
    public int jump(int nowLevel,int target){
        if(nowLevel==target){
            return 1;
        }
        int res=0;
        for(int i=1;i+nowLevel<=target;i++){
            res+=jump(nowLevel+i,target);
        }
        return res;
    }
    //方法二:动态规划
    public int jumpDp(int target){
        int[] dp=new int[target+1];
        dp[target]=1;
        for(int i=target-1;i>=0;i--){
            dp[i]=dp[i+1];
            for(int j=2;i+j<=target;j++){
                dp[i]+=dp[i+j];
            }
        }
        return dp[0];
    }
    public int jump3(int target){
        //方法三:打表找规律  --- 发现jumpDp(i) = 2^(i-1)
        /*for(int i=1;i<=20;i++){
            System.out.println(jumpDp(i));
        }*/
        return 1<<(target-1);
    }
}

JZ70 矩形覆盖

题目地址
描述
我们可以用 21 的小矩形横着或者竖着去覆盖更大的矩形。请问用 n 个 21 的小矩形无重叠地覆盖一个 2*n 的大矩形,从同一个方向看总共有多少种不同的方法?

数据范围:0 ≤ n ≤ 38
进阶:空间复杂度 0(1) ,时间复杂度 0(n)

注意:约定 n == 0 时,输出 0

比如n=3时,23的矩形块有3种不同的覆盖方法(从同一个方向看):
在这里插入图片描述
输入描述
2
1的小矩形的总个数n
返回值描述
覆盖一个2*n的大矩形总共有多少种不同的方法(从同一个方向看)
示例1

输入:
0
返回值:
0

示例2

输入:
1
返回值:
1

示例3

输入:
4
返回值:
5

代码

public class Solution {
    public int rectCover(int target) {
        //发现规律:f(1)=1,f(2)=2,f(n)=f(n-1)+f(n-2)
        if(target==0){
            return 0;
        }else if(target==1 || target==2){
            return target;
        }
        //f(n)=f(n-1)+f(n-2)
        //now = pre1 +pre2
        int now=0,pre1=2,pre2=1;
        for(int i=3;i<=target;i++){
            now=pre1+pre2;
            pre2=pre1;
            pre1=now;
        }
        return now;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值