算法-疯狂队列

文章讲述了如何解决一个关于数组排序的问题,目标是找到一种排列方式,使得两两元素之差的和最大化。对于奇数个数组元素,采用特定的高-低-高-低模式;偶数元素则有不同策略。作者提供了详细的代码实现并分享了解题思路。
摘要由CSDN通过智能技术生成

算法-疯狂队列


前言

起初是因为上周参加一个算法竞赛时有一道题如下:
第一行输入一个数T,表示测试案例数量,第二行输入一个数n,第三行输出一个结果数output。
这个结果数要求从1-n开始,找到任意一种排列方式最大化数组两两之差的和。你现在可能听起来很懵,接下来我将举个例子来说明:
比如:
输入:

  • 第一行:2(表示两个测试案列)
  • 第二行:5(表示从1-5)

输出:

  • 第三行:11(为什么是11呢,因为当数组为1-5,排列如3-2-5-1-4这样两两之差和为(3-2)+(5-2)+(5-1)+(4-1)=1+3+4+3=11为这5个数排序的最大值)
    输入:
  • 第四行:1(第二个测试案例,只有一个数1)

输出:

  • 第五行:1

然后当时想了挺久的吧,以为是找什么关系等差数列什么的,后面就上网搜到了一篇类似的OJ,链接如下:牛客
接下来我就以这篇OJ为例来讲解


一、题目介绍

题目说明
这道题就跟我刚才上面介绍的那道题差不多,我们可以先把这个数组从小到大排序好并且每个都编好编号,但是因为奇数个数不能整除2,按照计算机里面的表示,如5/2=2。因此我们把最中间那个数也作为高数,所以高数会总比低数多一个。如输入
5 10 25 40 25按从小到大排序后为 5 ⏟ 低 1 10 ⏟ 低 2 25 ⏟ 高 1 25 ⏟ 高 2 40 ⏟ 高 3 \underbrace{5}_{低1} \underbrace{10}_{低2} \underbrace{25}_{高1} \underbrace{25}_{高2} \underbrace{40}_{高3} 1 52 101 252 253 40
虽然这道题的数组个数为奇数,但是输入数组个数也可能为偶数,所以我们要分情况讨论:

第一种情况:当数组个数为奇数时(如题目一样):
最大化排序方式为25-10-40-5-25,我们用上面的编号来表示 25 ⏟ 高 1 10 ⏟ 低 2 40 ⏟ 高 3 5 ⏟ 低 1 25 ⏟ 高 2 \underbrace{25}_{高1} \underbrace{10}_{低2} \underbrace{40}_{高3} \underbrace{5}_{低1} \underbrace{25}_{高2} 1 252 103 401 52 25注意这里最左边的是高1,这里恰好高1和高2相等了,如果换成其他的数,这里要放的是高1。我们可以观察到这个形式其实就是高-低-高-低-高的形式。然后两两相减为 25 − 10 ⏟ 高 1 − 低 2 + 40 − 10 ⏟ 高 3 − 低 2 + 40 − 5 ⏟ 高 3 − 低 1 + 25 − 5 ⏟ 高 2 − 低 1 \underbrace{25-10}_{高1-低2} +\underbrace{40-10}_{高3-低2}+ \underbrace{40-5}_{高3-低1} +\underbrace{25-5}_{高2-低1} 12 2510+32 4010+31 405+21 255然后我们加起来,把高的放一起,低的放一起,就变为了下面式子:
高 1 + 高 2 + 高 3 + 高 3 − 2 × ( 低 1 + 低 2 ) 高1+高2+高3+高3-2\times(低1+低2) 1+2+3+32×(1+2),这个式子让我们想到可以转换成下面形式: 2 × ( 高 1 + 高 2 + 高 3 ) − 2 × ( 低 1 + 低 2 ) − 高 1 − 高 2 2\times(高1+高2+高3)-2\times(低1+低2)-高1-高2 2×(1+2+3)2×(1+2)12即可。因为我们发现高1和高2最大化数组排列时,分别位居数组两侧,所以计算值时只会被计算一次,其实就是最小的高数和第二小的高数。而高3最大在中间会被计算两次,其余的低数也都是在中间,也会被计算两次。所以我们想到把全部高数和低数各自分开相加后,因为高1和高2被多算了一次,要减去,所以就是高数和减去低数和然后乘以2再减去高1和高2就是最后的答案。

