问题描述
小U拿到了一组排列,她想知道有多少个子区间满足区间内部的数构成一个排列。一个区间的排列是指:该区间的数包含从 1到 k 的每个数,并且每个数恰好出现一次,这个区间的长度为 kk。
例如,对于数组 [2, 1, 5, 3, 4],其中区间 [2, 2],[1,2] 和 [1, 5] 都是排列。
测试样例
样例1:
输入:
n = 5 ,a = [2, 1, 5, 3, 4]
输出:3
样例2:
输入:
n = 5 ,a = [1, 2, 3, 4, 5]
输出:5
样例3:
输入:
n = 4 ,a = [4, 3, 2, 1]
输出:4
解题思路
好的,让我们来逐步解决这个问题。首先,我们需要理解题目要求:找到所有满足条件的子区间,这些子区间内的数构成一个排列。
解题思路
- 理解排列的定义:一个区间内的数构成排列,意味着这个区间内的数包含从1到k的每个数,并且每个数恰好出现一次。
- 滑动窗口:我们可以使用滑动窗口(双指针)的方法来遍历所有可能的子区间,并检查每个区间是否满足排列的条件。
- 哈希表:为了快速检查区间内的数是否构成排列,我们可以使用哈希表来记录每个数出现的次数。
代码提示
以下是一些代码提示,帮助你实现这个算法:
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
int solution(int n, vector<int>& a) {
int count = 0;
unordered_map<int, int> freq; // 用于记录每个数出现的次数
// 滑动窗口的左右指针
int left = 0, right = 0;
while (right < n) {
// 将右指针指向的数加入窗口
freq[a[right]]++;
// 检查当前窗口是否构成排列
while (/* 检查条件 */) {
// 如果构成排列,增加计数
count++;
// 移动左指针,缩小窗口
freq[a[left]]--;
if (freq[a[left]] == 0) {
freq.erase(a[left]);
}
left++;
}
// 移动右指针,扩大窗口
right++;
}
return count;
}
int main() {
vector<int> v1 = {2, 1, 5, 3, 4};
vector<int> v2 = {1, 2, 3, 4, 5};
vector<int> v3 = {4, 3, 2, 1};
cout << (solution(5, v1) == 3) << endl;
cout << (solution(5, v2) == 5) << endl;
cout << (solution(4, v3) == 4) << endl;
return 0;
}
解题思路
- 一个区间内的数构成排列,意味着这个区间内的数包含从1到k的每个数,并且每个数恰好出现一次。
- 可以使用滑动窗口(双指针)的方法来遍历所有可能的子区间,并检查每个区间是否满足排列的条件。
- 为了快速检查区间内的数是否构成排列,我们可以使用哈希表来记录每个数出现的次数。
代码
int solution(int n, vector<int>& a) {
int count = 0;
for (int k = 1; k <= n; ++k) {
for (int i = 0; i <= n - k; ++i) {
unordered_set<int> seen;
bool isArrangement = true;
for (int j = i; j < i + k; ++j) {
if (a[j] <= k && seen.find(a[j]) == seen.end()) {
seen.insert(a[j]);
} else {
isArrangement = false;
break;
}
}
if (isArrangement) {
count++;
}
}
}
return count;
}