学习笔记 -- 动态规划

参考文章如下

1. 这个动态规划分析的很详细(转载)

动态规划 基本知识点

**

动态规划

通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。

基本思想

若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。 通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量: 一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。 这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。

分治与动态规划

共同点:二者都要求原问题具有最优子结构性质,都是将原问题分而治之,分解成若干个规模较小(小到很容易解决的程序)的子问题.然后将子问题的解合并,形成原问题的解.

不同点:分治法将分解后的子问题看成相互独立的,通过用递归来做。

     动态规划将分解后的子问题理解为相互间有联系,有重叠部分,需要记忆,通常用迭代来做。

问题特征

最优子结构:当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。

重叠子问题:在用递归算法自顶向下解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只解一次,而后将其解保存在一个表格中,在以后尽可能多地利用这些子问题的解。

步骤

描述最优解的结构

递归定义最优解的值

按自底向上的方式计算最优解的值

由计算出的结果构造一个最优解

注意需要需要二维数组用容器,C++动态分配二维数组太坑爹


*****适合于用动态规划法求解的问题,经分解后得到的子问题往往不是互相独立的(即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解)

动态规划例题

1.LCS

   寻找最长子序列    ,按照下例,最长为blog 。

cnblogs

belong


public class LCS {
	public static String Lcs_str(String str1 , String str2) {
		int len1 = str1.length();
		int len2 = str2.length();
		String str_dp[][] = new String[len1 + 1][len2 + 1];
		for(int i = 0 ; i < len1 + 1; i ++ ) {
			for(int j = 0 ; j < len2 + 1 ; j ++ ) {
				if( i == 0 || j == 0 ) {
					str_dp[i][j] = "";
				}else if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
					str_dp[i][j] = str_dp[i-1][j-1] + str1.charAt(i - 1);
				}else {
					if(str_dp[i-1][j].length() >= str_dp[i][j-1].length()) {
						str_dp[i][j] = str_dp[i-1][j];
					}else {
						str_dp[i][j] = str_dp[i][j - 1];
					}
				}
			}
		}
		return str_dp[len1][len2];
	}
	public static int Lcs_int(String str1 , String str2) {
		int len1 = str1.length();
		int len2 = str2.length();
		int dp[][] = new int[len1 + 1][len2 + 1];

		for(int i = 0 ; i < len1 + 1; i ++ ) {
			for(int j = 0 ; j < len2 + 1 ; j ++ ) {
				if( i == 0 || j == 0 ) {
					dp[i][j] = 0;
				}else if (str1.charAt(i - 1) == str2.charAt(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[len1][len2];
	}
	
	public static void main(String args[]) {
		String str1 = "cnblogs";
		String str2 = "belong";
		System.out.println(Lcs_str(str1, str2));
	}
}

2. KMP

KMP主要是一个特征向量next存在。 他记载了前缀和后缀的 重复度

public class KMP {
	public static int[] getNextArr(String item) {
		int n = item.length();
		int[] next = new int[n+1];
		
		for(int i = 0 ; i < n ; i ++ ) {
			next[i] = 0;
		}
		int i = 0 , j = 1;
		while( i < n ) {
			if( j == 0 || item.charAt(i) == item.charAt(j)) {
				i ++;
				j ++;
				next[i] = j;
			}else {
				j = next[j];
			}
		}
		return next;
	}
	/*
	 * -2 长度不匹配
	 * -1 找不到
	 * 1 - n 匹配成功,str1 出现的第一个位置
	 * 
	 * 
	 * 对于str1,str2空 没有考虑
	 */
	public static int kmp(String str1 , String str2) {
		int[] next = getNextArr(str2);
		if(str1.length() < str2.length()) {
			return -2;
		}else {
			int pos = 0;
			pos = next[pos];
			for(int i = 0 ; i < str1.length() ; i ++ ) {
	
				if(str1.charAt(i) == str2.charAt(pos) && pos == str2.length() - 1) {
					return (i - str2.length() + 2);
				}else if( str1.charAt(i) == str2.charAt(pos) ) {
					pos ++;
				}else {
					pos = next[pos];
				}
			}
			return -1;
		}
	}
	
	public static void main(String args[]) {
		System.out.println(kmp("abasdasdabcabasdasdqggd", "abcab"));
	}
}

3 . 最长回文子串

dp[ i ][ j ]  == 1 表示  从  i 到 j 的字符串为 回文子串。

第一步 :初步寻找 len = 2 ,   str[ i ]  == str[ i + 1 ]   则得出  dp[ i ][ i + 1 ]  = 1;  形成一个 从 i  到  i + 1  的回文子串。

第二步 : 然后判断  dp[i][j] == 1 && str[ i - 1 ] == str[ j + 1] ;  则  len ++ ;

.

.

.

4 .

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值