非零段划分
题目描述:
输入格式:
输出格式:
样例1:
输入:
11
3 1 2 0 0 2 0 4 5 0 2
输出:
5
样例2:
输入:
14
5 1 20 10 10 10 10 15 10 20 1 5 10 15
输出:
4
样例3:
输入:
3
1 0 0
输出:
1
样例4:
输入:
3
0 0 0
输出:
0
分析:首先暴力肯定是会超时的O(n^2).在没有找出规律(或者毫无规律可言)的情况下,借助C++ STL 及优化算法对于降低时间复杂度来说是非常有效的。
思路:
- 首先进行离散化,将题中所给的数据离散化为连续的数据。
- 利用vector向量,保存每个数据离散化后的位置(和离散化前位置应该一样)
- 从0开始,第一次把0的位置全部变成0(即进行标记);第二次把1的位置全部变成0…依此类推。 细节处理:假设x的位置要变为0,若x-1和x+1的位置均被标记过了,则非零段-1;若都没标记过,则非零段+1;若有其中一个被标记过了,则非零段不变。
- 特殊情况: 若数组元素全为0,则ans = 0;
时间复杂度几乎为:O(n)
100分的代码:
#include <bits/stdc++.h>
#include <vector>
#include <set>
#include <algorithm>
#define fi first
#define se second
#define pb push_back
using namespace std;
const int N = 500010;
typedef pair<int,int> PII;
PII a[N];
int b[N];
bool book[N]; // 标记位置
vector<int> vc[N]; // 存放离散后的位置
int main()
{
int n;
scanf("%d",&n);
// 离散化
for(int i=1;i<=n;i++){
scanf("%d",&a[i].fi);
a[i].se = i;
}
sort(a+1,a+n+1);
int pos = 1;
for(int i=1;i<=n;i++){
if(a[i].fi!=a[i-1].fi && i!=1) pos++;
b[a[i].se] = pos;
}
// for(int i=1;i<=n;i++){
// printf("%d ",b[i]);
// }
// cout << "\n=================================" << endl;
for(int i=1;i<=n;i++){
vc[b[i]].pb(i);
}
// for(int i=1;i<=pos;i++){
// for(int j=0;j<vc[i].size();j++){
// cout << vc[i][j] << " ";
// }
// cout << endl;
// }
// cout << "=================================" << endl;
book[0] = 1,book[n+1] = 1;
int ans,res = 1;
// res 保存上次的结果, backup 保存此次更新的结果
for(int i=1;i<=pos;i++){
int backup = res;
for(int j=0;j<(int)vc[i].size();j++){
int x = vc[i][j];
book[x] = 1;
if(book[x-1] && book[x+1]) backup--;
else if(!book[x-1] && !book[x+1]) backup++;
}
// cout << "backup=" << backup << endl;
ans = max(ans,max(res,backup));
res = backup;
}
if(pos==1&&a[n].fi==0) ans = 0; // 特殊情况:若数组元素全为0,则ans = 0;
cout << ans << endl;
return 0;
}
注:也可以不使用sort,使用set或者优先队列进行优化.目的是排序
优化版本:时间复杂度和空间复杂度都是最优。
#include <bits/stdc++.h>
#include <vector>
#include <algorithm>
#define pb push_back
using namespace std;
const int N = 500010;
const int M = 10010;
//int a[N];
bool book[N];
vector<int> vc[M]; // 存放位置
int main()
{
int n;
scanf("%d",&n);
int p;
for(int i=1;i<=n;i++){
scanf("%d",&p);
vc[p].pb(i);
}
book[0] = 1,book[n+1] = 1;
int ans,res = 1;
// res 保存上次的结果, backup 保存此次更新的结果
for(int i=0;i<=10000;i++){
if(!vc[i].size()) continue;
int backup = res;
for(int j=0;j<(int)vc[i].size();j++){
int x = vc[i][j];
book[x] = 1;
if(book[x-1] && book[x+1]) backup--;
else if(!book[x-1] && !book[x+1]) backup++;
}
// cout << "backup=" << backup << endl;
ans = max(ans,max(res,backup));
res = backup;
}
if(vc[0].size()==n) ans = 0;
cout << ans << endl;
return 0;
}