这个题目是在网上看到了,题目描述如下:有两个数组a,b,大小都为n,数组元素的值任意,无序。要求:通过交换a,b中的元素,使数组a元素的和与数组b元素的和之间的差最小。不知道是否真的出自华为,但题目难度很大,以我的水平8分钟确实无法写出完整的代码,查阅网上的牛人的思路,理解整理如下:
- 对两个数字值进行累加,设差值 A = sum(a) - sum(b)
- a的第i个元素和b的第j个元素交换后,a和b的和之差为:A' = sum(a) - a[i] + b[j] - (sum(b) - b[j] + a[i]) = sum(a) - sum(b) - 2 (a[i] - b[j]) = A - 2 (a[i] - b[j])
- 设x = a[i] - b[j],带入上式得,|A| - |A'| = |A| - |A-2x|
- 假设A > 0,当x 在 (0,A)之间时,做这样的交换才能使得交换后的a和b的和之差变小,x越接近A/2效果越好,如果找不到在(0,A)之间的x,则当前的a和b就是答案。
算法描述为:将a、b两个数组看出天平两端,各自寻找使得x在(0,A)之间并且最接近A/2的i和j,交换相应的i和j元素,重新计算A后,重复前面的步骤直至找不到(0,A)之间的x为止。根据算法描述实现代码:
1 int SwapArray(int *a, int *b, int n)
2 {
3 int nSumA=0, nSumB=0; //分别记录两个数组的和
4 int nSumDiff=0, nNumDiff=0; //nSumDiff表示每轮数组和的差值,nNumDiff表示每轮数组各选两数之差
5
6 float dHalfDiffSum=0.0f, dClose2SumDiff=0.0f; //dHalfDiffSum表示nSumDiff/2, dClose2SumDiff表示每轮最接近dHalfDiffSum的数
7
8 int nIndexI=0, nIndexJ=0;
9 bool bDesc=false, bSwitch=false; //bDesc为true表示 nSumA > nSumB,bSiwtch为true表示 nNumDiff < nSumDiff,此轮无需交换
10
11 int i=0, j=0;
12 while(1)
13 {
14 for(i=0; i!=n; i++)
15 {
16 nSumA += a[i];
17 nSumB += b[i];
18 }
19 nSumDiff = nSumA - nSumB;
20 dHalfDiffSum = (float)nSumDiff/2;
21 dClose2SumDiff = dHalfDiffSum;
22 bDesc = nSumA >= nSumB? true : false;
23 if(bDesc)
24 {
25 for(i=0; i!=n; i++)
26 for(j=0; j!=n; j++)
27 {
28 nNumDiff = a[i]-b[j];
29 cout<<__LINE__<<" nSumDiff = "<<nSumDiff<<" dHalfDiffSum = "<<dHalfDiffSum<<" "<<"dClose2SumDiff = "<<dClose2SumDiff<<" "<<"nNumDiff = "<<nNumDiff<<endl;
30 //当在SumA>SumB时,考虑满足交换的条件:1. a[i]<b[j]此时交换只会使SumA更大于SumB,使得SumA-SumB>nSumDiff 2. a[i]-b[j]>SumA-Sumb此时交换同样使得|SumA-SumB|>nSumDiff,这两者条件下都会使两个数组差值越来越大,故需要进行如下过滤
31 if(nNumDiff > 0 && nNumDiff < nSumDiff)
32 {
33 if(nNumDiff >= dHalfDiffSum)
34 {
35 if(nNumDiff - dHalfDiffSum < dClose2SumDiff)
36 {
37 bSwitch = true;
38 dClose2SumDiff = nNumDiff- dHalfDiffSum;
39 nIndexI = i;
40 nIndexJ = j;
41 cout<<__LINE__<<" nIndexI = "<<nIndexI<<" nIndexJ = "<<nIndexJ<<" dClose2SumDiff = "<<dClose2SumDiff<<endl;
42 }
43 }
44 else
45 {
46 if(dHalfDiffSum - nNumDiff < dClose2SumDiff)
47 {
48 bSwitch = true;
49 dClose2SumDiff = dHalfDiffSum - nNumDiff;
50 nIndexI = i;
51 nIndexJ = j;
52 cout<<__LINE__<<" nIndexI = "<<nIndexI<<" nIndexJ = "<<nIndexJ<<" dClose2SumDiff = "<<dClose2SumDiff<<endl;
53 }
54 }
55 }
56 }
57 }
58 else
59 {
60 for(i=0; i!=n; i++)
61 for(j=0; j!=n; j++)
62 {
63 nNumDiff = a[i]-b[j];
64 cout<<__LINE__<<" nSumDiff = "<<nSumDiff<<" dHalfDiffSum = "<<dHalfDiffSum<<" "<<"dClose2SumDiff = "<<dClose2SumDiff<<" "<<"nNumDiff = "<<nNumDiff<<endl;
65 if(nNumDiff < 0 && nNumDiff < nSumDiff)
66 {
67 if(nNumDiff > dHalfDiffSum)
68 {
69 if(nNumDiff - dHalfDiffSum < dClose2SumDiff)
70 {
71 bSwitch = true;
72 dClose2SumDiff = nNumDiff-dHalfDiffSum;
73 nIndexI = i;
74 nIndexJ = j;
75 cout<<__LINE__<<" nIndexI = "<<nIndexI<<" nIndexJ = "<<nIndexJ<<" dClose2SumDiff = "<<dClose2SumDiff<<endl;
76 }
77 }
78 else
79 {
80 if(dHalfDiffSum - nNumDiff < dClose2SumDiff)
81 {
82 bSwitch = true;
83 dClose2SumDiff = dHalfDiffSum-nNumDiff;
84 nIndexI = i;
85 nIndexJ = j;
86 cout<<__LINE__<<" nIndexI = "<<nIndexI<<" nIndexJ = "<<nIndexJ<<" dClose2SumDiff = "<<dClose2SumDiff<<endl;
87 }
88 }
89 }
90 }
91 }
92
93 if(!bSwitch)
94 break;
95
96 swap(a[nIndexI], b[nIndexJ]);
97
98 for(i=0; i!=n; i++)
99 cout<<a[i]<<" ";
100 cout<<endl;
101
102 for(i=0; i!=n; i++)
103 cout<<b[i]<<" ";
104 cout<<endl;
105
106 nSumA = nSumB =0;
107 bDesc = bSwitch = false;
108 }
109
110 return 0;
111 }
112
113 int _tmain(int argc, _TCHAR* argv[])
114 {
115 int a[] = {5, 10,22};
116 int b[] = {1, 4, 3};
117
118 SwapArray(a, b, 3);
119
120 return 0;
121 }