leecode更新

This commit is contained in:
markilue 2023-02-14 14:02:45 +08:00
parent 8c613c918d
commit 233d50dbed
6 changed files with 454 additions and 0 deletions

View File

@ -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) = 0F(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;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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