LeetCode刷题的DP算法
LeetCode刷题之动态规划算法
1.基本思路及代码框架
首先,动态规划的穷尽有点特殊,因为如果这种问题在存在「重叠子问题」,被猛烈地穷尽,效率会极低,所以需要“备忘录”或“DP表”来优化穷尽过程,避免不必要的计算。
此外,动态规划问题必须是具备「最优子结构」,问题,以便通过子问题的最大值获得原问题的最大值。
此外,虽然动态规划的核心思想是穷尽最佳价值,但问题可能是千变万化的,要穷尽所有可行的解决方案并不容易。只有列出正确的「状态转移方程」,我们才能正确地穷尽它们。
上述重叠子问题、最优子结构和状态转移方程是动态规划的三个要素。你什么意思?我稍后会给你一个例子,但是在实际的算法问题中,写出状态转移方程是最困难的,这就是为什么很多朋友觉得动态规划问题很难。让我提供一个我开发的思维框架来帮助你思考状态转移方程:
明确 base case - 明确「状态」- 明确「选择」 - 定义 dp 数组/函数的含义.
按照上面的例程,最终的结果可以设置这个框架:
#初始化基本案例
dp[0][0][.]=基础
#进行状态转换。
对于状态1的所有值中的1:
状态2中状态2的所有值:
为.
Dp[国家1][国家2][.]=找到最大值(选项1,选项2.)
2.题目解答
1.LeetCode之509斐波拉且数列
解决方案思维
首先,递归函数是通过递归直接编写的。
第二,记录每一种情况,避免重复计算。
代码实现
1.递归方程
/*
* @ LC app=leet code . cn id=509 lang=CPP
*
* [509]斐波那契数
*/
//@lc代码=开始
解决方案类{
公众号:
int fib(int n){ 0
if (n==0)返回0;
if(n==1 | | n==2){ 0
返回1;
}
返回光纤(n -1)光纤(n-2);
}
};
//@lc代码=结束
2.子状态记录
解决方案类{
公众号:
int fib(int n){ 0
if(n==0){ 0
返回0;
}
int * DP=new int[n ^ 1];
DP[0]=0;DP[1]=1;
for(int I=2;I=n;I){ 0
DP[I]=DP[I-1]DP[I-2];
}
返回DP[n];
}
};
2.LeetCode之322零钱兑换
解决方案思维
动态编程用于解决问题,避免递归。找出基本状态、选择和目标。写出状态方程:
代码实现
解决方案类{
公众号:
int coinChange(矢量硬币,int金额){ 0
矢量dp(数量1,数量1);
DP[0]=0;
for(int I=0;I DP . size();I){ 0
for(自动硬币:硬币){ 0
if(I-coin 0){ 0
继续;
}
dp[i]=min(dp[i],1 DP[I-coin]);
}
}
退货(DP[金额]==金额1)-1 : DP[金额];
}
};
3.LeetCode之
300最长递增子序列
解题思路
状态转移方程:我们以dp[i]表示以num[i]结尾得最长递增子序列的长度。
根据这个定义,我们的最终结果(子序列的最大长度)应该是 dp 数组中的最大值。
int res = 0; for (int i = 0; i dp.length; i++) { res = Math.max(res, dp[i]); } return res;
nums[5] = 3
,既然是递增子序列,我们只要找到前面那些结尾比 3 小的子序列,然后把 3 接到最后,就可以形成一个新的递增子序列,而且这个新的子序列长度加一。显然,可能形成很多种新的子序列,但是我们只选择最长的那一个,把最长子序列的长度作为
dp[5]
的值即可。for (int i = 0; i nums.length; i++) { for (int j = 0; j i; j++) { if (nums[i] nums[j]) dp[i] = Math.max(dp[i], dp[j] + 1); } }
-
代码实现
/* * @lc app=leetcode.cn id=300 lang=cpp * * [300] 最长递增子序列 */ // @lc code=start class Solution { public: int lengthOfLIS(vectorint nums) { vectorint dp(nums.size(), 1); for (int i = 0; i nums.size(); i++) { for (int j = 0; j i; j++) { if (nums[i] nums[j]) { dp[i] = max(dp[i], dp[j] + 1); } } } int res = 0; for(int i = 0; i nums.size(); i++) { res = max(res, dp[i]); } return res; } }; // @lc code=end
4.LeetCode之1143最长公共子序列
-
解题思路
明确基础状态,写出状态,做出选择。
写出状态方程。
-
代码实现
/* * @lc app=leetcode.cn id=1143 lang=cpp * * [1143] 最长公共子序列 */ // @lc code=start class Solution { public: int longestCommonSubsequence(string text1, string text2) { int m = text1.size(), n = text2.size(); vectorvectorint dp(m + 1,vectorint(n + 1, 0)); for (int i = 1; i = m; i++) { for (int j = 1; j = n; j++) { if (text1[i - 1] == text2[j - 1]) { dp[i][j] = 1 + dp[i - 1][j - 1]; } else { dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); } } } return dp[m][n]; } }; // @lc code=end
5.LeetCode之583两个字符串的删除操作
-
解题思路
与上一题解法思路一致,只不过最终结果需要转化一下。
-
代码实现
/* * @lc app=leetcode.cn id=583 lang=cpp * * [583] 两个字符串的删除操作 */ // @lc code=start class Solution { public: int minDistance(string word1, string word2) { int m =word1.size(), n =word2.size(); vectorvectorint dp(m + 1,vectorint(n + 1, 0)); for (int i = 1; i = m; i++) { for (int j = 1; j = n; j++) { if (word1[i - 1] ==word2[j - 1]) { dp[i][j] = 1 + dp[i - 1][j - 1]; } else { dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); } } } return m + n - 2 * dp[m][n]; } }; // @lc code=end
6.LeetCode之712两个字符串的最小ASCII删除和
-
解题思路
先给出基本状态,明确数组的含义,初始化数组,给出状态,做选择。
-
代码实现
/* * @lc app=leetcode.cn id=712 lang=cpp * * [712] 两个字符串的最小ASCII删除和 */ // @lc code=start class Solution { public: int minimumDeleteSum(string s1, string s2) { int m = s1.size(), n = s2.size(); vectorvectorint dp(m + 1,vectorint(n + 1, 0)); for (int i = m - 1; i = 0; i--) { dp[i][n] = dp[i + 1][n] + s1[i]; } for (int j = n - 1; j = 0; j--) { dp[m][j] = dp[m][j + 1] + s2[j]; } for (int i = m - 1; i = 0; i--) { for (int j = n -1; j = 0; j--) { if (s1[i] == s2[j]) { dp[i][j] = dp[i + 1][j + 1]; } else { dp[i][j] = min(dp[i + 1][j] + s1[i], dp[i][j + 1] + s2[j]); } } } return dp[0][0]; } }; // @lc code=end
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/124343.html