动态规划---序列问题(最长公共,最长递增,最长公共递增,最长数对,最长摆动)

2024-02-08 06:38

本文主要是介绍动态规划---序列问题(最长公共,最长递增,最长公共递增,最长数对,最长摆动),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.最长递增子序列

    /** 最长递增子序列* */public int lengthOfLIS(int[] nums) {//方案一:时间复杂度0(N^2)int n = nums.length;if (n == 0) return 0;int dp[] = new int[n];//dp[i]表示以i元素结尾最长递增子序列的长度dp[0] = 1;int maxL = 1;for (int i = 1; i < n; i++) {dp[i] = 1;//注意这个位置for (int j = 0; j < i; j++) {if (nums[j] < nums[i]) {dp[i] = Math.max(dp[i], dp[j] + 1);}}maxL = Math.max(maxL, dp[i]);}return maxL;}/** 维持一个有序数组tail[],tail[i]表示递增子序列长度为i+1时,最末尾的最小元素.* */public int lengthOfLIS2(int[] nums) {//方案二:时间复杂度0(NlogN)int n = nums.length;if (n == 0) return 0;int tail[]=new int[nums.length];tail[0]=nums[0];int j=0;/** 遍历所有元素。* 如果它大于 tails 数组所有的值,那么把它添加到 tails 后面,表示最长递增子序列长度加 1* 如果 tails[i-1] < x <= tails[i],那么更新 tails[i] = x。* */for(int i=1;i<nums.length;i++){int index=binarySearch(tail,j,nums[i]);tail[index]=nums[i];if(index==j+1) j++;}return j+1;}public int binarySearch(int a[],int count,int k){//找到第一个大于或等于k的元素索引(找到大于等于k的最小元素的索引),如果找不到返回count+1int start=0;int end=count;int index=-1;int elem=Integer.MAX_VALUE;while (start<=end){int mid=(start+end)/2;if(k<=a[mid]){if(a[mid]<elem) {elem = a[mid];index = mid;}end=mid-1;}else{start=mid+1;}}return index==-1?count+1:index;}

2. 一组整数对能够构成的最长链

/** 最长数对链* 题目描述:* 给出 n 个数对。 在每一个数对中,第一个数字总是比第二个数字小。* 现在,我们定义一种跟随关系,当且仅当 b < c 时,数对(c, d) 才可以跟在 (a, b) 后面。我们用这种形式来构造一个数对链。* 给定一个对数集合,找出能够形成的最长数对链的长度。你不需要用到所有的数对,你可以以任何顺序选择其中的一些数对来构造。* *///动态规划方法解决public int findLongestChain(int[][] pairs) {int num = 0;int n = pairs.length;if (n == 0) return 0;Arrays.sort(pairs, new Comparator<int[]>() {@Overridepublic int compare(int[] o1, int[] o2) {return o1[0] - o2[0];}});int dp[] = new int[n];//dp[i]表示以第i个数对结尾的最大长度int max = 1;for (int i = 0; i < pairs.length; i++) {dp[i] = 1;for (int j = 0; j < i; j++) {if (pairs[i][0] > pairs[j][1]) {dp[i] = Math.max(dp[i], dp[j] + 1);}}max = Math.max(max, dp[i]);}return max;}//贪心方法解决public int findLongestChain2(int[][] pairs) {/** 优先选择数对 尾值更小的,给 组合后面的数对 留更多的机会* */if (pairs == null || pairs.length == 0) return 0;int n = pairs.length;Arrays.sort(pairs, new Comparator<int[]>() {@Overridepublic int compare(int[] o1, int[] o2) {return o1[1] - o2[1];}});int curEnd = pairs[0][1];int sum = 1;for (int i = 1; i < n; i++) {if (pairs[i][0] > curEnd) {sum++;curEnd = pairs[i][1];}}return sum;}

3.最长摆动子序列

 /** 摆动序列* 题目描述:如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。* 给定一个整数序列,返回作为摆动序列的最长子序列的长度。 通过从原始序列中删除一些(也可以不删除)元素来获得子序列,剩下的元素保持其原始顺序。* 思路:见程序中注释* 解释:up,down的每一次更新(up=down+1,down=up+1),都意味着更新了 最长摆动子序列的末尾curEnd,虽然最长长度可能没更新。* 连续上升(下降),最长长度不会变,变的是最长摆动子序列的末尾curEnd* (隐晦一点解释:有升才有降,有降才有升)* */public int wiggleMaxLength(int[] nums) {int down = 1;//down维护了此时 摆动序列以down操作结尾的 最长长度int up = 1; //up维护了此时 摆动序列以up操作结尾的 最长长度for (int i = 1; i < nums.length; i++) {if (nums[i] > nums[i - 1]) {up = down + 1;//up在down的基础上上升} else if (nums[i] < nums[i - 1]) {down = up + 1;//down在up的基础上下降}}/** 解决质疑:*  1.连续下降时,程序为什么将curEnd更新为后面的,也就是说为什么curEnd会更新为越小的值?*  因为在等待下一次上升时,只要比curEnd大,就可以完成上升操作。所以curEnd越小,上升的机会就越大,那么累计的序列就越长*  2.会不会出现  在等待下降时,隔了很多个元素才满足下降条件,就累计不到了  这种情况?*  不会。例如序列[4,5,7,8,9,3] 在4等待下降时,直观来看,4和3之间隔了很多个元素,这几个元素一定都会比4大, 程序早已将curEnd更新为了9,9>3则累计。*  再例如序列[4,9,6,8,7,3] 在4等待下降时,直观来看,4和3之间隔了很多元素, 这些元素呈现了一个摆动状态,能确保者之间的摆动被累计了吗?*  可以确保,其实,当元素遍历到9时curEnd不再是4,而是9了(虽然最长长度没更新,但最长摆动子序列的末尾curEnd被更新了),然后再继续累计9下降到6的情况,以此类推。* */return Math.min(nums.length, Math.max(down, up));}

4.最长公共子序列

 /**  dp[i][j]表示S1前i个字符和S2前j个字符的最长公共子序列的长度值* 当 S1i==S2j 时,那么就能在 S1 的前 i-1 个字符与 S2 的前 j-1 个字符最长公共子序列的基础上再加上 S1i 这个值,最长公共子序列长度加 1,即 dp[i][j] = dp[i-1][j-1] + 1。* 当 S1i != S2j 时,此时最长公共子序列为 S1 的前 i-1 个字符和 S2 的前 j 个字符最长公共子序列,或者 S1 的前 i 个字符和 S2 的前 j-1 个字符最长公共子序列,取它们的最大者,即 dp[i][j] = max{ dp[i-1][j], dp[i][j-1] }。* */public int longestCommonSubsequence2(String S1, String S2) {int len1 = S1.length();int len2 = S2.length();if (len1 == 0 || len2 == 0) return 0;int dp[][]=new int[len1+1][len2+1];int book[][]=new int[len1+1][len2+1];//记录dp[i][j]的更新情况,找到最长公共子序列for(int i=1;i<=len1;i++){for(int j=1;j<=len2;j++){if(S1.charAt(i-1)==S2.charAt(j-1)){dp[i][j]=dp[i-1][j-1]+1;book[i][j]=1;//代表最大值在此时更新}else{if(dp[i-1][j]>dp[i][j-1]){dp[i][j]=dp[i-1][j];book[i][j]=2;//代表更新为dp[i-1][j]的值}else{dp[i][j]=dp[i][j-1];book[i][j]=3;//代表更新为dp[i][j-1]的值}}}}int i=len1,j=len2;while (i>=0&&j>=0){if(book[i][j]==1) {System.out.print(S1.charAt(i-1)+" ");i--;j--;}else if(book[i][j]==2) i--;else j--;}return dp[len1][len2];//最长公共子序列的长度}

5.最长公共递增子序列

public class MaxLenOfCommonIncrease {//只过了80%,超时了public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();while (n-- != 0) {int l1 = scanner.nextInt();int s1[] = new int[l1];for (int i = 0; i < l1; i++) {s1[i] = scanner.nextInt();}int l2 = scanner.nextInt();int s2[] = new int[l2];for (int j = 0; j < l2; j++) {s2[j] = scanner.nextInt();}int dp[][] = new int[l1][l2];//dp[i][j]表示s1列表中前i个元素,s2列表中前j个元素,并且以s2[j]为末尾的最长公共递增序列的长度for(int j=0;j<l2;j++) dp[0][j]= s1[0]==s2[j]?1:0;for(int i=0;i<l1;i++) dp[i][0]= s2[0]==s1[i]?1:0;for(int i=1;i<l1;i++){for(int j=1;j<l2;j++){dp[i][j]=dp[i-1][j];if(s1[i]==s2[j]){for(int k=0;k<j;k++){if(s2[j]>s2[k]) dp[i][j]=Math.max(dp[i][j],dp[i-1][k]+1);}dp[i][j]=Math.max(1,dp[i][j]);}}}int res = 0;for (int j = 0; j < l2; ++j)res = Math.max(res, dp[l1-1][j]);System.out.println(res);}}
}
/*
这种方法可以全过,但不是很懂public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();while (n-- != 0) {int l1 = scanner.nextInt();int s1[] = new int[l1];for (int i = 0; i < l1; i++) {s1[i] = scanner.nextInt();}int l2 = scanner.nextInt();int s2[] = new int[l2];for (int j = 0; j < l2; j++) {s2[j] = scanner.nextInt();}int dp[][] = new int[505][505];for (int i = 0; i <l1; i++) {int max = 0;for (int j = 0; j <l2; j++) {dp[i + 1][j + 1] = dp[i][j + 1];if (s1[i] > s2[j])max = Math.max(max, dp[i][j + 1]);if (s1[i] == s2[j]) {dp[i + 1][j + 1] = max + 1;}}}int res = 0;for (int j = 1; j <= l2; ++j)res = Math.max(res, dp[l1][j]);System.out.println(res);}}*/

这篇关于动态规划---序列问题(最长公共,最长递增,最长公共递增,最长数对,最长摆动)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/690185

相关文章

详谈redis跟数据库的数据同步问题

《详谈redis跟数据库的数据同步问题》文章讨论了在Redis和数据库数据一致性问题上的解决方案,主要比较了先更新Redis缓存再更新数据库和先更新数据库再更新Redis缓存两种方案,文章指出,删除R... 目录一、Redis 数据库数据一致性的解决方案1.1、更新Redis缓存、删除Redis缓存的区别二

oracle数据库索引失效的问题及解决

《oracle数据库索引失效的问题及解决》本文总结了在Oracle数据库中索引失效的一些常见场景,包括使用isnull、isnotnull、!=、、、函数处理、like前置%查询以及范围索引和等值索引... 目录oracle数据库索引失效问题场景环境索引失效情况及验证结论一结论二结论三结论四结论五总结ora

element-ui下拉输入框+resetFields无法回显的问题解决

《element-ui下拉输入框+resetFields无法回显的问题解决》本文主要介绍了在使用ElementUI的下拉输入框时,点击重置按钮后输入框无法回显数据的问题,具有一定的参考价值,感兴趣的... 目录描述原因问题重现解决方案方法一方法二总结描述第一次进入页面,不做任何操作,点击重置按钮,再进行下

解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题

《解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题》本文主要讲述了在使用MyBatis和MyBatis-Plus时遇到的绑定异常... 目录myBATis-plus-boot-starpythonter与mybatis-spring-b

mysql主从及遇到的问题解决

《mysql主从及遇到的问题解决》本文详细介绍了如何使用Docker配置MySQL主从复制,首先创建了两个文件夹并分别配置了`my.cnf`文件,通过执行脚本启动容器并配置好主从关系,文中还提到了一些... 目录mysql主从及遇到问题解决遇到的问题说明总结mysql主从及遇到问题解决1.基于mysql

如何测试计算机的内存是否存在问题? 判断电脑内存故障的多种方法

《如何测试计算机的内存是否存在问题?判断电脑内存故障的多种方法》内存是电脑中非常重要的组件之一,如果内存出现故障,可能会导致电脑出现各种问题,如蓝屏、死机、程序崩溃等,如何判断内存是否出现故障呢?下... 如果你的电脑是崩溃、冻结还是不稳定,那么它的内存可能有问题。要进行检查,你可以使用Windows 11

如何安装HWE内核? Ubuntu安装hwe内核解决硬件太新的问题

《如何安装HWE内核?Ubuntu安装hwe内核解决硬件太新的问题》今天的主角就是hwe内核(hardwareenablementkernel),一般安装的Ubuntu都是初始内核,不能很好地支... 对于追求系统稳定性,又想充分利用最新硬件特性的 Ubuntu 用户来说,HWEXBQgUbdlna(Har

MAVEN3.9.x中301问题及解决方法

《MAVEN3.9.x中301问题及解决方法》本文主要介绍了使用MAVEN3.9.x中301问题及解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录01、背景02、现象03、分析原因04、解决方案及验证05、结语本文主要是针对“构建加速”需求交

如何用Python绘制简易动态圣诞树

《如何用Python绘制简易动态圣诞树》这篇文章主要给大家介绍了关于如何用Python绘制简易动态圣诞树,文中讲解了如何通过编写代码来实现特定的效果,包括代码的编写技巧和效果的展示,需要的朋友可以参考... 目录代码:效果:总结 代码:import randomimport timefrom math

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字