算法实现
有两个序列a,b,大小都为n,序列元素的值任意整数,无序;
要求:通过交换a,b 中的元素,使[序列a 元素的和]与[序列b 元素的和]之间的差最小。
var a=[100,99,98,1,2, 3];
var b=[1, 2, 3, 4,5,40];
题目来自July大神的 微软公司等数据结构+算法面试100题(第1-100题)全部出炉
在此写下自己的实现
#include<iostream>
#include<list>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
int n,i,j,s1=0,s2=0;
int A, min = 0;
int li,lj,low,high,tmp,count;
vector<int> v1,v2,t;
cin>>n;
for(i = 0;i<n;i++){
cin>>j;
v1.push_back(j);
s1 += j;
}
for(i = 0;i<n;i++){
cin>>j;
v2.push_back(j);
s2 += j;
}
//将s1设置为和为大的那个集合
if(s1<s2){
j = s1;
s1 = s2;
s2 = j;
t = v1;
v1 = v2;
v2 = t;
}
//排序为了二分查找
sort(v1.begin(),v1.end());
sort(v2.begin(),v2.end());
low = 0;
high = v2.size()-1;
count=0;
A = s1-s2; //A 中存放当前两个集合的差值
while(min!=A){
min = A;
count++;
//对集合v1每一个i都进行查找
for(i=0;i<n;i++){
tmp = v1[i]-A/2;
low = 0;
high = v2.size()-1;
//在集合v2中二分查找最后一个小于tmp值的元素
//或者第一个大于tmp值的元素
while(low<high){
j = (low+high)/2;
if(v2[j]<tmp)
low = j+1;
else if(v2[j]>tmp)
high = j-1;
else{
//恰好相等的话则不用再找了,直接break
li = i;lj = j;
min = 0;
break;
}
}
//若有恰好等于tmp值的,无需再找,直接得到更新两个集合
if(min == 0)
{
break;
}
//选择最合适的那个元素对应的下标
if(low!=v2.size()-1&&low!=0){
if(abs(tmp - v2[low]>abs(tmp-v2[low+1]))
&& abs(tmp - v2[low+1])<abs(tmp-v2[low-1])){
low = low+1;
}
if(abs(tmp - v2[low])>abs(tmp-v2[low-1])
&& abs(tmp - v2[low+1])>abs(tmp-v2[low-1]))
low = low-1;
}
//更新min值,并记录下标
if(v1[i]-v2[low]>0 && v1[i]-v2[low]<A )
if(min>abs(tmp - v2[low])){
min = abs(tmp - v2[low]);
li = i;
lj = low;
}
}
//以下为交换当前最合适的两元素
if(min<A)
{
s1 = s1-v1[li]+v2[lj];
s2 = s2+v1[li]-v2[lj];
tmp = v1[li] ;
v1[li] = v2[lj];
v2[lj] = tmp ;
A = s1-s2;
sort(v1.begin(),v1.end());
sort(v2.begin(),v2.end());
continue;
}
}
//打印结果
for(i = 0;i<n;i++){
cout<<v1[i]<<" ";
}
cout<<endl;
for(i = 0;i<n;i++){
cout<<v2[i]<<" ";
}
cout<<endl<<count<<endl;
return 0;
}