当前位置:网站首页>动态规划、背包问题 6/26 116-120
动态规划、背包问题 6/26 116-120
2022-08-10 05:36:00 【吉良吉影__.】
1.最长递增子序列( LeetCode 300 )
方法一:动态规划
此题解还有二分 + 贪心,目前难度较大,暂时放一放
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int ans = 1;
//dp[i] = 已i下标处结尾的最长递增子序列长度
int[] dp = new int[n];
dp[0] = 1;
for (int i = 1; i < n; i++) {
int max = 0;
//寻找以本节点结尾可以获得的最大长度
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i])
max = Math.max(max,dp[j]);
}
dp[i] = max + 1;//求得了以本节点结尾的最长子序列长度
ans = Math.max(ans,dp[i]);
}
return ans;
}
}
2.最长连续递增序列( LeetCode 674 )
class Solution {
public int findLengthOfLCIS(int[] nums) {
int n = nums.length;
//dp[i] = 以第i个元素结尾的最长连续子序列长度
int[] dp = new int[n];
dp[0] = 1;
int ans = 1;
for (int i = 1; i < n; i++) {
dp[i] = nums[i] > nums[i - 1] ? dp[i - 1] + 1 : 1;
ans = Math.max(ans,dp[i]);
}
return ans;
}
}
3.分割等和子集( LeetCode 416 )01背包
方法一:动态规划
时间复杂度O(NM)
空间复杂度O(NM)
//分割等和子集
class Solution {
public boolean canPartition(int[] nums) {
int sum = 0;
for (int x:nums) sum += x;
int target = sum / 2;
if (target * 2 != sum)return false;//如果sum为奇数则不能拆分为等和子集
//问题转化为能不能从nums中选出一些元素和为target
//dp[i][j] = 从前i个元素中进行选取,总和不超过j的最大值
int[][] dp = new int[nums.length][target + 1];
//初始化第一行,只有nums[0] <= i才能装进背包
for (int i = 0; i <= target; i++) {
dp[0][i] = nums[0] <= i ? nums[0] : 0;
}
for (int i = 1; i < nums.length; i++) {
for (int j = 0; j <= target; j++) {
//不选第i个元素的最大价值
int no = dp[i - 1][j];
//选第i个元素的最大价值
int yes = nums[i] <= j ? dp[i - 1][j - nums[i]] + nums[i] : 0;
dp[i][j] = Math.max(no,yes);
}
}
return dp[nums.length - 1][target] == target;
}
}
方法二:动态规划 优化
滚动数组优化
时间复杂度O(NM)
空间复杂度O(M)
//分割等和子集
class Solution {
public boolean canPartition(int[] nums) {
int sum = 0;
for (int x:nums) sum += x;
int target = sum / 2;
if (target * 2 != sum)return false;//如果sum为奇数则不能拆分为等和子集
//问题转化为能不能从nums中选出一些元素和为target
//dp[i][j] = 从前i个元素中进行选取,总和不超过j的最大值
int[][] dp = new int[2][target + 1];
//初始化第一行,只有nums[0] <= i才能装进背包
for (int i = 0; i <= target; i++) {
dp[0][i] = nums[0] <= i ? nums[0] : 0;
}
for (int i = 1; i < nums.length; i++) {
for (int j = 0; j <= target; j++) {
//不选第i个元素的最大价值
//(i - 1) & 1 上一行对应的行下标
int no = dp[(i - 1) & 1][j];
//选第i个元素的最大价值
int yes = nums[i] <= j ? dp[(i - 1) & 1][j - nums[i]] + nums[i] : 0;
//i & 1本行对应的行下标
dp[i & 1][j] = Math.max(no,yes);
}
}
return dp[(nums.length - 1) & 1][target] == target;
}
}
方法三:动态规划 优化
一维数组优化
时间复杂度O(NM)
空间复杂度O(M)
//分割等和子集
class Solution {
public boolean canPartition(int[] nums) {
int sum = 0;
for (int x:nums) sum += x;
int target = sum / 2;
if (target * 2 != sum)return false;//如果sum为奇数则不能拆分为等和子集
//问题转化为能不能从nums中选出一些元素和为target
//dp[j] = 总和不超过j的最大值
int[] dp = new int[target + 1];
for (int num: nums) {
//前i个元素中选取
//逆序填充dp数组
for (int i = target; i >= num ; i--) {
//选与不选第i个元素的最大值
dp[i] = Math.max(dp[i],dp[i - num] + num);
}
}
return dp[target] == target;
}
}
4.最长重复子数组( LeetCode 718 )
动态规划
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int n = nums1.length;
int m = nums2.length;
int ans = 0;
//dp[i][j] = 以nums1中下标i结尾,nums2中下标j结尾的最长公共子数组
int[][] dp = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (nums1[i] == nums2[j]){
//相等查看前一个元素的最长子数组
dp[i][j] = (i - 1 >= 0 && j - 1 >= 0) ? dp[i - 1][j - 1] + 1 : 1;
}else {
//不相等,公共子数组长度为0
dp[i][j] = 0;
}
ans = Math.max(ans,dp[i][j]);
}
}
return ans;
}
}
5.最长公共子序列( LeetCode 1143 )
动态规划
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int m = text1.length();
int n = text2.length();
/* dp[i][j] = text1下标i及i之前,text2下标j及j之前的最长公共子序列 在i,j处有两种情况 情况一:text1[i] = text2[j] dp[i][j] = dp[i - 1][j - 1] + 1; 情况二:text1[i] != text2[j] dp[i][j] = Math.max(dp[i - 1][j],dp[j - 1][i]); */
int[][] dp = new int[m][n];
int ans = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int x = j - 1 >= 0 ? dp[i][j - 1] : 0;//dp[i,j - 1]
int y = i - 1 >= 0 ? dp[i - 1][j] : 0;//dp[i - 1 ,j]
int z = (j - 1 >= 0 && i - 1 >= 0) ? dp[i - 1][j - 1] : 0;//dp[i - 1][j - 1]
if (text1.charAt(i) == text2.charAt(j)){
dp[i][j] = 1 + z;
}else {
dp[i][j] = Math.max(x,y);
}
ans = Math.max(ans,dp[i][j]);
}
}
return ans;
}
}
边栏推荐
猜你喜欢
随机推荐
最简单的字符设备驱动
碳酸锂、碳酸氢锂溶液除钙镁离子工艺原理
开源游戏服务器框架NoahGameFrame(NF)简介(一)
动态规划、背包问题 6/22 96-100
51单片机营养液自动配置搅拌系统TDS浓度采集自动加水加营养液
STM32单片机LORA无线远程火灾报警监控系统DS18B20MQ2火焰检测
观察者模式-数据池
C陷阱与缺陷 个人阅读笔记
每日刷题(day03)——leetcode 899. 有序队列
手把手教你改内核源码--sysfs虚拟文件系统1
STC12C5A60S2单片机WIFI信号扫描报警监视系统信号增强信号过低报警
51单片机智能远程遥控温控PWM电风扇系统红外遥控温度速度定时关机
二次元卡通渲染之描边
Unity中采用二进制存档与读档
KDE框架介绍
I don't like my code
在Unity中判断游戏物体是否在游戏屏幕范围之内
常用模块封装-csv文件操作封装
(Flutter报错)Cannot run with sound null safety, because the following dependencies
在Unity的Update中通过物体自身位置判断运动方向









