Ebay 面试题 | 把数组分成和大小一样的集合

Posted jiuzhangsuanfa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ebay 面试题 | 把数组分成和大小一样的集合相关的知识,希望对你有一定的参考价值。

题目描述 cs3k.com

给定一个只包含正整数的非空数组,判断该数组能否分成两个和相等的子数组。

样例输入 cs3k.com

输入[1,5,11,5] 返回 true . 可以分为[1,5,5]和[11]
输入[1,2,3,5]    返回false. 无法分为相等的两个子数组

算法分析

本题需要判断数组能否分为两个和想等的子数组,等价于在数组中选取一定数目的元素,能否使得选择的元素之和为sum/2(sum为数组中所有元素的和)。而等价的问题就是经典的0-1背包问题,即给定一个正整数数组,能否从数组中选取一定数量的元素,使得这些元素的和恰好为sum/2。

为了解决这个问题,直观的想法是我们可以枚举原数组的所有子集,计算每个子集的元素之和能否等于sum/2,但是含有n个元素的数组的子集数目为2^n个,这样算法的复杂度是指数级别的,在n比较大的时候并不可行。

我们假设数组中存在子集num1,num2,...,numk满足和为sum/2,那么,从该子集中去掉最后一个元素numk,其和一定为sum/2-numk。也就是说子问题:是否存在一个子集,其和为sum/2-numk,该问题一定是有解的(可以用反证法证明)。

这样,我们可以确定,原问题有解当且仅当子问题有解。这样,我们就把一个规模比较大的问题归结成了规模比较小的子问题。这就是动态规划的思想。那么,我们如何确定子问题是否有解呢?可以这样考虑,假设dp[i][j]表示数组中前i个元素能否得到和为j的子数组,dp[i][j] = 1表示前i个元素能够得到和为j的子数组,dp[i][j] = 0 表示不能得到。那么对于第i个元素来说,有两种情况,一种是第i个元素在和为j的子数组中,那么对于前i-1个元素来讲,应该得到和为j-nums[i]的子数组;另一种情况是第i个元素不在和为j的子数组中,那么对于前i-1个元素来讲,应该得到和为j的子数组。上述两种情况成立其一就可以保证能够得到合法解。因此我们有以下关系:

 dp[i][j] = dp[i-1][j] | dp[i-1]][j-nums[i]]

上述解法的时间复杂度和空间复杂度均为O(n*sum)的,由于问题中,n*sum = 200 * 100  * 200 = 4*10^6,我们x需要优化空间复杂度。进一步思考我们发现,第i次迭代的过程只与第i-1次迭代过程有关系,而与前i-2次迭代过程无关。因此我我们首先可以考虑使用2×sum的滚动数组来解决此题。此时可以把空间复杂度压缩到O(sum)。

另一种解法是一维动态规划,我们假设dp[j]表示第i轮迭代能否得到和为j的子数组,那么只要保证此时数组中存储的是上一轮(i-1轮)迭代的结果,我们就可以去掉一个维度。因此我们有如下关系: 

dp[j] = dp[j] | dp[j - nums[i]]

但是这种情况下,内层循环必须从大往小循环(请读者思考为什么)。
下面给出O(sum)空间复杂度的一维动态规划解法。

参考代码

技术分享图片

 

面试官角度分析

本题是动态规划的经典问题0-1背包的简单变形,给出动态规划算法可以达到hire的程度。

cs3k.com



以上是关于Ebay 面试题 | 把数组分成和大小一样的集合的主要内容,如果未能解决你的问题,请参考以下文章

Java集合详解12:arraylist和linkedlist面试题汇总,可能没有你想象中那么简单!

百度面试——算法岗

(转)40个Java集合面试问题和答案

Android 开发高级面试题集合—— Binder 篇 <二>

面试题Java常见面试题

JAVA集合面试问题