牛牛的排序子序列问题

简介: 牛牛的排序子序列问题

一.问题描述



1)排序子序列 牛牛定义排序子序列为一个数组中一段连续的子序列, 并且这段子序列是非递增或者非递减排序的。 牛牛有一 个长度为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的每个数字。


3)输出描述: 输出一个整数表示牛牛可以将A至少划分为多少段排序子序列


4)示例:

输入 6 1 2 3 2 2 1

输出 2


二.解题思路



1)

子序列有如下要求: 非递增或非递减排序;

递增序列: 1 2 3 4 …

递减序列: 9 7 6 5 …

既不递增也不递减序列: 1 2 2 3 4 或者 9 7 6 6 6 5


综上所述:子序列的顺序可以任意排序,是不做要求的

那么如何判定其为子序列?

非递增则其为既不递增也不递减或者递减序列;

非递减则其为既不递增也不递减或者递增序列;


综上所述:


当给定一组数据, 其原本为递增序列(1 2 3 …)直至下一个数让其改变了原本的递增序列(1 2 3 2… 或者 1 2 3 3 ),则此时这个数之前的所有数可以分为一组,看作递增或者既不递增也不递减的子序列;


当给定一组数据,其原本为递减序列(6 5 4 …) 直至下一个数让其改变了原本的递减序列(6 5 4 3… 或者 6 5 4 4), 则此时这个数之前的所有数可以分为一组,看作递减或者既不递增也不递减的子序列;


2)输出要求: 可以将数组A至少划分为多少段子序列,至少是关键!!!

那么,如何去判断至多至少问题呢?


看一组例子:

6e06b4991813451b92a38f467398abc2.png


序列规则, 可以得到如下子序列分组

8ac8bd5b07934cb189384ab385b4857c.png


1)原本为一个递减序列(6 2 1),下一个1 排进来时,变成 (6 2 1 1), 符合要求让原本的递减序列变成了一个既不递增也不递减序列,因此 (6 2 1) 可以作为一个子序列

9e4aa6bff44941c9a91736145ad7b5ce.png


2)原本为一个暂时无序序列(1),下一个1排进来时,变成了(1 1 ),符合要求让原本的序列变成了一个既不递增也不递减序列,因此(1)可以单独做一个子序列

ffaf328792ee459991a0295173786f3d.png


3)原本为一个递增序列(1 2 ), 下一个1 排进来时,变成了(1 2 1),符合要求让原本递增的序列变成了一个既不递增也不递减序列,因此(1 2 )可以单独做一个子序列

0df48fbd10a94745bfdc130eebb26c6e.png



4)最后的递增序列(1 2),由于数据已经遍历完,但仍未改变其序列,因此,最后的递增序列(1 2) 可以单独做一个子序列


综上所述: 上述一组数据,一共可以有四个子序列

但是,上述的一组数据,还可以按照要求如下分

85fd1c5df4b84f7aa66c89e97ffd8fcd.png


1)当 6 , 2, 1 依次排进来时,此时为一个递减序列,但当第二个1排进来时,发现其变成了一个既不递增也不递减序列(6 2 1 1),但当第三个1也排进来时,其任然可以保持为一个既不递增也不递减序列,因此我们可以将其归为一个子序列(6 2 1 1 1)

2213ba246e9f49989e79e1577207674a.png


2)此时的三个数据( 2 1 2) 很明显可以分为两组子序列(2 1) 和 (2),如此分的话,可以认为上述一组数可以有三个子序列,比第一次的划分少一个。


综上所述: 如果需要满足至少这个条件的话,当下一个数和当前数相比,如果相同时,应当让当前这个数和前面的数归为一组因此为了保持最少的子序列,子序列的判定就变成了当遇到违背其递增或者递减时即可作为划分条件


三.代码实现(java)



    public static int fun2() {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(); // 数组长度
        int[] arr = new int[n + 1]; // 防止遍历数组越界
        int len = 0;
        while (scanner.hasNextInt()) {
            // 存储数据
            for (int i = 0; i < n; i++) {
                arr[i] = scanner.nextInt();
            }
            int i = 0;
            len = 0;
            while (i < n) {
                // 递增
                if (arr[i] < arr[i + 1]) {
                    // 向后继续执行 -- 前提为i不越界,且满足升序
                    while (i < n && arr[i] < arr[i + 1]) {
                        i++;
                    }
                    // 此时已经非递增 (arr[i+1] <= arr[i]) 则之前为一组
                    len++;
                    // i+1 为下一组子序列开头
                    i++;
                }
                // 相等 -- 既不递增也不递减序列 -- 继续向后排序
                else if (arr[i] == arr[i + 1]) {
                    while (i < n && arr[i] == arr[i + 1]) {
                        i++;
                    }
                    // 此时 arr[i+1] > arr[i]  或者  arr[i+1] < arr[i] 则当前arr[i]与之前分为一组
                    i++;
                }
                // 递减
                else {
                    while (i < n && arr[i] > arr[i + 1]) {
                        i++;
                    }
                    len++;
                    i++;
                }
            }
        }
        return len;
    }


  • 最后,希望各位可以多多指点!*
相关文章
|
3月前
|
算法 搜索推荐
每日一题——下一个排列
每日一题——下一个排列
|
存储 算法 C++
【数据结构与算法】哈希表1:字母异位词 & 两数交集 & 快乐数 & 两数之和
【数据结构与算法】哈希表1:字母异位词 & 两数交集 & 快乐数 & 两数之和
67 0
|
搜索推荐 Java
Leecode912. 排序数组
Leecode912. 排序数组
43 0
|
C语言 C++
C/C++每日一练(20230514) 全排列、分数转小数、排序链表去重II
C/C++每日一练(20230514) 全排列、分数转小数、排序链表去重II
82 0
数位排序-蓝桥杯-2022
利用HashMap该数据结构的特点,因为1到n不会有重复,而且把它做为键
|
算法 C语言
剑指Offer 第53题:数字在升序数组中出现的次数
剑指Offer 第53题:数字在升序数组中出现的次数
123 0
剑指Offer 第53题:数字在升序数组中出现的次数
|
算法
每日一题——字典序排数
每日一题——字典序排数
57 0
每日一题——字典序排数
|
算法
LeetCode每日一题(3)——字典序排数
LeetCode每日一题(3)字典序排数 1.题目 2.示例 3.思路 4.代码
LeetCode每日一题——1636. 按照频率将数组升序排序
给你一个整数数组 nums ,请你将数组按照每个值的频率 升序 排序。如果有多个值的频率相同,请你按照数值本身将它们 降序 排序。
163 0
|
算法 Python
LeetCode每日一题——386. 字典序排数
给你一个整数 n ,按字典序返回范围 [1, n] 内所有整数。
83 0