动态规划-2-1
作者:互联网
最大子序和
-
public int crossSum(int[] nums, int left, int righ, int p){ if(left == right) return nums[left]; int leftSubsum = Integer.MIN_VALUE; int currSum = 0; for(int i=p;i > left -1; --i){ currSum += nums[i]; leftSubsum = Math.max(leftSubsum, currSum); } int rightSubsum = Integer.MIN_VALUE; currSum = 0; for(int i = p +1;i<right + 1;++i){ currSum += nums[i]; rightSubsum = Math.max(rightSubsum, currSum); } return leftSubsum + rightSubsum; } public int helper(int[] nums, int left, int right){ if(left == right) return nums[left]; int p = (left + right) / 2; int leftSum = helper(nums, left, p); int rightSum = helper(nums, p + 1, right); int crossSum = crossSum(nums, left, right, p); return Math.max(Math.max(leftSum, rightSum), crossSum); } public int maxSubArray(int[] nums){ return helper(nums, 0, nums.lenght - 1); }
爬楼梯
每步只能爬1或2个台阶,总共多少种方法。
-
暴力法:把所有可能爬的阶数进行组合,也就是1和2.
-
climbStairs(i,n)=(i+1,n)+climbStairs(i+2,n)
-
其中i定义了当前阶数,而n定义了目标阶数。
public class Solution{
public int climbStairs(int n){
climb_Stairs(0,n);
}
public int climb_Stairs(int i, int n){
if(i > n){
return 0;
}
if(i == n){
return 1;
}
return climb_Stairs(i+1, n) + climb_Stairs(i+2, n);
}
}
-
记忆化递归
-
思路:把每一步的结果存储在memo数组之中,当函数每次被调用,我们就直接从memo数组中返回结果。在memo数组的帮助下,可以得到一个修复的递归树,其大小减小到n。
-
public class Solution{ public int climbStairs(int n){ int memo[] = new int[n + 1]; return climb_Stairs(0,n,memo); } public int climb_Stairs(int i, int n, int memo[]){ if(i > n){ return 0; } if(i == n){ return 1; } if(memo[i] > 0){ return memo[i]; } memo[i] = climb_Stairs(i + 1, n, memo) + climb_Stairs(i + 2, n, memo); return memo[i]; } }
-
时间和空间复杂度为:O(n)
-
动态规划
-
思路:可以被分解为一些包含最优子结构的子问题。即他的最优解可以从其子问题的最优解来有效构建。
在i阶可以由以下的两种方法得到: 1. 在第(i-1)阶后向上爬一阶 2. 在第(i - 2)阶后向上爬2阶。
public class Solution{ public int climbStairs(int n){ if(n == 1){ return 1; } int[] dp = new int[n + 1]; dp[1] = 1; dp[2] = 2; for(int i = 3;i <= n; i++){ dp[i] = dp[i-1]+dp[i-2]; } return dp[n]; } }
方法四:斐波那契数,
public class Solution{ public climbStairs(int n){ if(n==1){ return 1; } int first = 1; int second = 2; for(int i=3;i<=n;i++){ int third = first + second; first = second; second = third; } return second; } }
方法五:Binets方法,两种方式初始化数组,第一种,将斐波那契数列的初始项修改为2和1来代替原来的1和0. 第二种,使用相同的初始化矩阵Q并使用result = Qn[0,0]得到最后的结果。
public class Solution{ public int climbStairs(int n){ int[][] q = {{1,1},{1,0}}; int res = pow(q, n); return res[0][0]; } public int[][] pow(int[][] p, int n){ int[][] ret = {{1,0},{0,1}}; while(n > 0){ if((n & 1) == 1){ //判断n是否是奇数 ret = multiply(ret,a); } n >>= 1;//n的二进制数向右移动一位 a = multiply(a, a); } return ret; } public int[][] multiply(int[][] a, int[][] b){ int[][] c = new int[2][2]; for(int i=0; i<2;i++){ for(int j=0;j<2;j++){ c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j]; } } return c; } }
不同路径
这是个杨辉三角形,每个位置的路径=该位置左边的路径+该位置上边的路径。
二维数组的动态规划
class Solution{ public int uniquePaths(int m, int n){ int[][] dp = new int[m][n]; for(int i=0;i<m;i++) dp[0][i]=1; for(int j=0;j<n;j++) dp[j][0]=1; for(int i=1;i<m;i++){ for(int j=1;j<n;j++){ dp[i][j] = dp[i-1][j] + dp[i][j-1]; } } return dp[m-1][n-1]; } }
空间压缩
public static int uniquePaths(int m, int n){ if(m<=0||n<=0){ return 0; } int less = Math.min(m,n); int more = Math.max(m,n); int[] dp = new int[less];//空间压缩,就是利用了dp暂存上一轮的值,在这一次的赋值中循环利用第一行或第一列的值都是1,因为第一行的路径只能是从左侧走过来。 Arrays.fill(dp,1); for(int i=1;i<more;i++){//转换成了一位数组 for(int j=1;j<less;j++){ dp[j] = dp[j-1] + dp[j]; } } return dp[less-1]; }
-
标签:return,int,Stairs,memo,climbStairs,动态,规划,public 来源: https://blog.csdn.net/qq_31900497/article/details/104130215