leecode更新
This commit is contained in:
parent
8c613c918d
commit
233d50dbed
|
|
@ -0,0 +1,71 @@
|
|||
package com.markilue.leecode.dynamic.second;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.dynamic.second
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-02-14 10:15
|
||||
*@Description:
|
||||
* TODO 力扣509题 斐波那契数:
|
||||
* 斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
|
||||
* F(0) = 0,F(1) = 1
|
||||
* F(n) = F(n - 1) + F(n - 2),其中 n > 1
|
||||
* 给定 n ,请计算 F(n) 。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T01_Fib {
|
||||
|
||||
/**
|
||||
* 递归:
|
||||
* 时间复杂度O(2^n)
|
||||
* 速度击败10.43% 内存击败88.93% 9ms
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public int fib(int n) {
|
||||
if (n < 2) return n;
|
||||
return fib(n - 1) + fib(n - 2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态规划法:
|
||||
* 1.dp定义:dp[i]表示n=i时的斐波那契数
|
||||
* 2.dp状态转移方程: dp[i]=dp[i-1]+dp[i-2]
|
||||
* 3.dp初始化;dp[0]=0;dp[1]=1;
|
||||
* 4.dp遍历顺序:从前往后
|
||||
* 5.dp举例推导:
|
||||
* 时间复杂度O(N)
|
||||
* 速度击败100% 内存击败33.74% 0ms
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public int fib1(int n) {
|
||||
if (n < 2) return n;
|
||||
int[] dp = new int[n + 1];
|
||||
dp[0] = 0;
|
||||
dp[1] = 1;
|
||||
for (int i = 2; i <= n; i++) {
|
||||
dp[i] = dp[i - 1] + dp[i - 2];
|
||||
}
|
||||
return dp[n];
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态规划法:一维dp优化
|
||||
* 速度击败100% 内存击败9.5%
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public int fib2(int n) {
|
||||
if (n < 2) return n;
|
||||
int dp0 = 0;
|
||||
int dp1 = 1;
|
||||
for (int i = 2; i <= n; i++) {
|
||||
int temp = dp1;
|
||||
dp1 = dp1 + dp0;
|
||||
dp0 = temp;
|
||||
}
|
||||
return dp1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package com.markilue.leecode.dynamic.second;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.dynamic.second
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-02-14 10:29
|
||||
*@Description:
|
||||
* TODO 力扣70题 爬楼梯:
|
||||
* 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
|
||||
* 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
|
||||
* 1<n<45
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T02_ClimbStairs {
|
||||
|
||||
/**
|
||||
* dp五部曲:
|
||||
* 1.dp定义:dp[i]表示有多少种方法爬到第i层
|
||||
* 2.dp状态转移方程:dp[i]=dp[i-1]+dp[i-2]从下一层上一步;从下两层上两步
|
||||
* 3.dp初始化:dp[0]=1 dp[1]=1; 原地不动
|
||||
* 4.dp遍历顺序:从前往后
|
||||
* 5.dp举例推导:
|
||||
* 速度击败100% 内存击败71.71%
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public int climbStairs(int n) {
|
||||
if (n < 2) return n;
|
||||
int[] dp = new int[n + 1];
|
||||
dp[0] = 1;
|
||||
dp[1] = 1;
|
||||
for (int i = 2; i <= n; i++) {
|
||||
dp[i] = dp[i - 1] + dp[i - 2];
|
||||
}
|
||||
return dp[n];
|
||||
}
|
||||
|
||||
/**
|
||||
* 一维dp优化
|
||||
* 速度击败100% 内存击败21.35%
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public int climbStairs1(int n) {
|
||||
if (n < 2) return n;
|
||||
int dp0 = 1;
|
||||
int dp1 = 1;
|
||||
int temp;
|
||||
for (int i = 2; i <= n; i++) {
|
||||
temp=dp1;
|
||||
dp1 = dp0 + dp1;
|
||||
dp0=temp;
|
||||
}
|
||||
return dp1;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package com.markilue.leecode.dynamic.second;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.dynamic.second
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-02-14 10:42
|
||||
*@Description:
|
||||
* TODO 力扣746题 使用最小花费爬楼梯:
|
||||
* 给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。
|
||||
* 你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。
|
||||
* 请你计算并返回达到楼梯顶部的最低花费。
|
||||
* 2 <= cost.length <= 1000
|
||||
* 0 <= cost[i] <= 999
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T03_MinCostClimbingStairs {
|
||||
|
||||
/**
|
||||
* 思路:最小
|
||||
* 1.dp定义:dp[i]表示到达第i层的最小花费
|
||||
* 2.dp状态转移方程:dp[i]=min(dp[i-2]+cost[i-2],dp[i-1]+cost[i-1])
|
||||
* 3.dp初始化:dp[0]=0;dp[1]=0:因为你可以选择从0或1位置开始爬楼梯原地不动即可
|
||||
* 4.dp遍历顺序:从前往后
|
||||
* 5.dp举例推导:
|
||||
* 速度击败100% 内存击败78.4%
|
||||
* @param cost
|
||||
* @return
|
||||
*/
|
||||
public int minCostClimbingStairs(int[] cost) {
|
||||
int[] dp = new int[cost.length + 1];
|
||||
dp[0]=0;dp[1]=0;
|
||||
|
||||
for (int i = 2; i <= cost.length; i++) {
|
||||
dp[i]=Math.min(dp[i-2]+cost[i-2],dp[i-1]+cost[i-1]);
|
||||
}
|
||||
return dp[cost.length];
|
||||
}
|
||||
|
||||
/**
|
||||
* 一维dp优化
|
||||
* @param cost
|
||||
* @return
|
||||
*/
|
||||
public int minCostClimbingStairs1(int[] cost) {
|
||||
|
||||
int dp0=0;
|
||||
int dp1=0;
|
||||
int temp;
|
||||
|
||||
for (int i = 2; i <= cost.length; i++) {
|
||||
temp=dp1;
|
||||
dp1=Math.min(dp0+cost[i-2],dp1+cost[i-1]);
|
||||
dp0=temp;
|
||||
}
|
||||
return dp1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package com.markilue.leecode.dynamic.second;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.dynamic.second
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-02-14 11:00
|
||||
*@Description:
|
||||
* TODO 力扣62题 不同路径:
|
||||
* 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
|
||||
* 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
|
||||
* 问总共有多少条不同的路径?
|
||||
* 1 <= m, n <= 100
|
||||
* 题目数据保证答案小于等于 2 * 109
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T04_UniquePaths {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int m = 3;
|
||||
int n = 7;
|
||||
System.out.println(uniquePaths(m, n));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 思路:非常标准的dp题:告诉你可以选择的思路,问题有多少种方法
|
||||
* 1.dp定义:dp[m][n]表示到达m,n位置总共的路径数
|
||||
* 2.dp状态转移方程:dp[m][n]=dp[m-1][n]+dp[m][n-1] 机器人每次只能向下或者向右移动一步
|
||||
* 3.dp初始化:dp[0][i]=1; dp[i][0]=1
|
||||
* 4.dp遍历顺序:从前往后从上到下
|
||||
* 5.dp举例推导:
|
||||
* 速度击败100% 内存击败78.89%
|
||||
* @param m
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public int uniquePaths(int m, int n) {
|
||||
|
||||
int[][] dp = new int[m][n];
|
||||
//初始化
|
||||
for (int i = 0; i < m; i++) {
|
||||
dp[i][0] = 1;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
dp[0][i] = 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];
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 一维dp优化
|
||||
* 速度击败100% 内存击败78.15%
|
||||
* @param m
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public int uniquePaths1(int m, int n) {
|
||||
|
||||
int[] dp = new int[n];
|
||||
//初始化
|
||||
for (int i = 0; i < n; i++) {
|
||||
dp[i] = 1;
|
||||
}
|
||||
|
||||
for (int i = 1; i < m; i++) {
|
||||
for (int j = 1; j < n; j++) {
|
||||
dp[j] = dp[j] + dp[j - 1];
|
||||
}
|
||||
}
|
||||
return dp[n-1];
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
package com.markilue.leecode.dynamic.second;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.dynamic.second
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-02-14 11:23
|
||||
*@Description:
|
||||
* TODO 力扣63题 不同路径II:
|
||||
* 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
|
||||
* 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
|
||||
* 现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
|
||||
* 网格中的障碍物和空位置分别用 1 和 0 来表示。
|
||||
* m == obstacleGrid.length
|
||||
* n == obstacleGrid[i].length
|
||||
* 1 <= m, n <= 100
|
||||
* obstacleGrid[i][j] 为 0 或 1
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T05_UniquePathsWithObstacles {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[][] obstacleGrid = {{0}, {1}};
|
||||
System.out.println(uniquePathsWithObstacles1(obstacleGrid));
|
||||
}
|
||||
|
||||
/**
|
||||
* dp法:核心在于遇到障碍物应该如何处理:
|
||||
* 1.dp定义:与T04一致
|
||||
* 2.dp状态转移方程:
|
||||
* if obstacleGrid[i][j]==0 :
|
||||
* dp[i][j]=dp[i-1][j]+dp[i][j-1]
|
||||
* else
|
||||
* dp[i][j]=0 //无法到达
|
||||
* 3.dp初始化;与之前一致
|
||||
* 4.dp遍历顺序:与之前一致
|
||||
* 5.dp举例推导
|
||||
* 速度击败100%,内存击败38.77%
|
||||
* @param obstacleGrid
|
||||
* @return
|
||||
*/
|
||||
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
|
||||
int[][] dp = new int[obstacleGrid.length][obstacleGrid[0].length];
|
||||
|
||||
for (int i = 0; i < dp.length; i++) {
|
||||
if (obstacleGrid[i][0] == 0) dp[i][0] = 1;
|
||||
else {
|
||||
dp[i][0] = 0;//如果这里到不了那么后面的都到不了
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < dp[0].length; i++) {
|
||||
if (obstacleGrid[0][i] == 0) dp[0][i] = 1;
|
||||
else {
|
||||
dp[0][i] = 0;//如果这里到不了那么后面的都到不了
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i < obstacleGrid.length; i++) {
|
||||
for (int j = 1; j < obstacleGrid[0].length; j++) {
|
||||
if (obstacleGrid[i][j] == 0) dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
|
||||
else dp[i][j] = 0;
|
||||
}
|
||||
}
|
||||
return dp[obstacleGrid.length - 1][obstacleGrid[0].length - 1];
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 一维dp优化
|
||||
* @param obstacleGrid
|
||||
* @return
|
||||
*/
|
||||
public int uniquePathsWithObstacles1(int[][] obstacleGrid) {
|
||||
int[] dp = new int[obstacleGrid[0].length];
|
||||
|
||||
|
||||
for (int i = 0; i < dp.length; i++) {
|
||||
if (obstacleGrid[0][i] == 0) dp[i] = 1;
|
||||
else {//如果这里到不了那么后面的都到不了
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i < obstacleGrid.length; i++) {
|
||||
dp[0] = obstacleGrid[i][0] == 0 ? 1 : 0;
|
||||
for (int j = 1; j < obstacleGrid[0].length; j++) {
|
||||
if (obstacleGrid[i][j] == 0) dp[j] = dp[j] + dp[j - 1];
|
||||
else dp[j] = 0;
|
||||
}
|
||||
}
|
||||
return dp[obstacleGrid[0].length - 1];
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package com.markilue.leecode.dynamic.second;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.dynamic.second
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-02-14 11:51
|
||||
*@Description:
|
||||
* TODO 力扣343题 整数拆分:
|
||||
* 给定一个正整数 n ,将其拆分为 k 个 正整数 的和( k >= 2 ),并使这些整数的乘积最大化。
|
||||
* 返回 你可以获得的最大乘积 。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T06_IntegerBreak {
|
||||
|
||||
/**
|
||||
* 根据证明:一个数拆成2和3的组合是最大的,依次进行递推
|
||||
* 1.dp定义; dp[i]表示i拆分后的乘积最大值
|
||||
* 2.dp状态转移方法: dp[i]=max(dp[i-2]*2,dp[i-3]*3)
|
||||
* 3.dp初始化:dp[1]=1,dp[2]=2,dp[3]=3
|
||||
* 4.dp遍历顺序:从前往后
|
||||
* 5.dp举例推导: 以10为例
|
||||
* i=4:4
|
||||
* i=5:6
|
||||
* i=6:9
|
||||
* i=7:12
|
||||
* i=8:18
|
||||
* i=9:27
|
||||
* i=10:36
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public int integerBreak(int n) {
|
||||
if(n<4)return n-1;
|
||||
|
||||
int[] dp = new int[n+1];
|
||||
dp[1]=1;dp[2]=2;dp[3]=3;
|
||||
|
||||
for (int i = 4; i <= n; i++) {
|
||||
dp[i]=Math.max(dp[i-2]*2,dp[i-3]*3);
|
||||
}
|
||||
return dp[n];
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 思路:如何未知拆成2或3最大呢? for循环,遍历拆
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
public int integerBreak1(int n) {
|
||||
int[] dp = new int[n+1];
|
||||
dp[2]=1;
|
||||
|
||||
for (int i = 2; i <= n; i++) {
|
||||
//遍历j进行拆分
|
||||
for (int j = 1; j < i; j++) {
|
||||
//这里dp[i]可以不用进行初始化,因为dp[i]一定比0大
|
||||
dp[i]=Math.max(dp[i],Math.max((i-j)*j,dp[i-j]*j));
|
||||
}
|
||||
}
|
||||
|
||||
return dp[n];
|
||||
|
||||
}
|
||||
|
||||
public int integerBreak2(int n) {
|
||||
if (n <= 3) {
|
||||
return n - 1;
|
||||
}
|
||||
int[] dp = new int[n + 1];
|
||||
dp[2] = 1;
|
||||
for (int i = 3; i <= n; i++) {
|
||||
dp[i] = Math.max(Math.max(2 * (i - 2), 2 * dp[i - 2]), Math.max(3 * (i - 3), 3 * dp[i - 3]));//这样才是合理的
|
||||
}
|
||||
return dp[n];
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue