题目:
基础:我写完了代码被 1 2 3 3 5这组数据钻牛角了。发现自己搞错了一些基础概念。首先,集合具有唯一性,不存在相同的元素,所以这组数据不可能存在。其次,不相交三个字并不是没意义,因为子集有很多个,不相交三个字把子集的划分方式规定死了,就是把两个子集拼装能变回原集合。
分析:相比于前几年的线性表算法题难度有明显提升。不再能直接暴力思路模拟题干。①不相交即没有公共元素,规定了子集划分方式。②|n1-n2|最小即两个子集分配的时候要尽量雨露均沾。③|S1-S2|最大即,虽然分配元素个数要差不多,但分配出去的元素大小相差很大,联想到一种思路即分一个大的出去,然后分一个小的出去,前提是存在一条有序的序列能让我们这么做。从而得到一种可能可行的思路即排序后分果果,理论推完实践开始。
(打脸了,之前2013的想偷懒不写排序的优化代码,现在直接变成首选了。。。。。,不过还是偷了一下懒,没写归并的模板,调用了sort函数)
思路一:sort排序(快排+插排)
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e5;
int A[N],A1[N],A2[N];
int n1,n2,S1,S2,n;
void check(int A[],int n)
{
for(int i=0,j=n-1;i<=j;i++,j--)//依次分配
{
if(i!=j)
{
A1[n1++]=A[i];
S1+=A[i];
A2[n2++]=A[j];
S2+=A[j];
}
else//当元素为奇数个时,决定中间那个元素的去留
{
if(S1<S2) A2[n2++]=A[i],S2+=A[i];
else A1[n1++]=A[i],S1+=A[i];
}
}
for(int i=0;i<n1;i++) cout<<A1[i]<<' ';
puts("");
for(int i=0;i<n2;i++) cout<<A2[i]<<' ';
puts("");
printf("|n1-n2|=%d,|S1-S2|=%d",abs(n1-n2),abs(S1-S2));
}
int main()
{
cin>>n;
for(int i=0;i<n;i++) cin>>A[i];
sort(A,A+n);//快速+插入排序
check(A,n);//分配集合
return 0;
}
平均时间复杂度为:O(nlongn),最坏时间复杂度为:O(n^2)但是在该题目情景下不会进入到最坏情况。空间复杂度为:O(logn)
思路二:归并排序
思考:想进一步在排序的思路上降低时间复杂度,就得实现真正O(nlogn)的算法即归并排序。
具体模板请自行搜索,推荐Acwing y总写的归并模板。
思路三:调整排序
思考:再再一次提升效率只能针对排序的内部实现优化,具体想了解参考2016年专业408算法题,或看王道的真题讲解(个人感觉这次的讲解的不是很形象,可能是上来就是最优解的原因,必须熟悉和理解快排原理的基础上才能改动模板)。