• 【算法】不无聊序列


    问题:

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

    思想:

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

    步骤:

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

    时间复杂度:

    O(nlogn)

    代码(C++):

    #include 
    #include 
    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;
    }
    

    运行结果:

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

  • 相关阅读:
    SQL Server中substring的用法
    上周内容回顾
    Java基于SpringBoot的旅游网站的设计与实现论文
    Linux面试题
    SpringBoot入门
    【算法练习Day42】买卖股票的最佳时机 III&&买卖股票的最佳时机 IV
    苹果或推出多屏幕iPhone;​爱彼迎CEO:办公室时代已过去;Apache Flink 1.15 发布|极客头条
    Maven 构建配置文件
    Shell特殊变量(Shell $#、$*、$@、$?、$$)的使用
    辅助解决小白遇到的电脑各种问题
  • 原文地址:https://blog.csdn.net/Yua_H/article/details/126957998