以前没有遇到过中途相遇这种方法,看紫书解释后感觉非常巧妙。本题的解法是在给定区间找出唯一的元素后,分别在元素的左半区间和元素的右半区间查找。
问题是
1:如何在一段区间找出唯一的元素,可以转化为该元素左右邻居的位置下标(与该元素值相同),因此可以使用双向链表,用map进行预处理该双向链表。
2:如果从左向右或者从右向左寻找唯一的元素,最坏的时间复杂度总是可以被卡到n^2。中途相遇的思路,就是同时从两边向中间寻找唯一的元素,可以保证最坏的时间复杂度是nlogn。
#include <iostream>
#include <cstring>
#include <unordered_map>
using namespace std;
const int N = 2e5 + 10;
const int INF = 2e6;
int a[N];
int ne[N], pre[N];
unordered_map<int, int> mp;
bool dfs(int l, int r)
{
if (l >= r)
return true;
int i = l, j = r;
int suc = 0;
while(i <= j)
{
if (pre[i] >= l || ne[i] <= r) i ++;
else
{
suc = 1;
break;
}
if (pre[j] >= l || ne[j] <= r) j --;
else
{
suc = 2;
break;
}
}
if (!suc) return false;
if (suc == 1)
if (!dfs(l, i - 1) || !dfs(i + 1, r)) return false;
if (suc == 2)
if (!dfs(l, j - 1) || !dfs(j + 1, r)) return false;
return true;
}
int main()
{
int T;
cin >> T;
while(T --)
{
mp.clear();
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i ++)
{
ne[i] = INF;
scanf("%d", &a[i]);
if (mp.count(a[i]) == 0)
pre[i] = 0;
else
{
pre[i] = mp[a[i]];
ne[mp[a[i]]] = i;
}
mp[a[i]] = i;
}
if (dfs(1, n)) puts("non-boring");
else puts("boring");
}
}