1045. 快速排序(25)

原题: https://www.patest.cn/contests/pat-b-practise/1045

思路: 看样子乙级最后一道题, 如果复杂度是n^2, 基本上是错了, 不错
也是超时的节奏, 一开始自己的想法复杂了.

我们直接先看题目给出的测试

输入样例:
5
1 3 2 4 5
输出样例:
3
1 4 5

要想确定某一个数是不是主元, 就是要确定这个数左边的值都比当前数小,
而右边的值都比当前数大(这不是废话吗!)
假如我们另外有2个数组, 和当前数组一一对应, 分别存放的是当前数左边
最大值和当前数右边最小值, 这样简单作下比较就OK了.
我们看下给出的测试, 首先1的左边没有数, 可能大家愿意认为1的左边最
小数是0, 右边最大数是2. 这样 0 1 2, 1就是我们需要的主元. 但是我
们现在不这样想, 我们把1本身也给考虑进去, (这样主要是为了编程方便)

把自身也考虑进去, 那么1左边最大的数就是1, 1右边最小的数还是1, 对应
上面的测试样例, 我们需要这样的数组

原来的: 1 3 2 4 5
左边的: 1 3 3 4 5
右边的: 1 2 2 4 5

没错, 你会发现如果当前数是主元, 那它就是和左右都相等. 最后最关键的
问题就是怎么得出这2个数组了, 自己在纸上思考下, 或者看看下面的代码,
相信你已经会写了.

坑1: 如果所有的数都不是主元, 输入2行, 分别是0\n

实现:

#include <stdio.h>

int main (void) {
    int n;
    int arr[100010];
    int lmax[100010];
    int rmin[100010];
    int count = 0;
    int max;
    int min;
    int i;
    char ch = ' ';

    scanf("%d", &n);
    for (i = 0; i < n; i++) {
        scanf("%d", &arr[i]);
    }

    // 从左边开始, 一步步找当前数左边的最大数
    max = arr[0]; // 初始最大数
    for (i = 0; i < n; i++) {
        if (arr[i] > max) {
            max = arr[i];
        }
        lmax[i] = max;
    }
    // 从右边开始, 一步步找当前数右边的最小数
    min = arr[n - 1]; // 初始最小数
    for (i = n - 1; i >= 0; i--) {
        if (arr[i] < min) {
            min = arr[i];
        }
        rmin[i] = min;
    }

    // 接下来打印也要废些功夫, 首先遍历把主元数出来, 
    // 并且把非主元标记为0
    for (i = 0; i < n; i++) {
        if (arr[i] == lmax[i] && arr[i] == rmin[i]) {
            count++;
        } else {
            arr[i] = 0;
        }
    }
    printf("%d\n", count);
    // 接着利用count, 控制打印格式
    // 注意空在C语言中对应着 \0
    for (i = 0; i < n && count != 0; i++) {
        if (count == 1) ch = '\0';
        if (arr[i] != 0) {
            printf("%d%c", arr[i], ch);
            count--;
        }
    }
    printf("\n");

    return 0;
}

参考: http://www.jianshu.com/p/2927e519d9c5

posted @ 2017-11-18 16:10  阿胜4K  阅读(229)  评论(0编辑  收藏  举报