交换序列a,b 中的元素,使两序列的和之差最小

算法实现

有两个序列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;
    }
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值