1.最长公共子序列(动态规划)剑指offer95
输入:text1 = “abcde”, text2 = “ace”
输出:3
解释:最长公共子序列是 “ace” ,它的长度为 3 。
Q1:为什么想到二维dp?
A1:因为涉及到两个字符串的比较,通常我们的做法都是设置两个指针进行遍历操作;而两个指针当前走到哪以及当前已经记录的公共子序列长度,我们可以采取一个二维dp记录
假设字符串text1和text2的长度分别为m,n,创建m+1行n+1列的二维数组dp,其中dp[i][j]表示text1[0:i]和text2[0:j]的最长公共子序列长度
//初始化dp数组
i=0;text1[0:i]为空,0<=j<=n,dp[0][j]=0;
j=0;text2[0:j]为空,0<=i<=m,dp[i][0]=0;
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int m=text1.size();int n=text2.size();
假设字符串text1和text2的长度分别为m,n,创建m+1行n+1列的二维数组dp,
///其中dp[i][j]表示text1[0:i]和text2[0:j]的最长公共子序列长度
//初始化dp数组
//i=0;text1[0:i]为空,0<=j<=n,dp[0][j]=0;
//j=0;text2[0:j]为空,0<=i<=m,dp[i][0]=0;
vector<vector<int>>dp(m+1,vector<int>(n+1));
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(text1[i-1]==text2[j-1])
{dp[i][j]=dp[i-1][j-1]+1;}
else
{dp[i][j]=max(dp[i-1][j],dp[i][j-1]);}
}
}
return dp[m][n];
}
};
2.最长递增子序列(动态规划)leetcode300
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
定义dp[i]为考虑前i个元素,以第i个数字结尾的最长上升子序列的长度,注意nums[i]必须被选取
假设已经得到dp[0…i-1]的值 状态转移方程为:
dp[i]=max(dp[j])+1 (0<=j<i && nums[j]<nums[i])
最后,整个数组的最长上升子序列即所有 dp[i]中的最大值
class Solution {
public:
int lengthOfLIS(vector<int>& nums)
{
if(nums.size()<2)return nums.size();
vector<int>dp(nums.size(),1); //dp[i]代表截至到nums[i]最长的递增序列长度
for(int i=1;i<nums.size();i++)
{
for(int j=0;j<i;j++)
{
if(nums[i]>nums[j])
dp[i]=max(dp[j]+1,dp[i]);
}
//cout<<dp[i]<<endl;
}
return *max_element(dp.begin(),dp.end());
}
};
3.最长连续序列(动规,unordered_set)剑指offer119
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9
方法一:unordered_set
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_set<int>s1;
for (int num : nums)
{
s1.insert(num);
}
int res=0;
for (int num : s1)
{
int cur=num;
int length=1;//初始化的位置
if(!s1.count(num-1))
{
while(s1.count(cur+1))
{
cur++;
length++;
}
}
res=max(res,length);
}
return res;
}
};
方法二:动态规划
class Solution
{
public:
int longestConsecutive(vector<int>&nums)
{
unordered_map<int,int>m1;//key-num value-对应连续长度
int res=0;
for(int num:nums)
{
if(!m1[num])
{
int left=m1[num-1];
int right=m1[num+1];
int length=left+right+1;
//cout<<length<<endl;
res=max(res,length);
//更新左右两个端点的值
m1[num]=length;
m1[num-left]=length; //num-left意味着从num移动到连续序列的左端点
m1[num+right]=length; //num+right意味着从num移动到连续序列的右端点
}
}