J - Non-boring sequences
题目要判断一个序列是否满足这样的要求:它的所有连续子序列中至少包含一个不重复的数字。满足这样要求的序列称为non-boring的序列,反之称为boring的序列。
求解主要采用了map来辅助得到每个元素左右最近的相等元素的位置。方法即顺序、逆序遍历所给的序列,遍历过程中用map记录上一次遇到某个值时的位置。详细地说,即每进一步判断一次当前值
n
是否存在,若存在,将map中保存的“上次遇到该值的位置
接着,使用一个递归函数,判断子区间是否都满足条件。
某个区间 a[0] .. a[n] 是否non-boring可以这样判断:先看整体,若存在元素 a[i] 在序列中只出现一次,可知当前这个大的区间是non-boring的,需要进一步判断其子区间;对其子区间,我们只需取 a[0] .. a[i - 1] 以及 a[i + 1] .. a[n] 进行判断,以此类推,若全部满足non-boring,则说明区间 a[0] .. a[n] 是non-boring的。
这个特征和对它的利用详见 range_check() 函数,可以一目了然。
程序中,使用map做完了准备工作,调用 range_check(0,n) ,返回真输出non-boring,返回假输出boring即可。
#include <iostream>
#include <cstdio>
#include <map>
#include <vector>
using namespace std;
vector<int> myVec, leftNear(200008), rghtNear(200008);
map<int, int> dupliChek;
bool range_check(int left, int rght){
if(left >= rght)
return true;
for(int i = 0; i <= (rght - left) / 2; i++){ //从两边向中间找,提高效率
if(leftNear[left + i] < left && rghtNear[left + i] > rght)
return range_check(left, left + i - 1) && range_check(left + i + 1, rght);
if(leftNear[rght - i] < left && rghtNear[rght - i] > rght)
return range_check(left, rght - i - 1) && range_check(rght - i + 1, rght);
}
return false;
}
int main(){
int T;
cin >> T;
for(int t = 0; t < T; t++){
myVec.clear();
int n, temp;
cin >> n;
for(int i = 0; i < n; i++){
scanf("%d", &temp);
myVec.push_back(temp);
}
dupliChek.clear();
for(int i = 0; i < n; i++){ //-----+
if(dupliChek.count(myVec[i])){ // |
leftNear[i] = dupliChek[myVec[i]]; // |
} // |
else{ // |
leftNear[i] = -1; // |
} // |
dupliChek[myVec[i]] = i; // |
} // |
dupliChek.clear(); // +--用map辅助找出每个位置前后最近重复元素的过程
for(int i = n - 1; i >= 0; i--){ // |
if(dupliChek.count(myVec[i])){ // |
rghtNear[i] = dupliChek[myVec[i]]; // |
} // |
else{ // |
rghtNear[i] = n; // |
} // |
dupliChek[myVec[i]] = i; // |
} //-----+
if(range_check(0,n - 1))
printf("non-boring\n");
else
printf("boring\n");
}
return 0;
}