最长连续子序列
思路
1.空间换时间,利用哈希表存储原始数据。
2.遍历原始数组,例如遍历到nums[i],在哈希表中先往num[i]右边找,即num[i] + 1方向;再往左边找,即nums[i] - 1方向。
3.优化,每次往左右找时,即可把左右的数在哈希表中删除,防止重复查找 O(n)+O(n)
int longestConsecutive(vector<int>& nums) {
if (nums.size() < 2)
return nums.size();
unordered_set<int>hashSet;
for (int i = 0; i < nums.size(); i++)
hashSet.insert(nums[i]);
int maxConSeqLen = 0;
for (int i = 0; i < nums.size(); i++) {
//哈希表中存在该key则删除 且返回1;否则直接返回0 可以省去find操作
if (hashSet.erase(nums[i])) {
int num = nums[i];
int curLen = 1;
//往右找
while (hashSet.erase(++num))
curLen++;
//往左找
num = nums[i]; //该步骤是因为num发生了改变 必须变回nums[i]
while (hashSet.erase(--num))
curLen++;
maxConSeqLen = (maxConSeqLen > curLen ? maxConSeqLen : curLen);
}
}
return maxConSeqLen;
}
最长递增子序列个数(包含最长递增子序列长度)
思路:
1.用len数组记录以每个元素为结尾的最长递增子序列长度,例如{1,3,5,4,1}对应的len数组为{1,2,2,3,1},这样最长递增子序列得解。
2.在1的基础上加上一个combination数组,记录达到当前最长递增子序列所有的子序列个数
int findNumberOfLIS(vector<int>& nums) {
if (nums.size() < 2)
return nums.size();
vector<int>len(nums.size(), 1); //记录每个位置结尾的递增子序列长度
vector<int>combination(nums.size(), 1); //记录每个位置达到该位置最长递增子序列所有的组合数
int maxLen = 0; //记录最大递增子序列长度
for (int i = 1; i < nums.size(); i++) {
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
if (len[j] == len[i]) //关键步骤
combination[i] = combination[j];
if (len[j] + 1 == len[i]) //关键步骤 又是一种达到最长子序列的可能
combination[i] += combination[j];
len[i] = max(len[i], len[j] + 1);
}
}
maxLen = (maxLen > len[i] ? maxLen : len[i]);
}
int res = 0;
for (int i = 0; i < nums.size(); i++) {
if (maxLen == len[i])
res += combination[i];
}
return res;
}