算法--06年华为面试:求两个数组的最小差值(Java实现)
Q題目
華為06年面試題(要求8分鐘完成)
有兩個數組a,b,大小都為n,數組元素的值任意,無序; 要求:通過交換a,b中的元素,使數組a元素的和與數組b元素的和之間的差最小。A解法
1.常見錯誤邏輯
錯誤邏輯一:將兩個數組合并為一個數組,進行排序,將前面n個小的作為數組a,后面n作為數組b,a減b得到值,即為最小值。【該思路對題意理解有誤,這里求最小差值,指的是絕對值】
錯誤邏輯二:同樣是將兩個數組合并,然后排序,此時采用交錯的取法,分配給兩個數組a和b,比如1,2,3,4,將1和3分給a,2和4非配給b【明顯是錯誤的】。還有人采用更加嚴謹一些的方法,就是沒次交錯給兩個數組非配值前,比較一下兩個數組和的大小,給小的分配大值,此時1,2,3,4的分配結果是- - a數組為:1 , 4 - - b數組為:2 , 3 。貌似是正確的,但假如最大數非常大,大到比剩余所有數字的總和還大呢?此時應該是將前面(n-1)個最小值與最大值組合在一起。
2.最小差值算法
2.1邏輯分析
大概邏輯:將數組a的每一個數依次去與數組b中的每個數,進行交換,每次交換完成后分別計算兩個數組的差值(minus),如果差值變大則,不交換,差值變小則交換。此時時間復雜度為O(n!)
詳細分析:
1)數組a的第一個數與數組b第一個數進行交換,交換后兩數組差值變小,則不做改變了,若變大了,則重新交換回來
2)在上一步基礎上,再用數組a的第一個數(可能是a[0],也可能交換后的b[0])去與數組b的第二個數進行交換,差值變小,則不作改變,變大,則重新換回來,依次進行比較
3)數組a的第一個數與數組b中的所有數進行交換處理后,采用同樣的方法,再用數組a的第二個數與數組b中的所有數依次進行交換,在比較差值來處理
缺點:計算量大,有許多重復的計算
2.2實現代碼如下
package 華為面試兩數組最小差值;import java.util.Arrays;public class Test2 {public static void main(String[] args) {//1.測試數組a和b // int a[] = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 989 }; // int b[] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 };int a[] = { 1, 3, 5 ,49};int b[] = { 0, 2, 4 ,18};//2.調用處理數組的函數getMinusArray(a, b);//3.打印處理實現最小差值的數組a和b--a和b各自的和--System.out.println("交換處理后的數組a:"+Arrays.toString(a));System.out.println("交換處理后的數組b:"+Arrays.toString(b));System.out.println("getSum(a)="+getSum(a));System.out.println("getSum(b)="+getSum(b));System.out.println("交換后a和b的差值:getSum(a)-getSum(b)="+Math.abs(getSum(a)-getSum(b)));}//兩數組進行元素交換實現最小差值public static void getMinusArray(int[] a, int[] b) {// 數組a和b的和int suma = getSum(a);int sumb = getSum(b);int startMinus = Math.abs(suma - sumb); // System.out.println("startMinus="+startMinus);int minus = 0;for(int i = 0; i < a.length; i++){for(int j = 0; j < a.length; j++) {//先交換int temp=a[i];a[i]=b[j];b[j]=temp;//交換后的差值minus = Math.abs(getSum(a) - getSum(b));if(minus<startMinus){startMinus = minus;}else{//若交換后,差值比原來大或相等,則不交換--即重新換回來int temp2=a[i];a[i]=b[j];b[j]=temp2;}}}}// 求數組和public static int getSum(int[] arr) {int sum = 0;for (int i : arr) {sum += i;}return sum;} }運行結果:
3.背包算法
筆者對背包算法不出很清楚
以下粘貼了一部分有關的背包算法的邏輯分析,僅供參考
舉個例子,有1,2,3一共3個數,將這三個數分成兩部分,有3種分法1 | 2,3或者1,2| 3 或者1,3|2,然后計算每部分所有數的和,
1 | 2,3 -> 和為1,5,和的差是4
1 2| 3 -> 和為3,3,和的差是0
1 3|2 -> 和為4,2,和的差是2
所以按照1,2| 3分得到的和的差最小。
那么任意給定一個數組,如何找出最小值呢?
思路:差最小就是說兩部分的和最接近,或者說與所有數的和SUM的一半最接近的。
假設用sum1表示第一部分的和,sum2表示第二部分的和,SUM表示所有數的和,那么sum1+sum2=SUM。
假設sum1<sum2 那么SUM/2-sum1 = sum2-SUM/2;所以我們就有目標了,使得sum1<=SUM/2的條件下盡可能的大。
也就是說從n個數中選出某些數,使得這些數的和盡可能的接近或者等于所有數的和的一半。
這其實就是簡單的背包問題了:
背包容量是SUM/2,每個物體的體積是數的大小,然后盡可能的裝滿背包。
dp方程:f[i][V] = max(f[i-1][V-v[i]]+v[i], f[i-1][V] ) 說明:f[i][V]表示用前i個物體裝容量為V的背包能夠裝下的最大值,f[i-1][V-v[i]]+v[i]表示第i個物體裝進背包的情況,f[i-1][V]表示第i件物品不裝進背包的情況。按照dp方程不難寫出代碼:
初始值:f[0][k]=0,f[i][0]=0;偽代碼
for(i=0;i<n;i++){ for(j=1;j<SUM/2;j++){ f[i][j]=f[i-1][j];if(v[i]<=j && f[i-1][j-v[i]]+v[i]>f[i][j]){ f[i][j]=value[i-1][j-v[i]]+v[i]; } }} 最終差值就是SUM-2*f[n-1][SUM/2];可參考百度百科:背包算法–http://baike.baidu.com/link?url=f2rLJADvttP0UvcubvHofIGVAcvdl6MV4eQH17fKYeCOLQTECBLsvOIVFKid_OnC1ybaElqARhPqCJjoU-5rqO1D5sKT5OOiEbbNB1EcEeFBYpLzhgYXpjDN2PlWxaU1
總結
以上是生活随笔為你收集整理的算法--06年华为面试:求两个数组的最小差值(Java实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 向MySQL数据库中插入数据,sql语句
- 下一篇: 算法--生成m个指定范围的不重复随机数的