排序子序列

该博客主要探讨了一道编程题目,涉及数组的排序子序列划分问题。通过示例解释了如何判断非递增或非递减排序,并给出了两种不同的解题思路和代码实现。题解代码更简洁且考虑了边界条件,旨在帮助读者理解算法和优化代码。
摘要由CSDN通过智能技术生成

题目链接

排序子序列

题目描述与示例

牛牛定义排序子序列为一个数组中一段连续的子序列,并且这段子序列是非递增或者非递减排序的。牛牛有一个长度为n的整数数组A,他现在有一个任务是把数组A分为若干段排序子序列,牛牛想知道他最少可以把这个数组分为几段排序子序列.
如样例所示,牛牛可以把数组A划分为[1,2,3]和[2,2,1]两个排序子序列,至少需要划分为2个排序子序列,所以输出2

输入描述

输入的第一行为一个正整数n(1 ≤ n ≤ 10^5)
第二行包括n个整数A_i(1 ≤ A_i ≤ 10^9),表示数组A的每个数字。

输出描述

输出一个整数表示牛牛可以将A最少划分为多少段排序子序列

示例

输入:

6
1 2 3 2 2 1

输出:

2

解题思路

题目分析

题目还是比较简单的,就相当于给你一个数组,然后你按规则把这个数组划分,最少可以分几段即可。需要注意的地方就在于需要划分出来的排序子序列是一个非递增排序或者非递减排序。

非递增(递减)排序我感觉说简单点就是在单调递增(递减)排序的基础上允许中间元素出现重复,就比如1 2 3单调递增,那么1 2 2 3即使个非递减排序。

个人思路

  1. 开始遍历数组时判断下一个元素与首元素的大小关系,确定即将进入非递增(非递减)排序
  2. 调用对应函数找到结束非递增(非递减)排序的位置下标
  3. count++

我感觉不太会描述我自己的思路了,给个图理解下吧,就拿题目给的示例来看:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UGgObkg6-1653201113981)(C:\Users\lwz\AppData\Roaming\Typora\typora-user-images\image-20220521132155934.png)]

函数逻辑比较简单,匹配到下一个数据不再大于等于(小于等于)就表示找到了非递减(非递增)的位置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3DI8mqTw-1653201113991)(C:\Users\lwz\AppData\Roaming\Typora\typora-user-images\image-20220521132444837.png)]

for循环的i++后会自动指向下一个元素进行新一轮判断直到完全遍历数组为止。

这个地方需要注意的是,当下一个元素和当前元素相同的时候,无论是划分到非递增或者非递减都是一样的,所以相同元素只需要执行i++即可无需count++。

代码展示

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

//找到非递减排序结束的下标
int IsASC(const vector<int> &A,size_t begin)
{
    size_t end=begin;
    for(;end<A.size();end++)
    {
        if(A[end+1]<=A[end])
        break;
    }
    return end;
}

//找到非递增排序结束的下标
int IsDESC(const vector<int> &A,size_t begin)
{
    size_t end=begin;
    for(;end<A.size();end++)
    {
        if(A[end+1]>=A[end])
        break;
    }
    return end;
}

int main()
{
    int n;
    vector<int> A;
    cin>>n;
    int tmp;
    for(int i=0;i<n;i++)
    {
        cin>>tmp;
        A.push_back(tmp);
    }
    int count=0;
    for(size_t i=0;i<A.size();i++)
    {
        //相等的话无需寻找结束标志,i++即可
        if(A[i+1]==A[i])
        {
            continue;
        }
        //下一个元素大于当前元素表明即将进入非递减排序
        if(A[i+1]>A[i])
        {
            //找到结束非递减排序的下标后修改i的值
            //这个地方一定要修改,不然会导致这个子序列的所有字符都会进行一次划分
            i=IsASC(A,i);
            count++;
            continue;
        }
        if(A[i+1]<A[i])
        {
            //同上
            i=IsDESC(A,i);
            count++;
        }
    }
    cout<<count;
    return 0;
}

题解

本次我的思路与题解几乎一致,但是在实现上却显得复杂了很多,也有些小细节没有处理好,还是先给出题解代码:

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

int main()
{
    int n;
    cin>>n;
    vector<int> a;
    //因为判断时都是拿下一个元素与当前元素做比较
    //当当前元素为最后一个元素时,下一个元素的访问会越界,所以多给了一个空间
    a.resize(n+1);
    //范围for,与for(int i=0;i<n;i++)一致,具体可参考博客初始C++
    for(auto& e:a)
    {
        cin>>e;
    }
    //题目给出的数据都是正整数,所以最够一个位置给0不会影响结果,此处只是为了避免越界访问的问题
    a[n]=0;
    int count=0;
    int i=0;
    while(i<n)
    {
        if(a[i]<a[i+1])
     {
        //循环到a[i+1]<a[i]的位置
        //即对应找到非递减结束的位置
        //同时需要保证到i不会超过数组的元素个数
        while(a[i]<a[i+1]&&i<n)
        {
            i++;
        }
        count++;
        i++;
     }
       if(a[i]==a[i+1])
       {
           i++;
       }
        if(a[i]>a[i+1])
        {
       while(a[i]>a[i+1]&&i<n)
     {
            i++;
        }
        count++;
        i++;
     }
    }
    cout<<count;
    return 0;
}

关于题解代码的解释已经在代码中以注释的形式给出,整体思路几乎没有区别,不过题解的代码更加简洁,也考虑的更加周全,需要注意的是,这道题牛客网并没有检测到访问越界,所以就算设置成n也是没有问题的,不过自己还是需要知道存在这些问题,才能防患于未然。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值