子数组:指在一个数组中,选择一些连续的元素组成的新数组。
例题一:6900. 统计完全子数组的数目
给你一个由 正 整数组成的数组 nums
。
如果数组中的某个子数组满足下述条件,则称之为 完全子数组 :
- 子数组中 不同 元素的数目等于整个数组不同元素的数目。
返回数组中 完全子数组 的数目。
子数组 是数组中的一个连续非空序列。
示例 1:
输入:nums = [1,3,1,2,2] 输出:4 解释:完全子数组有:[1,3,1,2]、[1,3,1,2,2]、[3,1,2] 和 [3,1,2,2] 。示例 2:
输入:nums = [5,5,5,5] 输出:10 解释:数组仅由整数 5 组成,所以任意子数组都满足完全子数组的条件。子数组的总数为 10 。提示:
1 <= nums.length <= 1000
1 <= nums[i] <= 2000
思路:1.用set以及unerdered_set容器暴力枚举
2.滑动窗口
AC代码:
//暴力
class Solution {
public:
int countCompleteSubarrays(vector<int>& nums)
{
int sum=0;
set<int> s;
for(auto& x:nums)
s.insert(x);
int l=nums.size();
for(int i=0;i<l;i++)
{
unordered_set<int> ss;
for(int j=i;j<l;j++)
{
ss.insert(nums[j]);
if(s.size()==ss.size())
sum++;
}
}
return sum;
}
};
//滑动窗口
class Solution {
public:
int countCompleteSubarrays(vector<int> &nums) {
int m = unordered_set<int>(nums.begin(), nums.end()).size();
unordered_map<int, int> cnt;
int ans = 0, left = 0;
for (int v: nums) { // 枚举子数组右端点 v=nums[i]
cnt[v]++;
while (cnt.size() == m) {
int x = nums[left++];
if (--cnt[x] == 0)
cnt.erase(x);
}
ans += left; // 子数组左端点 < left 的都是合法的
}
return ans;
}
};
例题二:5057. 截断数组
给定一个长度为 n 的正整数数组a1,a2,…,an 和一个正整数 p。
现在,要将该数组从中间截断,得到两个非空子数组。
我们规定,一个数组的价值等于数组内所有元素之和模 p 的结果。
我们希望,将给定数组截断后,得到的两个非空子数组的价值之和尽可能大。
请你输出这两个非空子数组的价值之和的最大可能值。
输入格式
第一行包含两个整数 n 和 p。
第二行包含 n个整数 a1,a2,…,an。
输出格式
一个整数,表示价值之和的最大可能值。
数据范围
前 33 个测试点满足 2≤n≤10。
所有测试点满足 2≤n≤1e5,2≤p≤10000,1≤ai≤1e6。
输入样例1:
4 10
3 4 7 2
输出样例1:
16
输入样例2:
10 12
16 3 24 13 9 8 7 5 12 12
输出样例2:
13
思路:前缀和+枚举
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5+10;
int a[N],n,p,sum[N],ans;
int sumn;
void solve()
{
cin>>n>>p;
for(int i=0;i<n;i++){
cin>>a[i];
sumn += a[i];
}
sum[0] = a[0];
for(int i=1;i<n;i++){
sum[i] = sum[i-1]+a[i];
}
if(n == 2){
int cnt = a[0] % p + a[1] % p;
cout<<cnt<<endl;
return ;
}
for(int i=1;i<n-1;i++){
int tmp = sum[i-1]%p+(sumn-sum[i-1])%p;
ans = max(ans,tmp);
}
cout<<ans<<endl;
return ;
}
signed main()
{
int t=1;
while(t--)
solve();
return 0;
}
今日推荐音乐:落单恋人