回 帖 发 新 帖 刷新版面

主题:“华为面试题!8分钟做出来”,我做的思路,大家帮看一下对不对,谢谢哈~!

原题:有两个数组a,b,大小都为n,数组元素的值任意,无序;
要求:通过交换a,b中的元素,使数组a元素的和与数组b元素的和之间的差最小
原帖http://bbs.misuland.com/bbsstaticweb/bbs_bbsforumannounce1221209363477_2.html

我的答案:
我能想出来怎么做,不过我打字慢,8分钟打不出来!嘿嘿!

前边和大家想的都一样,也是计算出数组a和b的差值c,然后除以2再取整。
之后,再做一个循环过程:
    做一个由所有的a和b的元素差值生成的二维数组sub[i][j]。然后,遍历这个数组寻找和c差值最小的元素,交换数组a和b中的元素i和j。如果,sub[i][j]和c的差值小于或等于1,结束循环,否则,继续。

大家帮看看啊!谢谢了!有写代码快的,帮忙写出来验证一下,不胜感激啊 !

回复列表 (共24个回复)

沙发

我的算法和你不太一样:
1.将a和b中的元素放入大小为2n的数组c中。对c中的元素进行由小到大排序。
2.a先取最小的,b先取次小的,然后根据a,b已取元素和的大小来决定谁来取剩下元素中最小的。
策略是,已取得的所有元素之和大的来取c中剩下元素中的最小者。如此反复,直到取完。每次都是a,b各取一个。
源码:
#include <iostream>
using namespace std;
void main(void)
{
    int n,temp,sum1,sum2,i,j;//n是数组长度,temp临时变量
    int *a,*b,*c;//c是临时数组
    cout<<"请输入n的大小"<<endl;
    cin>>n;
    a=new int [n];
    b=new int [n];
    c=new int [2*n];
    //a和b的初始值,并将它们存入c中
    for(i=0,j=0;i<n;i++,j++)
    {
        cin>>a[i]>>b[i];
        c[j]=a[i];
        j++;
        c[j]=b[i];
    }
    //直接插入排序
    for(i=0;i<2*n;i++)
    {
        temp=c[i];
        for(j=i;j>0&&temp<c[j-1];j--)
            c[j]=c[j-1];
        c[j]=temp;
    }
    a[0]=sum1=c[0];
    b[0]=sum2=c[1];
    //
    for(i=1,j=2;j<2*n;i++,j++)
    {
        if(sum1<sum2)
        {
            b[i]=c[j];
            j++;
            a[i]=c[j];
        }
        else
        {
            a[i]=c[j];
            j++;
            b[i]=c[j];
        }
        sum1+=a[i];
        sum2+=b[i];
    }
    for(i=0;i<n;i++)
        cout<<a[i]<<" ";
    cout<<endl;
    for(i=0;i<n;i++)
        cout<<b[i]<<" ";
    cout<<endl;

}

板凳

[quote]a先取最小的,b先取次小的[/quote]
肯定不对,比如
1 2 7
3 3 4
你的结果就是
1 3 7
2 3 4

3 楼

群里一个朋友写的
#include<math.h> 
#include<stdio.h>
main()
{
    int a[1000],b[1000],n,i,j,sa=0,sb=0,t,c=0,ai=0,bj=0,y=0;
    printf("请输入a,b数组数量n\n");
    scanf("%d",&n);
    printf("请输入数组a中的数\n");
    for (i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
        sa=a[i]+sa;//数组A的和
    }
    printf("请输入数组b中的数\n");
    for (i=0;i<n;i++)
    {
        scanf("%d",&b[i]);
        sb=b[i]+sb;//数组B的和
    }
    t=abs((sa+sb)/2-sa);
    for (i=0;i<n;i++)
    {
        for (j=0;j<n-1;j++)
        {
            c=abs(sb-sa+2*a[i]-2*b[j]);
            if (c<t) {t=c;c=0;ai=i;bj=j;y=1;} 
        }
    }
    if (y!=0)
    printf("交换数组a里的第%d个数和数组b里的第%d个数后,\n两数组各自之和差最小。最小值为:%d\n",ai+1,bj+1,t);
    else
    printf("不用交换,已经是最小了!\n");
}

