算法--06年华为面试:求两个数组的最小差值(Java实现)
2017-06-12 17:21
645 查看
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
相关文章推荐
- 【LeetCode-面试算法经典-Java实现】【153-Find Minimum in Rotated Sorted Array(找旋转数组中的最小数字)】
- 【LeetCode-面试算法经典-Java实现】【154-Find Minimum in Rotated Sorted Array II(找旋转数组中的最小数字II)】
- 【LeetCode-面试算法经典-Java实现】【004-Median of Two Sorted Arrays(两个排序数组的中位数)】
- 【LeetCode-面试算法经典-Java实现】【064-Minimum Path Sum(最小路径和)】
- 【LeetCode-面试算法经典-Java实现】【215-Kth Largest Element in an Array(数组中第K大的数)】
- 【LeetCode-面试算法经典-Java实现】【088-Merge Sorted Array(合并排序数组)】
- 【LeetCode-面试算法经典-Java实现】【152-Maximum Product Subarray(子数组的最大乘积)】
- 【LeetCode-面试算法经典-Java实现】【029-Divide Two Integers(两个整数相除)】
- 面试常考算法题 局部最小 求二叉树结点 求两个数组中所有数的上中位数 两个数组的所有数中第K小的数
- 用两个栈实现队列、旋转数组的最小数、斐波那契数列、青蛙跳台阶、矩形覆盖 --漫漫算法路 刷题篇
- 【LeetCode-面试算法经典-Java实现】【064-Minimum Path Sum(最小路径和)】
- 【LeetCode-面试算法经典-Java实现】【081-Search in Rotated Sorted Array II(搜索旋转的排序数组)】
- 【LeetCode-面试算法经典-Java实现】【189-Rotate Array(旋转数组)】
- 【LeetCode-面试算法经典-Java实现】【053-Maximum Subarray(最大子数组和)】
- 【LeetCode-面试算法经典-Java实现】【155-Min Stack(最小栈)】
- 【LeetCode-面试算法经典-Java实现】【021-Merge Two Sorted Lists(合并两个排好序的单链表)】
- 【LeetCode-面试算法经典-Java实现】【111-Minimum Depth of Binary Tree(二叉树的最小深度)】
- java 随机长度10位数组,输入两个数字,找出差值最小的
- java实现数组逆序的算法 使用函数两个参数
- 【LeetCode-面试算法经典-Java实现】【111-Minimum Depth of Binary Tree(二叉树的最小深度)】