第二种情况:当数组个数为偶数时,可以整除2,所以高数低数各占一半
我把上面的题目进行修改,改为4个数:5 10 25 40
先进行排序编号: 5 ⏟ 低 1 10 ⏟ 低 2 25 ⏟ 高 1 40 ⏟ 高 2 \underbrace{5}_{低1} \underbrace{10}_{低2} \underbrace{25}_{高1} \underbrace{40}_{高2} 1 52 101 252 40
然后最大化排序方式为: 10 ⏟ 低 2 40 ⏟ 高 2 5 ⏟ 低 1 25 ⏟ 高 1 \underbrace{10}_{低2} \underbrace{40}_{高2} \underbrace{5}_{低1} \underbrace{25}_{高1} 2 102 401 51 25这个式子其实就变成了一个低-高-低-高的形式。两两相减得: 40 − 10 ⏟ 高 2 − 低 2 + 40 − 5 ⏟ 高 2 − 低 1 + 25 − 5 ⏟ 高 1 − 低 1 \underbrace{40-10}_{高2-低2}+ \underbrace{40-5}_{高2-低1} +\underbrace{25-5}_{高1-低1} 22 4010+21 405+11 255还是高的放一起低的放一起: 高 1 + 高 2 + 高 2 − 低 1 − 低 1 − 低 2 高1+高2+高2-低1-低1-低2 1+2+2112
转换成: 2 × ( 高 1 + 高 2 ) − 2 × ( 低 1 + 低 2 ) − 高 1 + 低 2 2\times(高1+高2)-2\times(低1+低2)-高1+低2 2×(1+2)2×(1+2)1+2这里要注意,奇数时我们是多加了一个要减去,偶数时这里我们是多减了一个要加回来。因为个数为偶数所以最大的低数会放在最左边,最小的高数会放在最右边,这两个数都会只被计算一次。其余数都会被计算两次。而且注意最大低数因为是减去了两次,所以要加回来一个。

二、代码实现

#include<iostream>
#include<algorithm>
using namespace std;
int cal(int* num, int length) { //输入数组和长度
    //先升序排序
    sort(num, num + length);
    int bigsum = 0;
    int smallsum = 0;
    int ans = 0; //结果
    //取中位数
    int mid = length / 2;
    for (int i = 0; i < mid; i++) {
        smallsum += num[i]; //低数累加
    }
    for (int i = mid; i < length; i++) {
        bigsum += num[i]; //高数累加
    }
    //判断是奇数还是偶数
    if (length & 1) { //如果是奇数
        return 2 * (bigsum - smallsum) - num[mid] - num[mid + 1];
    } else {
        return 2 * (bigsum - smallsum) - num[mid] +num[mid - 1];
    }
}
int main() {
    int n;
    cin >> n;
    int*num=new int[n];
    for (int i = 0; i < n; i++) {
        cin >> num[i];
    }
    cout << cal(num, n);
    delete[] num;
    return 0;
}

结果也是成功AC:在这里插入图片描述


三、写在最后

因为这是本人第一次写博客,如果有什么错误或者写的不好的地方,欢迎各位提出宝贵的意见。

最后就是写一段勉励的话吧:
感觉上了大学后,你会感觉很多人比你优秀或者怎么怎么样。每个人对优秀有自己的标准,你不能达到所有人认定的优秀条件,可那有怎么样,你可以大声坦然自己的平庸,也可以很坚定的说出其实我也不错。人民日报说过:“无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁,焦虑回调你本就不多的热情和定力。”如果说,小学初中高中你的坦途顺利,那么我祝你成年迈进大学依旧成功,如果不能,那我希望你可以悦纳自己,接受自己的一切,包括你的暗淡无光与无人在意。

“抬头自卑,低头自得,唯有平视,才能看见真实的自己。”

愿你我都能摆脱内耗,接受平庸!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值