4 楼

将所有数存在另一个缓存,清空两个数组,从中取最大的,随意放进一个数组,记录它的sum值,再取次大的,判断哪个数组的sum最小,就把次大数存入,以此类推

5 楼

[quote]从中取最大的,随意放进一个数组,记录它的sum值,再取次大的,判断哪个数组的sum最小,就把次大数存入,以此类推[/quote]
明显不靠谱,比如
11, 10, 01
09, 07, 06
按你的方法就成了
11, 07, 06
10, 09, 01

6 楼

3楼的代码一看就知道有问题,因为其只能交换一个元素

比如输入
1 2 3 4
5 6 7 8
他的答案是
7 2 3 4
5 6 1 8
而正确答案是
1 2 7 8
3 4 5 6

7 楼

下班后随便写了一个,还没优化,回家

#include <malloc.h>

struct position
{
    size_t bufsize;
    int* pbuf;
    int sum;
    size_t* pcur;
};
bool thefirst( struct position& pos, int buf[], size_t bufsize )
{
    if( bufsize==0 || bufsize%2!=0 )
        return false;

    pos.bufsize = bufsize;

    pos.pbuf = (int*)malloc( sizeof(pos.pbuf[0])*bufsize );
    for( size_t i=0; i<bufsize; ++i )
        pos.pbuf[i] = buf[i];

    pos.sum = 0;
    for( size_t i=0; i<bufsize; ++i )
        pos.sum += buf[i];

    pos.pcur = (size_t*)malloc( sizeof(pos.pcur[0])*bufsize/2 );
    for( size_t i=0; i<bufsize/2; ++i )
        pos.pcur[i] = i;

    return true;
}
bool thenext( struct position& pos )
{
    for( size_t i=pos.bufsize/2; i>0; --i )
    {
        if( pos.pcur[i-1] != i-1+pos.bufsize/2 )
        {
            ++pos.pcur[i-1];
            for( size_t j=i; j<pos.bufsize/2; ++j )
                pos.pcur[j] = pos.pcur[j-1] + 1;
            return true;
        }
    }
    return false;
}
void theclose( struct position& pos )
{
    free( pos.pbuf );
    free( pos.pcur );
}
unsigned int different( struct position& pos, int buf2[] )
{
    bool* temp = (bool*)malloc( sizeof(temp[0])*pos.bufsize );

    for( size_t i=0; i<pos.bufsize; ++i )
        temp[i] = false;

    int sum1 = 0;
    for( size_t i=0; i<pos.bufsize/2; ++i )
    {
        buf2[i] = pos.pbuf[ pos.pcur[i] ];
        temp[ pos.pcur[i] ] = true;
        sum1 += buf2[i];
    }

    int sum2 = 0;
    int* p = &buf2[pos.bufsize/2];
    for( size_t i=0; i<pos.bufsize; ++i )
    {
        if( !temp[i] )
        {
            *p = pos.pbuf[i];
            ++p;
            sum2 += pos.pbuf[i];
        }
    }

    free( temp );

    return (sum1>=sum2) ? (sum1-sum2) : (sum2-sum1);
}

