题目链接:https://leetcode.cn/problems/number-of-longest-increasing-subsequence/description/
讲这个题之前,首先看一个算法
//假设你要求一个数组中最大值,及其出现的次数(要求:只遍历一次)
//本质:贪心算法
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> s = { 1,2,2,3,4,4,5,5,9,1,9,2,9 };
int maxval = s[0];//记录最大值
int count = 1;//记录最大值出现的次数
int size = s.size();
for( int i = 1 ; i < size ;i++)
{
if( maxval == s[i] )count++;
else if( maxval < s[i] )//当出现比当前最大值更大的值时,更新最大值和次数
{
maxval = s[i];
count = 1;
}
}
}
思路:
这道题可以用动态规划来解决,状态表示:count[i] 可以表示成以i位置为结尾的最长子序列的个数
长度等于1时 count[i] = 1
长度大于1时 count[i] = sum(count[j]) j表示在0 ~ i - 1中的满足条件的最长子序列,用sum的原因是因为可能有多个
举个列子:
len 1 2 3 3 4
count 1 1 1 1 2
难点就在于:如何找到0 ~ i - 1中满足条件的最长子序列,方法:设置一个dp(命名为len)表记录以i位置为结尾的单增最长子序列的长度
状态转移方程:
对于len来说: len[i] 的最小值为1,以自己为子序列的长度
j属于 0 ~ i - 1 if ( nums[i] > nums[j] ) len[i] = max(len[j] + 1 , len[i] );
对于count来说: 通过遍历0 ~ i - 1 可以求出最长子序列的长度,边遍历可以边更新count
(贪心算法,上面的算法)
初始值:对于len的最小值为1 , 对于count的最小值也是1(解释:最差情况以自己为最长子序列的,此时count为1,其余情况均大于等于1)
返回值:len中最大长度所对应的次数总和
class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
int size = nums.size();
vector<int> len(size,1);
vector<int> count(size,1);
for (int i = 1; i < size; i++)
{
for (int j = i - 1; j >= 0; j--)
{
if (nums[i] > nums[j])
{
if( len[i] < len[j] + 1 )
{
count[i] = count[j];
len[i] = len[j] +1;
}
else if( len[i] == len[j] +1 )
count[i] += count[j];
}
}
}
int maxval = len[0];
int count1 = count[0];
for (int i = 1; i < size; i++)
{
if (len[i] > maxval)
{
maxval = len[i];
count1 = count[i];
}
else if (len[i] == maxval)
{
count1 += count[i];
}
}
return count1;
}
};