目录
- 1.最长递增子序列的个数
- 1.题目链接
- 2.算法原理详解
- 3.代码实现
- 2.最长数对链
- 1.题目链接
- 2.算法原理详解
- 3.代码实现
1.最长递增子序列的个数
1.题目链接
- 最长递增子序列的个数
2.算法原理详解
- 注意:本题思路和思维方式及用到的方法很值得考究,个人感觉很有含金量,且初见不好理解
- 前置知识:如何在数组中一次遍历就找出最大值出现的次数?
x == maxVal
:count++
x < maxVal
:无视x > maxVal
:更新最大值,重新计数int maxVal = nums[0], count = 1; for(int i = 1; i < nums.size(); i++) { if(nums[i] == maxVal) { count++; } else if(nums[i] > maxVal) { maxVal = nums[i]; count = 1; } }
- 思路:
-
确定状态表示 ->
dp[i]
的含义- 以
i
位置元素为结尾的所有子序列中,最长递增子序列的个数 - 本题状态标识还可以继续划分
len[i]
:以i
位置元素为结尾的所有子序列中,最长递增子序列的"长度"count[i]
:以i
位置元素为结尾的所有子序列中,最长递增子序列的"个数"
- 以
-
推导状态转移方程
- 令
j
为i
前面的任一一个数
- 令
-
初始化:
vector<int> len(n, 1), count(n, 1)
-
确定填表顺序:从左往右,两个表一起填
-
确定返回值:前置知识部分用到的小贪心策略,见代码
-
3.代码实现
int findNumberOfLIS(vector<int>& nums)
{
int n = nums.size();
vector<int> len(n, 1), count(n, 1);
int retLen = 1, retCount = 1;
for(int i = 1; i < n; i++)
{
for(int j = 0; j < i; j++)
{
if(nums[j] < nums[i])
{
if(len[j] + 1 == len[i])
{
count[i] += count[j];
}
else if(len[j] + 1 > len[i])
{
len[i] = len[j] + 1;
count[i] = count[j];
}
}
}
if(retLen == len[i])
{
retCount += count[i];
}
else if(retLen < len[i])
{
retLen = len[i];
retCount = count[i];
}
}
return retCount;
}
2.最长数对链
1.题目链接
- 最长数对链
2.算法原理详解
- 预处理:按照第一个元素排序
- 此时问题就转化成了最长递增子序列了
- 目的:保证当前位置不存在可以连在它后面的数对的后面的可能
- 思路:
-
确定状态表示 ->
dp[i]
的含义- 以
i
位置元素为结尾的所有子序列中,最长的数对链长度
- 以
-
推导状态转移方程
-
初始化:
vector<int> dp(n, 1)
-
确定填表顺序:从左往右
-
确定返回值:整个
dp
表里的最大值
-
3.代码实现
int findLongestChain(vector<vector<int>>& pairs)
{
sort(pairs.begin(), pairs.end()); // 预处理
int n = pairs.size();
vector<int> dp(n, 1);
int ret = 1;
for(int i = 1; i < n; i++)
{
for(int j = 0; j < i; j++)
{
if(pairs[j][1] < pairs[i][0])
{
dp[i] = max(dp[j] + 1, dp[i]);
}
}
ret = max(ret, dp[i]);
}
return ret;
}