#include <stdio.h>
int main()
{
    int buf[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    //int buf[] = { 1, 3, 7, 2, 3, 4 };
    //int buf[] = { 11, 7, 6, 10, 9, 1 };

    struct position pos;
    unsigned int dif = -1;
    int buf2[ sizeof(buf)/sizeof(buf[0]) ];
    for( bool b=thefirst(pos,buf,sizeof(buf)/sizeof(buf[0])); b; b=thenext(pos) )
    {
        int buf2_temp[ sizeof(buf)/sizeof(buf[0]) ];
        unsigned int dif_temp = different( pos, buf2_temp );
        
        if( dif_temp < dif )
        {
            dif = dif_temp;
            for( size_t i=0; i<sizeof(buf)/sizeof(buf[0]); ++i )
                buf2[i] = buf2_temp[i];
        }
    }
    theclose( pos );

    for( size_t i=0; i<sizeof(buf)/sizeof(buf[0])/2; ++i )
        printf( "%d ", buf2[i] );
    printf( "\n" );
    for( size_t i=sizeof(buf)/sizeof(buf[0])/2; i<sizeof(buf)/sizeof(buf[0]); ++i )
        printf( "%d ", buf2[i] );
    printf( "\n --- %u ---\n", dif );

    return 0;
}

8 楼

补充:struct position 太复杂了,根本就不需要它的存在,应当如 std::next_permutation 一样

9 楼


好啰嗦的代码。。。。。。

10 楼

假设数据为 1 2 3 3 4 5
那么只有以下几种分法:
1 2 3 | 3 4 5
1 2 4 | 3 3 5
1 2 5 | 3 3 4
1 3 3 | 2 4 5
1 3 4 | 2 3 5
1 3 5 | 2 3 4
1 4 5 | 2 3 3
分别计算每一种分法的差值,取最小者。

#include <cassert>
#include <algorithm>

// 最差情况下(无重复数字),时间复杂度是O( n! / (n/2)! / (n/2)! / 2 )
// 假设n为6,则时间复杂度是O( (6*5*4)/(3*2*1)/2 ) = 10
bool nextpermutation( int buf[], size_t n )
{
    assert( n!=0 && n%2==0 );

    for( size_t i=n/2-1; i!=0; --i ) // 之所以不是 i!=-1,是因为第一个数放在A堆中和放在B堆中一样,因此假定放在A堆中,去掉一半的重复
    {
        int* p = std::upper_bound( buf+i+1, buf+n, buf[i] );
        if( p+(n/2-i) > buf+n )
        {
            std::sort( buf+i, buf+n );
            continue;
        }
        std::swap_ranges( p, p+(n/2-i), buf+i );
        if( i != n/2-1 )
            std::sort( buf+n/2, buf+n );
        return true;
    }
    return false;
}

#include <numeric>

int foo( int buf[], size_t n, int out[] )
{
    assert( n!=0 && n%2==0 );

    int sum = std::accumulate( buf+0, buf+n, 0 );
    std::sort( buf+0, buf+n );
    int diff = ::abs( 2*std::accumulate(buf+0,buf+n/2,0) - sum );
    std::copy( buf+0, buf+n, out );
    if( diff == 0 ) return 0;
    while( nextpermutation(buf,n) )
    {
        int diff2 = ::abs( 2*std::accumulate(buf+0,buf+n/2,0) - sum );
        if( diff2 < diff )
        {
            diff = diff2;
            std::copy( buf+0, buf+n, out );
            if( diff == 0 ) return 0;
        }
    }

    return diff;
}


#include <iostream>
#include <iterator>
using namespace std;

//void test( int buf[], size_t n )
//{
//    assert( n!=0 && n%2==0 );
//
//    std::ostream_iterator<int> oitor( std::cout, " " );
//    std::sort( buf+0, buf+n );
//    std::copy( buf+0, buf+n/2, oitor ); std::cout << ", ";
//    std::copy( buf+n/2, buf+n, oitor ); std::cout << '\n';
//    while( nextpermutation(buf,n) )
//    {
//        std::copy( buf+0, buf+n/2, oitor ); std::cout << ", ";
//        std::copy( buf+n/2, buf+n, oitor ); std::cout << '\n';
//    }
//    cout << flush;
//}

int main()
{
    // input
    int buf[] = { 1, 2, 3, 3, 4, 5 };
    //int buf[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    //int buf[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    //int buf[] = { 1, 3, 7, 2, 3, 4 };
    //int buf[] = { 11, 7, 6, 10, 9, 1 };

    // pre deal
    const size_t n = sizeof(buf)/sizeof(buf[0]);

    // test
    //test( buf, n );

    // foo
    int out[n];
    int diff = foo( buf, n, out );

    // output
    ostream_iterator<int> oitor( cout, " " );
    cout << '\n';
    cout << "A: "; std::copy( out+0, out+n/2, oitor ); cout << '\n';
    cout << "B: "; std::copy( out+n/2, out+n, oitor ); cout << '\n';
    cout << "different = " << diff << endl;

    return 0;
}

我来回复

您尚未登录,请登录后再回复。点此登录或注册