动态规划【完结】5.9任务
Leetcode.53最大子数组和
Leetcode.120三角形最小路径和
Leetcode.63不同路径 II
Leetcode.91解码方法
Leetcode.198打家劫舍
Leetcode.300最长递增子序列
Leetcode.72编辑距离
Leetcode.518零钱兑换 II
Leetcode.664奇怪的打印机
Leetcode.10正则表达式匹配
link
一、Leetcode.53最大子数组和
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
int maxSubArray(vector<int>& nums) {
int ans=INT_MIN;
int last=0;
for(int i=0;i<nums.size();i++){
int now=max(0,last)+nums[i];
ans=max(ans,now);
last=now;
}
return ans;
}
二、Leetcode.120三角形最小路径和
给定一个三角形 triangle ,找出自顶向下的最小路径和。
每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。
int minimumTotal(vector<vector<int>>& triangle) {
vector<vector<long long>>dp(triangle.size(),vector<long long>(triangle.size()));
dp[0][0]=triangle[0][0];
for(int i=1;i<triangle.size();i++){
for(int j=0;j<=i;j++){
if(j>0&&i!=j){
dp[i][j]=min(dp[i-1][j],dp[i-1][j-1])+triangle[i][j];
cout<<dp[i][j]<<"="<<min(dp[i-1][j],dp[i-1][j-1])<<"+"<<triangle[i][j]<<" ";
}
else if(j==0){
dp[i][j]=dp[i-1][j]+triangle[i][j];
cout<<dp[i][j]<<' ';
}else {
dp[i][j]=dp[i-1][j-1]+triangle[i][j];
}
}
cout<<endl;
}
long long ans=INT_MAX;
for(int i=0;i<triangle.size();i++)ans=min(ans,dp[triangle.size()-1][i]);
return ans;
}
三、Leetcode.63不同路径 II
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
if(obstacleGrid[0][0]==1)return 0;
int m=obstacleGrid.size(),n=obstacleGrid[0].size();
vector<vector<long long>>dp(m,vector<long long>(n));
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(obstacleGrid[i][j]==1)continue;
if(i==0&&j!=0)dp[i][j]=dp[i][j-1];
else if(i!=0&&j==0)dp[i][j]=dp[i-1][j];
else if(i==0&&j==0)dp[i][j]=1;
else{
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
}
return dp[m-1][n-1];
}
四、Leetcode.91解码方法
要 解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,“11106” 可以映射为:
“AAJF” ,将消息分组为 (1 1 10 6)
“KJF” ,将消息分组为 (11 10 6)
注意,消息不能分组为 (1 11 06) ,因为 “06” 不能映射为 “F” ,这是由于 “6” 和 “06” 在映射中并不等价。
给你一个只含数字的 非空 字符串 s ,请计算并返回 解码 方法的 总数 。
题目数据保证答案肯定是一个 32 位 的整数。
int numDecodings(string s) {
vector<int>dp(s.size());
if(s[0]!='0')dp[0]=1;
else return 0;
if(s.size()>=2){
if(s[1]-'0'>0)dp[1]++;
if((s[0]-'0')*10+s[1]-'0'<=26&&(s[0]-'0')*10+s[1]-'0'>=10)
dp[1]++;
}
for(int i=2;i<s.size();i++){
if(s[i]!='0')dp[i]+=dp[i-1];
if((s[i-1]-'0')*10+s[i]-'0'<=26&&(s[i-1]-'0')*10+s[i]-'0'>=10)dp[i]+=dp[i-2];
}
return dp[s.size()-1];
}
五、Leetcode.198打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
int rob(vector<int>& nums) {
int n=nums.size();
vector<vector<int>>dp(n,vector<int>(2));
dp[0][0]=0;
dp[0][1]=nums[0];
for(int i=1;i<n;i++){
dp[i][0]=max(dp[i-1][1],dp[i-1][0]);//0不偷
dp[i][1]=dp[i-1][0]+nums[i];
}
return max(dp[n-1][0],dp[n-1][1]);
}
六、Leetcode.300最长递增子序列
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
int lengthOfLIS(vector<int>& nums) {
int n=nums.size();
vector<int>dp(n);
int ans=1;
for(int i=0;i<n;i++){
dp[i]=1;
for(int j=0;j<i;j++){
if(nums[i]>nums[j])
dp[i]=max(dp[i],dp[j]+1);
}
ans=max(dp[i],ans);
}
return ans;
}
七、Leetcode.72编辑距离
给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。
int minDistance(string word1, string word2) {
word1=" "+word1;
word2=" "+word2;
int n1=word1.size();
int n2=word2.size();
vector<vector<int>>dp(n1,vector<int>(n2));
for(int i=0;i<n1;i++)dp[i][0]=i;
for(int i=0;i<n2;i++)dp[0][i]=i;
for(int i=1;i<n1;i++){
for(int j=1;j<n2;j++){
dp[i][j]=min(dp[i][j-1],dp[i-1][j])+1;
dp[i][j]=min(dp[i][j],dp[i-1][j-1]+(word1[i]!=word2[j]));
}
}
return dp[n1-1][n2-1];
}
八、Leetcode.518零钱兑换 II
给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。
假设每一种面额的硬币有无限个。
题目数据保证结果符合 32 位带符号整数。
int change(int amount, vector<int>& coins) {
vector<int>dp(amount+1);
dp[0]=1;
for(auto coin:coins)
for(int i=coin;i<=amount;i++){
dp[i]+=dp[i-coin];
}
return dp[amount];
}
九、Leetcode.664奇怪的打印机
有台奇怪的打印机有以下两个特殊要求:
打印机每次只能打印由 同一个字符 组成的序列。
每次可以在从起始到结束的任意位置打印新字符,并且会覆盖掉原来已有的字符。
给你一个字符串 s ,你的任务是计算这个打印机打印它需要的最少打印次数。
int strangePrinter(string s) {
if(s.empty())return 0;
int n=s.size();
vector<vector<int>>f(n+1,vector<int>(n+1));
for(int len=1;len<=n;len++){
for(int l=0;l+len-1<n;l++){
int r=l+len-1;
f[l][r]=f[l+1][r]+1;
for(int k=l+1;k<=r;k++){
if(s[k]==s[l])
f[l][r]=min(f[l][r],f[l][k-1]+f[k+1][r]);
}
}
}
return f[0][n-1];
}
十、Leetcode.10正则表达式匹配
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
bool isMatch(string s, string p) {
int n = s.length(), m = p.length();
vector<vector<bool>> f(n + 1, vector<bool>(m + 1, false));
s = " " + s;
p = " " + p;
f[0][0] = true;
for (int i = 0; i <= n; i++)
for (int j = 1; j <= m; j++) {
if (i > 0 && (s[i] == p[j] || p[j] == '.'))
f[i][j] = f[i][j] | f[i - 1][j - 1];
if (p[j] == '*') {
if (j >= 2)
f[i][j] = f[i][j] | f[i][j - 2];
if (i > 0 && (s[i] == p[j - 1] || p[j - 1] == '.'))
f[i][j] = f[i][j] | f[i - 1][j];
}
}
return f[n][m];
}