码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2018-11-02 14:38:20      阅读:377      评论:0      收藏:0      [点我收藏+]

标签:代码   情况下   问题   com   问题:   必须   http   进一步   目的   

题目描述 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 面试题 | 把数组分成和大小一样的集合

标签:代码   情况下   问题   com   问题:   必须   http   进一步   目的   

原文地址:https://www.cnblogs.com/jiuzhangsuanfa/p/9895705.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!