动态规划总结

最长递增子序列AC

最长公共子序列AC

最长公共子串AC

最小编辑代价AC

最长公共子序列和最长公共子串的区别

1.递推公式求解dp

子序列:

s1[i-1]==s2[j-1]  dp[i][j]=dp[i-1][j-1]+1

s1[i-1]!=s2[j-1]  dp[i][j]=max(dp[i-1][j], dp[i][j-1])

子串:

s1[i-1]==s2[j-1]  dp[i][j]=dp[i-1][j-1]+1

s1[i-1]!=s2[j-1]  dp[i][j]=0

2.返回结果

子序列:之间返回矩阵右下角的值

子串:需要遍历矩阵寻找最大值

最长递增子序列AC

package dp;
/**
最长递增子序列(LIS)


题目描述:
给定数组arr,返回arr的最长递增子序列。
比如arr={2,1,5,3,6,4,8,9,7},返回的最长递增子序列为[1,3,4,8,9],这个子序列的长度5。
*/
//时间复杂度O(n^2)
//nowcoder pass
public class AscentSequence {
    public int findLongest(int[] arr, int n) {
    	int[] dp = new int[n];
    	int maxLen = 1;
    	for (int i = 0; i < n; i++) {
    		dp[i] = 1;
    		for (int j = 0; j < i; j++) {
    			if (arr[j] < arr[i] && dp[i] < dp[j]+1) {
    				dp[i] = dp[j]+1;
    				maxLen = Math.max(maxLen, dp[i]);
    			}
    		}
    	}
    	
    	return maxLen;
    }
}

最长公共子序列AC

要注意与最长公共子串的递归公式的区别

s1[i-1]==s2[j-1]  dp[i][j]=dp[i-1][j-1]+1

s1[i-1]!=s2[j-1]  dp[i][j]=max(dp[i-1][j], dp[i][j-1])

package dp;
/**
最长公共子序列


题目描述
对于两个字符串,请设计一个高效算法,求他们的最长公共子序列的长度.
测试样例:
"1A2C3D4B56",10,"B1D23CA45B6A",12
返回:6


思路:经典的动态规划问题
str1长度为m,str2长度为n
dp[m+1][n+1]
dp[i][j]表示str1[0...i-1]与str2[0...j-1]的最长公共子序列的长度
递推公式:
str1[i-1]==str2[j-1]  dp[i][j]=dp[i-1][j-1]+1
str1[i-1]!=str2[j-1]  dp[i][j]=max(dp[i-1][j], dp[i][j-1])


多出来的一行和一列是第 0 行和第 0 列,
初始化为 0,表示空字符串和另一字符串的子串的最长公共子序列
str1="app",str2="apple",dp[0][3]表示 “” 和 “app” 的最长公共字串。
 */
//nowcoder pass
public class LCSubsequence {


    public int findLCS(String str1, int m, String str2, int n) {
    	if (str1 == null || str2 == null) {
    		return 0;
    	}
    	
    	int[][] dp = new int[m+1][n+1];
    	char[] s1 = str1.toCharArray();
    	char[] s2 = str2.toCharArray();
    	for (int i = 1; i <= m; i++) {
    		for (int j = 1; j <= n; j++) {
    			if (s1[i-1] == s2[j-1]) {
    				dp[i][j] = dp[i-1][j-1] + 1;
    			} else {
    				dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
    			}
    		}
    	}
    	return dp[m][n];
    }
}

最长公共子串AC

要注意与最长公共子序列的递归公式的区别

s1[i-1]==s2[j-1]  dp[i][j]=dp[i-1][j-1]+1

s1[i-1]!=s2[j-1]  dp[i][j]=0

package dp;
/**
最长公共子串


题目描述:
对于两个字符串,请设计一个时间复杂度为O(m*n)的算法(这里的m和n为两串的长度),
求出两串的最长公共子串的长度。这里的最长公共子串的定义为两个序列U1,U2,..Un和V1,V2,...Vn,
其中Ui + 1 == Ui+1,Vi + 1 == Vi+1,同时Ui == Vi。
给定两个字符串A和B,同时给定两串的长度n和m。
测试样例:
"1AB2345CD",9,"12345EF",7
返回:4


思路:动态规划问题
s1长度为m,s2长度为n
dp[m+1][n+1]
递推公式:
s1[i-1]==s2[j-1]  dp[i][j]=dp[i-1][j-1]+1
s1[i-1]!=s2[j-1]  dp[i][j]=0
 */
//nowcoder pass
public class LCSubstring {
    public int findLongest(String str1, int m, String str2, int n) {
    	
    	char[] s1 = str1.toCharArray();
    	char[] s2 = str2.toCharArray();
    	int[][] dp = new int[m+1][n+1];


    	int maxLen = 0;
    	for (int i = 1; i <= m; i++) {
    		for (int j = 1; j <= n; j++) {
    			if (s1[i-1] == s2[j-1]) {
    				dp[i][j] = dp[i-1][j-1]+1;
    				maxLen = Math.max(maxLen, dp[i][j]);
    			} else {
    				dp[i][j] = 0;//求dp时,和最长公共子序列仅这一行的区别
    			}
    		}
    	}
    	
    	return maxLen;
    }
}

最小编辑代价AC

package dp;
/**
最小编辑代价


题目描述:
对于两个字符串A和B,我们需要进行插入、删除和修改操作将A串变为B串,
定义c0,c1,c2分别为三种操作的代价,请设计一个高效算法,求出将A串变为B串所需要的最少代价。
给定两个字符串A和B,及它们的长度和三种操作代价,请返回将A串变为B串所需要的最小代价。
保证两串长度均小于等于300,且三种代价值均小于等于100。
测试样例:
"abc",3,"adc",3,5,3,100
返回:8


思路:动态规划
 */
//nowcoder pass
public class MinEditCost {
	
    public int findMinCost(String str1, int m, String str2, int n, int ic, int dc, int rc) {
    	
    	char[] s1 = str1.toCharArray();
    	char[] s2 = str2.toCharArray();
    	int[][] dp = new int[m+1][n+1];
    	//第一行
    	for (int i = 0; i <= n; i++) {
    		dp[0][i] = i*ic;
    	}
    	//第一列
    	for (int i = 0; i <= m; i++) {
    		dp[i][0] = i*dc;
    	}
    	
    	for (int i = 1; i <= m; i++) {
    		for(int j = 1; j <= n; j++) {
    			if (s1[i-1] == s2[j-1]) {
    				dp[i][j] = dp[i-1][j-1];
    			} else {
    				dp[i][j] = dp[i-1][j-1] + rc;
    			}
    			dp[i][j] = Math.min(dp[i][j], dp[i-1][j]+dc);
    			dp[i][j] = Math.min(dp[i][j], dp[i][j-1]+ic);
    		}
    	}
    	return dp[m][n];
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值