动态规划的一般解决方案

一、问题描述

解决动态规划问题,首先要判断是否需要用到动态规划。

可以使用动态规划的问题一般都遵循一些特点,比如提问的方式一般是:

1. 计数

有多少种方式走到右下角有多少种方法选出K个数使得和是Sum

2. 求最大最小值

从左上角到右下角路径的最大数字和最长上升子序列长度

3. 求存在性

取石子游戏,先手是否必胜能不能选出K个数字使得和是Sum。

针对以上最优解问题,往往可以先尝试动态规划的方法。这就需要我们首先找到构成最优问题的最优子问题,然后确定状态转移方程,问题便迎刃而解了。

二、解决方案

四步轻松搞定99%的动规题

1.确定状态是什么
2.状态转移方程是什么
3.状态的初始值是什么
4.问题要求的最后答案是什么

扫描二维码关注公众号,回复: 11478384 查看本文章

三、实例

1.题目

2.思路

首先第一步,我们需要定义dp数组的含义,定义二维布尔数组dp[i][j]数组表示:

dp[i][j]表示字符串s[i, j]范围内字符是否为回文串,i从后向前遍历,j从i位置向后遍历。

如果s[i] == s[j],那么i和j满足下面两个条件之一,则dp[i][j] = true。

    1、如果i和j相邻或只隔着一个字符,则dp[i][j] = true
    2、否则如果dp[i + 1][j - 1] = true,则dp[i][j] = true

if(s[i]) == s[j]){
    dp[i][j] = dp[i+1][j-1];
}else{
    dp[i][j] = false;
}

如果s[i]≠s[j]那么说明dp[i][j]必定不是回文子串。

3.代码

public:
	int countSubstrings(string s) {
		if (s.empty()) return 0;
		int size = s.size(), res = 0;
		vector<vector<bool>> dp(size, vector<bool>(size));
		for (int i = size - 1; i >= 0; --i) 
		{
			for (int j = i; j < size; ++j)
			{
				dp[i][j] = (s[i] == s[j]) && (j - i <= 2 || dp[i + 1][j - 1]);
				if (dp[i][j]) ++res;
			}
		}
		return res;
	}
public:
	int countSubstrings(string s) {
		if (s.empty()) return 0;
		int size = s.size(), res = 0;
		vector<vector<bool>> dp(size, vector<bool>(size));
		for (int i = size - 1; i >= 0; --i) 
		{
			for (int j = i ; j < size; j++) {
				if (s[i] == s[j]) {
					if (j - i < 3) {//i和j相邻的时候
						dp[i][j] = true;
					}
					else {
						dp[i][j] = dp[i + 1][j - 1];
					}
				}
				else {
					dp[i][j] = false;
				}

				if (dp[i][j]) {
					res++;
				}
				
			}

		}
		return res;
	}

参考:

https://blog.csdn.net/JiuZhang_ninechapter/article/details/105733463?utm_medium=distribute.pc_feed.none-task-blog-alirecmd-1.nonecase&depth_1-utm_source=distribute.pc_feed.none-task-blog-alirecmd-1.nonecase&request_id=

https://leetcode-cn.com/problems/palindromic-substrings/solution/647-hui-wen-zi-chuan-dong-tai-gui-hua-fang-shi-qiu/

猜你喜欢

转载自blog.csdn.net/sinat_31608641/article/details/107377706