动态规划学习记录

参考链接

总结
动态规划特点,从已知数据状态,推断出下一个数据状态。例如:{A1->A2}; {A1, A2->A3}; {A1,A2,A3->A4};……; {A1,A2,...,Ai}->Ai+1.
在这里插入图片描述

  1. 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。

  2. 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。

  3. 有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势)

常见问题

  • 斐波那契数列
    当前数据由前两种状态共同绝对,符合动态规范算法
	int solutionFibonacci(int n) {
		if (n <= 1) {
			return n;
		} else {
			int[] result = new int[n+1];
			result[0] = 0;
			result[1] = 1;
			for (int i = 2; i <= n; i++) {
				result[i] = result[i-1] + result[i-2];
			}
			return result[n];
		}
	}
  • 跳台阶问题:每次只能跳一个或者两个台阶,跳到n层台阶上有几种方法
    假设当前为第N台阶,那么上一次状态的位置只能是N-1或者N-2,只有这两种状态,符合动态规范算法
	public int JumpFloor(int target) {
		if (target <= 1) {
			return target;
		}
		int[] a = new int[target + 1];
		a[1] = 1;
		a[2] = 2;
		for (int i = 3; i <= target; i++) {
			a[i] = a[i - 1] + a[i - 2];
		}
		return a[target];
	}

同理,那如果:可以跳一个或者两个台阶或者三个台阶
那么F(n)=F(n-1) + F(n-2) + F(n-3),其中n>3

这类问题与找零钱一致,比如100块,可以换10块,或者20块的组合有多少种,类似于一次跳一个或者两个台阶,当前台阶为10

填充长方体问题:将一个2*1的长方体填充到2*n的长方体中,有多少种方法(同上)
在这里插入图片描述

  • 数组最大不连续递增子序列

这个是由于当前的数字Xn是否比前面的数字Xm大,若Xn>Xm,与Xn<Xm两种情况,符合动态规范

	public static int maxContinueSequence(int[] arr) {
		int[] result = new int[arr.length];
		for (int i = 0; i < arr.length; i++) {
			result[i] = 1;
		}
		
		for (int i = 1; i < arr.length; i++) {
			for (int j = 0; j < i; j++) {
				if (arr[j] < arr[i] && (result[j] + 1) > result[i]) {
					result[i] = result[j] + 1;
				}
			}
		}
		
		int max = 0;
		for (int i = 1; i < result.length; i++) {
			if (result[max] < result[i]) {
				max = i;
			}
		}
		return result[max];
	}
  • 数组最大连续子序列和
    当前数字之和Xm是不是最大,取决于要不要加入前一个数字的状态和,两种状态,符合动态规范
	public static int maxContinueSequenceSum(int[] arr) {
		int max = arr[0];
		for (int i = 1; i < arr.length; i++) {
			if ((max + arr[i]) > arr[i]) {
				max = max + arr[i]; 
			} else {
				max = arr[i];
			}
		}
		return max;
	} 
  • 数字塔从上到下所有路径中和最大的路径
    只有两种走法,红色的只能由蓝色两个而来,符合动态规划
    在这里插入图片描述
	public static int maxPathSum(int[][] dataArray) {
		int size = dataArray.length;
		
		int[][] result = new int[size+1][size+1];
		for (int i = 0; i < size; i++) {
			result[i][0] = 0;
			result[0][i] = 0;
		}
		
		int max = 0;
		for (int i = 1; i <= size; i++) {
			for (int j = 1; j <= i; j++) {
				if (result[i-1][j-1] > result[i-1][j]) {
					result[i][j] = result[i-1][j-1] + dataArray[i-1][j-1];
				} else {
					result[i][j] = result[i-1][j] + dataArray[i-1][j-1];
				}
				if (max < result[i][j]) {
					max = result[i][j];
				}
			}
		}
		
		return max;
	}
  • 两个字符串最大公共子序列
    只有相等或者不等的情况,不相等,前移一个位置,重复这个操作,符合动态规划
public static int maxContinueEqualArrayLength(String str1, String str2) {
		int m = str1.length();
		int n = str2.length();
		
		int[][] dp = new int[m+1][n+1];
		for (int i = 0; i < m; i++) {
			dp[i][0] = 0;
		}
		for (int i = 0; i < n; i++) {
			dp[0][i] = 0;
		}
		
		int max = 0;
		for (int i = 1; i <= m; i++) {
			char c1 = str1.charAt(i-1);
			for (int j = 1; j <= n; j++) {
				char c2 = str2.charAt(j-1);
				if (c1 == c2) {
					dp[i][j] = dp[i-1][j-1] + 1;
				} else {
					dp[i][j] = dp[i-1][j] > dp[i][j-1] ? dp[i-1][j] : dp[i][j-1]; 
				}
				if (dp[i][j] > max) {
					max = dp[i][j];
				}
			}
		}

		return max;
	}
  • 背包问题
	// i是第几件物品,j表示物品的重量,dp[i][j]表示价值
	// DP: dp[i][j] 表示j的背包中装进前i件物品所得到的最大价值。
	// 递推关系:dp[i][j] = max {dp[i - 1][j], dp[i - 1][j - weight[i]] + price[i]};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值