【算法】不无聊序列

问题:

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

思想:

采用分治法求解,如果要成为一个不无聊序列,就必须至少有一个独特(与序列中任何数都不重复)的数,找到这个数并且进行递归

步骤:

  • (1)定义prepos和nextpos两个数组,记录了序列中每个数前一次出现和后一次出现的位置
  • (2)从序列两边依次开始遍历,通过上面两个数组找寻那个独特的数
  • (3)无论是从序列左边还是序列右边找到独特的数,都以该数位置为界限,将该数左边和该数右边递归,判断这两边是否为不无聊序列,并返回bool值
  • (4)若这两边均为不无聊序列,则整个序列为不无聊序列

时间复杂度:

O(nlogn)

代码(C++):

#include <iostream>
#include <map>
using namespace std;

//prepos[i]表示序列中,位于第i个元素之前,且与第i个元素相同的元素的下标是prepos[i] 
//nextpos[i]表示序列中,位于第i个元素之后,且与第i个元素相同的元素的下标是nextpos[i] 
int prepos[10000],nextpos[10000];
int n; //数组大小
int arr[10000]; //定义数组
map<int,int>mp; //记录每个数字出现的下标

void find(){
    //赋值prepos数组
    for(int i=0;i<n;i++){
        int num=arr[i];
        if(mp.count(num)==0){ //判断map中有没有出现该数字
            prepos[i]=-1; //没出现过就赋值-1
        }else{
            prepos[i]=mp[num];  //出现过就赋值前一次出现时所在的索引位置
        }
        mp[num]=i; //更新数字对应的索引
    }
    mp.clear(); //清空map
    //赋值nextpos数组
    for(int i=n-1;i>=0;i--){
        int num=arr[i];
        if(mp.count(num)==0){ //判断map中有没有出现该数字
            nextpos[i]=n+1; //没出现过就赋值n+1
        }else{
            nextpos[i]=mp[num];  //出现过就赋值前一次出现时所在的索引位置
        }
        mp[num]=i; //更新数字对应的索引
    }
    mp.clear();
}

bool judge(int left,int right){
    if(left>=right) return true;
    int i=left,j=right; //从序列两端开始遍历
    while(i<=j){ //两端指针i,j未相遇
        if(prepos[i]<left&&nextpos[i]>right){  //若序列左边存在独特(不重复)的数,则进行递归
            return judge(left,i-1)&&judge(i+1,right);
        }
        i++;
        if(prepos[j]<left&&nextpos[j]>right){ //若序列右边存在独特(不重复)的数,则进行递归
            return judge(left,j-1)&&judge(j+1,right);
        }
        j--;
    }
    return false;
}

int main(){
    cout<<"input seqSize: ";
    cin>>n;
    cout<<"input seqNum: ";
    for(int i=0;i<n;i++){
        cin>>arr[i];
    }
    cout<<"the sequence is: "<<endl;
    for(int i=0;i<n;i++){
        cout<<arr[i]<<"\t";
    }
    cout<<endl;
    //找到prepos和nextpos两个数组的值
    find(); 
    //判断是否为不无聊数组
    if(judge(0,n)){
        cout<<"it is a non-boring sequence!";
    }
    else{
        cout<<"it is a boring sequence!";
    }
    return 0;
}

运行结果:

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值