题目:已知有一个集合A,A内的元素大于等于0,现将其分成两个没有交集的子集A1和A2, 元素个数分别是n1和n2, A1和A2中元素的和分别是S1和S2,利用尽可能高效的划分算法,满足|n1-n2|最小且|S1-S2|最大。
设计思路
根据题目可知, 让|n1-n2|=0或1时满足|n1-n2|最小, 若满足|S1-S2|最大需要让S1中元素都是数组中较小的, S2中元素都是数组中较大的。
可以利用快速排序的方式, 根据枢轴所在的位置i
判断
当i=n/2时, 分组完成
当i<n/2时, i位置的元素及其之前元素属于A1, 继续对i之后的元素进行划分
当i>n/2时, i位置的元素及其之后元素属于A2, 继续对i之前的元素进行划分
代码实现
主要位置代码
int QuickSort(int a[], int n){
// pivotKey: 存储分枢轴,
// low最左侧元素, low0标记low在改变前的位置
// high最右侧元素, high0标记high在改变前的位置
// flag作为循环的判断, 当low的值n/2时, flag=0跳出循环
// k数组长度的一半
int pivotKey, low=0,low0=0, high=n-1, high0=n-1, flag=1, k=n/2;
int s1=0, s2=0;
while (flag){ // 当low=k-1 也就是n/2-1时,flag=0
pivotKey=a[low]; // 选择枢轴
// 利用分治思想, 根据枢轴分割枢轴
while (low<high){
while (low<high && a[high]>=pivotKey){
--high;
if (low!=high){
a[low]=a[high];
}
}
while (low<high && a[low]<=pivotKey){
++low;
if (low!=high){
a[high]=a[low];
}
}
}
a[low]=pivotKey; // 把分割值放到对应的位置
// 判断此时low的位置是否处于n/2的位置
if (low==k-1){ // 枢轴是n/2时,分割结束
flag=0; //
} else {
if (low<k-1){
low0=++low;
high=high0;
} else {
low=low0;
high0=--high;
}
}
}
// 数组前一半的值相加
for (int i = 0; i< k; i++) {
s1+=a[i];
}
// 数组后一半的值相加
for (int i = k; i< n; i++) {
s2+=a[i];
}
return s2-s1;
}