考研数据结构(每日一题)
题目:已知由n(n>=2)个正整数构成得到集合A={ak|0<=k<n},将其划分为两个不相交的子集A1和A2,元素个数分别是n1和n2,A1和A2中的元素之和分别为S1和S2,设计一个尽可能高效的划分算法,满足|n1-n2|最小且|S1-S2|最大。
算法思想:
将最小的n/2个元素放在A1中,其余的元素放在A2中,分组即可满足题目要求。
按照快速排序的思想,基于枢轴将n个整数划分为两个子集。根据划分后枢轴所处的位置i进行处理:
若i=n/2,则分组完成,算法结束
若i<n/2,则枢轴及之前的所有元素均属于A1,继续对i之后的元素进行划分
若i>n/2,则枢轴及之后的所有元素均属于A2,继续对i之前的元素进行划分
其平均时间复杂度为O(n),空间复杂度是O(1)
完整代码:
int setPartition(int a[],int n){
int pivotket,low = 0,low0 = 0,high = n - 1,high0 = n - 1,flag = 1,k = n / 2,i;
int s1 = 0;
int s2 = 0;
while (flag)
{
pivotket = a[low]; //选择枢轴
while (low < high) //基于枢轴数据进行划分
{
while (low < high && a[high] >= pivotket)
{
-- high;
}
if (low != high)
{
a[low] = a[high];
}
while (low < high && a[low] <= pivotket)
{
++ low;
}
if (low != high)
{
a[high] = a[low];
}
}
a[low] = pivotket;
if (low == k - 1) //若枢轴是第n/2小元素,划分成功
{
flag = 0;
}else
{
if (low < k - 1)
{
low0 = ++ low;
high = high0;
}else{
high0 == -- high;
low = low0;
}
}
}
for (i = 0; i < k; i++)
{
s1 += a[i];
}
for (i = k; i < n; i++)
{
s2 += a[i];
}
return s2 - s1;
}