剑指offer--动态规划
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种不同的覆盖方法(从同一个方向看):
输入描述
21的小矩形的总个数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;
}
}