【滑动窗口】C++算法:K 个不同整数的子数组

作者推荐

动态规划 多源路径 字典树 LeetCode2977:转换字符串的最小成本

本题涉及知识点

滑动窗口

LeetCoe992 K 个不同整数的子数组

给定一个正整数数组 nums和一个整数 k,返回 nums 中 「好子数组」 的数目。

如果 nums 的某个子数组中不同整数的个数恰好为 k,则称 nums 的这个连续、不一定不同的子数组为 「好子数组 」。

例如,[1,2,3,1,2] 中有 3 个不同的整数:1,2,以及 3。

子数组 是数组的 连续 部分。

示例 1:

输入:nums = [1,2,1,2,3], k = 2

输出:7

解释:恰好由 2 个不同整数组成的子数组:[1,2], [2,1], [1,2], [2,3], [1,2,1], [2,1,2], [1,2,1,2].

示例 2:

输入:nums = [1,2,1,3,4], k = 3

输出:3

解释:恰好由 3 个不同整数组成的子数组:[1,2,1,3], [2,1,3], [1,3,4].

提示:

1 <= nums.length <= 2 * 10^4^

1 <= nums[i], k <= nums.length

滑动窗口

复杂度 : O(n)。

枚举子数组的左边界left,时间复杂度O(n);枚举r1,r2时间复杂度O(n)。由于r1和r2没有复位,所以总时间复杂度是O(n)。

r1 nums[left,r1)有k个不同的整数,如果有多个符合的r1,取最小值。如果没有符合的r1,则r1为m_c
r2 nums[left,r2)有k+1个不同的整数,如果有多个符合的r2,取最小值。如果没有符合的r2,则r2为m_c

如果没有符合的r1,则忽略或直接退出。

如果r2合法 则nums[left,r)刚好有k个数,r取值范围[r1,r2),数量为r2-r1
如果r2非法则 nums[left,r)刚好有k个数,r取值范围[r1,m_c],数量r2+1-r1

代码

核心代码

cpp 复制代码
template<class KEY>
class CKeyCount
{
public:
	void Add(const KEY& key, int iCount)
	{
		Cnt[key] += iCount;
		if (0 == Cnt[key])
		{
			Cnt.erase(key);
		}
	}
	std::unordered_map<KEY, int> Cnt;
};

class Solution {
public:
	int subarraysWithKDistinct(vector<int>& nums, int k) {
		m_c = nums.size();
		CKeyCount<int> cnt1,cnt2;
		int r1 = 0, r2 = 0;
		int iRet = 0;
		for (int left = 0; left < nums.size(); left++)
		{
			while ((r1 < m_c)&&( cnt1.Cnt.size() < k ) )
			{
				cnt1.Add(nums[r1++],1);
			}
			while ((r2 < m_c) && (cnt2.Cnt.size() < k+1))
			{
				cnt2.Add(nums[r2++], 1);
			}
			if (cnt1.Cnt.size() < k )
			{
				break;			
			}
            iRet += r2 - r1 + (cnt2.Cnt.size()==k);	
			cnt1.Add(nums[left], -1);
			cnt2.Add(nums[left], -1);
		}
		return iRet;
	}
	int m_c;
};

2023年5月版

class Solution {

public:

int subarraysWithKDistinct(vector& nums, int k) {

m_c = nums.size();

if (1 == k)

{

return DoK1(nums);

}

std::unordered_map<int, int> mValueNum;

std::unordered_map<int, std::queue> mIndexs;

int left = 0, right = 0;

//[i,vR1[i])表示以索引i开头符合条件的最短子串,[i,vR2[i]]表示以索引i开头符合条件的最长子串

//-1表示没有符合条件的子串

vector vR1(m_c,-1), vR2(m_c,-2);

while ((right < m_c) && (mValueNum.size() < k ))

{

mValueNum[nums[right]]++;

mIndexs[nums[right]].emplace(right);

right++;

}

if (mValueNum.size() != k)

{

return 0;

}

vR1[0] = right;

for (int left = 0; left < m_c; left++)

{

//[left,right) 全部符合条件

while ((right < m_c) && (mValueNum.count(nums[right])))

{

const int iRightValue = nums[right];

mValueNum[iRightValue]++;

mIndexs[iRightValue].emplace(right);

right++;

}

vR2[left] = right;

//删除索引为left的元素

const int iValueLeft = nums[left];

mIndexs[iValueLeft].pop();

if (1 == mValueNum[iValueLeft])

{

mValueNum.erase(iValueLeft);

while ((right < m_c) && (mValueNum.size() < k))

{

const int iRightValue = nums[right];

mValueNum[iRightValue]++;

mIndexs[iRightValue].emplace(right);

right++;

}

if (mValueNum.size() == k)

{

vR1[left + 1] = right;

}

else

{

break;

}

}

else

{

vR1[left + 1] = max(vR1[left], mIndexs[iValueLeft].front()+1);

mValueNum[iValueLeft]--;

}

}

int iRet = 0;

for (int i = 0; i < m_c; i++)

{

iRet += vR2[i] - vR1[i]+1;

}

return iRet;

}

int DoK1(const vector& nums)

{

int iRet = 0;

int iNum = 1;

int iPre = nums[0];

for (int i = 1; i < m_c; i++)

{

if (nums[i] == iPre)

{

iNum++;

}

else

{

iRet += iNum*(iNum + 1) / 2;

iNum = 1;

iPre = nums[i];

}

}

iRet += iNum*(iNum + 1) / 2;

return iRet;

}

int m_c;

};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法C++ 实现。

相关推荐
Ocean☾6 分钟前
前端基础-html-注册界面
前端·算法·html
顶呱呱程序14 分钟前
2-143 基于matlab-GUI的脉冲响应不变法实现音频滤波功能
算法·matlab·音视频·matlab-gui·音频滤波·脉冲响应不变法
爱吃生蚝的于勒36 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
羊小猪~~39 分钟前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
王哈哈^_^1 小时前
【数据集】【YOLO】【VOC】目标检测数据集,查找数据集,yolo目标检测算法详细实战训练步骤!
人工智能·深度学习·算法·yolo·目标检测·计算机视觉·pyqt
星沁城1 小时前
240. 搜索二维矩阵 II
java·线性代数·算法·leetcode·矩阵
脉牛杂德1 小时前
多项式加法——C语言
数据结构·c++·算法
legend_jz1 小时前
STL--哈希
c++·算法·哈希算法
CSUC1 小时前
【C++】父类参数有默认值时子类构造函数列表中可以省略该参数
c++
Vanranrr2 小时前
C++ QT
java·c++·qt