完美洗牌问题(2)

完美洗牌问题(2)

题目描述

给定一个数组arr,请将数组调整为依次相邻的数字,总是先<=、再>=的关系,并交替下去。比如数组中有五个数字,调整成[a,b,c,d,e],使之满足a<=b>=c<=d>=e。

输入描述:

输入包含两行,第一行一个整数 n ( 1 ≤ n ≤ 1 0 5 ) n(1 \leq n \leq 10^5) n(1n105),代表数组的长度,接下来一行n个整数,代表数组 a r r ( 1 ≤ a r r i ≤ 1 0 9 ) arr(1 \leq arr_i \leq 10^9) arr(1arri109)

输出描述:

输出一行,代表调整后的数组。

示例1
输入
6
1 2 3 4 5 6
输出
1 3 2 5 4 6
示例2
输入
3
1 2 3
输出
1 3 2
备注:

时间复杂度 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n),空间复杂度 O ( 1 ) O(1) O(1)


题解:

构造题,肯定有多种解法,这里提供两种构造方法:

法一:

参考 完美洗牌问题(1) ,对数组按照从大到小排序,然后分奇偶讨论:

  • 若元素个数为奇数,则对 a[1…n-1] 进行完美洗牌操作
  • 若元素个数为偶数,则对 a[1…n] 进行完美洗牌操作
法一代码:
#include <cstdio>
#include <functional>
#include <algorithm>

using namespace std;

const int N = 100001;
const int INF = 1e9 + 10;

int n;
int a[N];

int main(void) {
    scanf("%d", &n);
    for ( int i = 1; i <= n; ++i ) scanf("%d", a + i);
    sort( a + 1, a + n + 1, greater<int>() );
    int m;
    if ( n & 1 ) m = n - 1;
    else m = n;
    for ( int i = 1; i <= m; ++i ) {
        if ( a[i] > 0 ) {
            int pre = a[i] - INF;
            int nxt = (i << 1) % (m + 1);
            while ( nxt != i ) {
                int tmp = a[nxt] - INF;
                a[nxt] = pre;
                pre = tmp;
                nxt = (nxt << 1) % (m + 1);
            }
            a[nxt] = pre;
        }
    }
    if ( n & 1 ) a[n] -= INF;
    for ( int i = 1; i <= n; ++i )
        printf("%d ", a[i] + INF);
    return 0;
}
法二:

这种方法更简单,对数组从小到大排序,将偶数位数字与下一位奇数位数字进行交换即可。

法二代码:
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 100001;

int n;
int a[N];

int main(void) {
    scanf("%d", &n);
    for ( int i = 1; i <= n; ++i ) scanf("%d", a + i);
    sort( a + 1, a + n + 1 );
    for ( int i = 2; i < n; i += 2 )
        swap( a[i], a[i + 1] );
    for ( int i = 1; i <= n; ++i )
        printf("%d ", a[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值