这个题目是在网上看到了,题目描述如下:有两个数组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 }