【分治法】求解不无聊序列

题意

一个序列为不无聊序列,则必须满足划分任意长度的连续子序列(包括其本身),其中至少存在一个元素仅仅出现一次,即至少有一个元素不重复。
例子:
123321 ——无聊序列,子序列33中没有独特元素。
12321 ——不无聊序列,任意子序列都有独特元素。

思路

  • 划分:根据当前的元素进行划分(与快速排序的partition划分主元类似),不断累加或累减left和right,从而不断缩小查找的范围
  • 解决:判断在left~right的范围内是否有重复元素
  • 合并:以布尔值的形式返回

递归体:判断在left~right所构成的区间内,访问prepos[]和nextpos[],看是否存在与当前元素相同的元素,没有则递归进行判断
递归出口:当左指针left大于右指针right时为递归出口

false:无聊序列
true:不无聊序列

参考博客

代码

#include <bits/stdc++.h>
using namespace std;
const int MAX = 1e5 + 5;
//prepos[i]表示序列中,位于第i个元素之前,且与第i个元素相同的元素的下标是prepos[i] 
//nextpos[i]表示序列中,位于第i个元素之后,且与第i个元素相同的元素的下标是nextpos[i] 
int prepos[MAX], nextpos[MAX];
int n;
int arr[MAX];
map<int, int> mp; //记录数字出现的下标
void init()
{
	for(int i = 0; i < n; ++i)
	{
		int num = arr[i];
		if(mp.count(num) == 0)
			prepos[i] = -1;
		else
			prepos[i] = mp[num];
		mp[num] = i;//存放的是索引下标 
	}
	mp.clear();
	for(int i = n - 1; i >= 0; --i)
	{
		int num = arr[i];
		if(mp.count(num) == 0)
			nextpos[i] = n + 1;
		else
			nextpos[i] = mp[num];
		mp[num] = i;
	}
}
bool solve(int left, int right)
{
	if(left >= right)
		return true;
	int i = left, j = right - 1;//从两端遍历 
	while(i <= j)//直到两指针相遇 
	{
		//判断在left~right的区间内,是否存在与元素i相等的元素 
		if(prepos[i] < left && nextpos[i] > right)//不存在则进行递归 
			return solve(left, i - 1) && solve(i + 1, right);
		++i;
		//判断在left~right的区间内,是否存在与元素j相等的元素 
		if(prepos[j] < left && nextpos[j] > right)
			return solve(left, j -1) && solve(j + 1, right);
		--j;
	}
	return false;
}
int main(int argc, char *argv[]) {
	scanf("%d", &n);
	for(int i = 0; i < n; ++i)
	{
		scanf("%d", &arr[i]);
	}
	init();
	if(solve(0, n))
		printf("non-boring sequence\n");
	else
		printf("boring sequence\n");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值