leecode更新

This commit is contained in:
markilue 2023-02-15 14:11:44 +08:00
parent 233d50dbed
commit 4d3148c403
3 changed files with 229 additions and 0 deletions

View File

@ -0,0 +1,55 @@
package com.markilue.leecode.dynamic.second;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
*@Author: markilue
*@CreateTime: 2023-02-15 10:03
*@Description:
* TODO 力扣96题 不同的二叉搜索树:
* 给你一个整数 n 求恰由 n 个节点组成且节点值从 1 n 互不相同的 二叉搜索树 有多少种返回满足题意的二叉搜索树的种数
*@Version: 1.0
*/
public class T07_NumTrees {
@Test
public void test() {
int n = 5;
System.out.println(numTrees(n));
}
/**
* 思路:本人没有什么思路找不到状态转移方程以下是代码随想录思路:
* TODO DP五部曲:
* 1.dp定义:dp[i]表示到i的二叉搜索树有几个
* 2.dp状态转移方程:
* dp[i]如何得到可以从1到 i到 n分别做根节点之和那么以1为根节点如何得到呢
* 就是左子树没有节点dp[0]个数;右子树有dp[i-1]个节点个数(从2到n和从1到n-1的搜索数个数是一样的)
* dp[i]+=dp[0]*dp[i-1]+dp[1]*dp[i-2]+...+dp[i-1]*dp[0]
* 3.dp初始化: dp[0]=1;dp[1]=1
* 4.dp遍历顺序:从前往后
* 5.dp举例推导:以5为例
* i=2: 2
* i=3: 1*2+1*1+2*1=5
* i=4: 1*5+1*2+2*1+5*1=14
* i=5: 1*14+1*5+2*2*5*1+14*1=42
* 速度击败100%内存击败38.1%
* @param n
* @return
*/
public int numTrees(int n) {
if (n < 2) return 1;
int[] dp = new int[n + 1];
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
for (int j = 0; j < i; j++) {
dp[i] += dp[j] * dp[i - 1 - j];
}
}
return dp[n];
}
}

View File

@ -0,0 +1,94 @@
package com.markilue.leecode.dynamic.second;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
*@Author: markilue
*@CreateTime: 2023-02-15 11:27
*@Description:
* TODO 力扣416题 分割等和子集:
* 给你一个 只包含正整数 非空 数组 nums 请你判断是否可以将这个数组分割成两个子集使得两个子集的元素和相等
*@Version: 1.0
*/
public class T08_CanPartition {
@Test
public void test() {
// int[] nums = {1, 2, 3, 5};
int[] nums = {1, 5, 11, 5};
System.out.println(canPartition1(nums));
}
/**
* 思路:先求出总和然后挨个遍历可以选择要当前数或者不要当前数
* TODO 动规五部曲:
* 1.dp定义: dp[i][j]表示使用nums[0-i]能不能凑出j这个数
* 2.dp状态转移方程:
* dp[i][j] :可以选择要当前这个数 不要当前这个数(j-nums[i]这个数之前能不能凑出来)
* dp[i][j]=dp[i-1][j]||dp[i-1][j-nums[i]]
* 3.dp初始化:dp[i][0]=true; dp[0][j==nums[0]]=true;
* 4.dp遍历顺序:从上到下从前往后
* 5.dp举例推导:
* 速度击败9.4% 内存击败19.39% 53ms
* @param nums
* @return
*/
public boolean canPartition(int[] nums) {
//求和
int total = 0;
for (int num : nums) {
total += num;
}
if (total % 2 != 0) return false;
boolean[][] dp = new boolean[nums.length][total / 2 + 1];
for (int i = 0; i < dp.length; i++) {
dp[i][0] = true;
}
for (int i = 0; i < dp[0].length; i++) {
dp[0][i] = nums[0] == i;
}
for (int i = 1; i < nums.length; i++) {
for (int j = 1; j < dp[0].length; j++) {
if (j < nums[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]];
}
}
return dp[nums.length - 1][total / 2];
}
/**
* 一维dp优化
* 速度击败69.11% 内存击败51.4% 24ms
* @param nums
* @return
*/
public boolean canPartition1(int[] nums) {
//求和
int total = 0;
int max = 0;
for (int num : nums) {
total += num;
max = Math.max(max, num);
}
if (total % 2 != 0) return false;
int target = total / 2;
if (max > target) return false;//怎么也不可能到了,剪枝
boolean[] dp = new boolean[target + 1];
dp[0] = true;
for (int i = 0; i < nums.length; i++) {
for (int j = dp.length - 1; j >= nums[i]; j--) {
dp[j] = dp[j] || dp[j - nums[i]];//反向遍历避免多次
}
}
return dp[target ];
}
}

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-15 13:53
*@Description:
* TODO 力扣1049题 最后一块石头的重量II:
* 有一堆石头用整数数组 stones 表示其中 stones[i] 表示第 i 块石头的重量
* 每一回合从中选出任意两块石头然后将它们一起粉碎假设石头的重量分别为 x y x <= y那么粉碎的可能结果如下
* 如果 x == y那么两块石头都会被完全粉碎
* 如果 x != y那么重量为 x 的石头将会完全粉碎而重量为 y 的石头新重量为 y-x
* 最后最多只会剩下一块 石头返回此石头 最小的可能重量 如果没有石头剩下就返回 0
*@Version: 1.0
*/
public class T09_LastStoneWeightII {
/**
* 思路:消石头可以理解为总有一些是用来消另一些的那么可以变为让一堆+去消另一堆-
* -> 让正的那一堆和负的那一堆尽可能相等 ->让里面的其中一堆石头尽可能等于总量的一半 ->和上一题一样的思路
* 速度击败96.8% 内存击败67.2^% 2ms
* @param stones
* @return
*/
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for (int stone : stones) {
sum += stone;
}
int target = sum / 2;
int[] dp = new int[target + 1];
for (int i = 0; i < dp.length; i++) {
if (i >= stones[0]) dp[i] = stones[0];
}
for (int i = 1; i < stones.length; i++) {
for (int j = dp.length - 1; j >= stones[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
return sum - 2 * dp[target];
}
/**
* 官方提供的另一种解法判断是否能取到那个值能取到就把他减掉
* @param stones
* @return
*/
public int lastStoneWeightII1(int[] stones) {
int sum = 0;
for (int weight : stones) {
sum += weight;
}
int n = stones.length, m = sum / 2;
boolean[][] dp = new boolean[n + 1][m + 1];
dp[0][0] = true;
for (int i = 0; i < n; ++i) {
for (int j = 0; j <= m; ++j) {
if (j < stones[i]) {
dp[i + 1][j] = dp[i][j];
} else {
dp[i + 1][j] = dp[i][j] || dp[i][j - stones[i]];
}
}
}
for (int j = m;; --j) {
if (dp[n][j]) {
return sum - 2 * j;
}
}
}
}