主题:“华为面试题!8分钟做出来”,我做的思路,大家帮看一下对不对,谢谢哈~!
qingeng_1052
[专家分:0] 发布于 2009-01-15 02:13:00
原题:有两个数组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个回复)
沙发
zhuker [专家分:0] 发布于 2009-01-15 17:07:00
我的算法和你不太一样:
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;
}
板凳
bruceteen [专家分:42660] 发布于 2009-01-15 18:24:00
[quote]a先取最小的,b先取次小的[/quote]
肯定不对,比如
1 2 7
3 3 4
你的结果就是
1 3 7
2 3 4
3 楼
dannyliu [专家分:350] 发布于 2009-01-16 00:25:00
群里一个朋友写的
#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 楼
叫阿son [专家分:150] 发布于 2009-01-17 17:34:00
将所有数存在另一个缓存,清空两个数组,从中取最大的,随意放进一个数组,记录它的sum值,再取次大的,判断哪个数组的sum最小,就把次大数存入,以此类推
5 楼
bruceteen [专家分:42660] 发布于 2009-01-19 17:37:00
[quote]从中取最大的,随意放进一个数组,记录它的sum值,再取次大的,判断哪个数组的sum最小,就把次大数存入,以此类推[/quote]
明显不靠谱,比如
11, 10, 01
09, 07, 06
按你的方法就成了
11, 07, 06
10, 09, 01
6 楼
bruceteen [专家分:42660] 发布于 2009-01-19 17:49:00
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 楼
bruceteen [专家分:42660] 发布于 2009-01-19 19:03:00
下班后随便写了一个,还没优化,回家
#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 楼
bruceteen [专家分:42660] 发布于 2009-01-20 08:56:00
补充:struct position 太复杂了,根本就不需要它的存在,应当如 std::next_permutation 一样
9 楼
woshiyun [专家分:300] 发布于 2009-01-20 16:34:00
好啰嗦的代码。。。。。。
10 楼
bruceteen [专家分:42660] 发布于 2009-01-20 17:59:00
假设数据为 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;
}
我来回复