数组的均值分割【LC805】
给定你一个整数数组
nums我们要将
nums数组中的每个元素移动到A数组 或者B数组中,使得A数组和B数组不为空,并且average(A) == average(B)。如果可以完成则返回
true, 否则返回false。**注意:**对于数组
arr,average(arr)是arr的所有元素除以arr长度的和。
You are given an integer array
nums.You should move each element of
numsinto one of the two arraysAandBsuch thatAandBare non-empty, andaverage(A) == average(B).Return
trueif it is possible to achieve that andfalseotherwise.Note that for an array
arr,average(arr)is the sum of all the elements ofarrover the length ofarr.
做了好久做出来了,很有很有成就感
- 思路:转化为01背包问题
-
当能够分成两个等均值的数组时,均值为固定值,即为数组nums的均值AVE,推导如下,nA和nB分别代表数组A和数组B的长度,sum为数组nums的和,a=average(A) = average(B)
- nA * a + nB * a = sum
- a = sum/(nA+nB)=AVE
-
因此如果能够找到任意n个数的和为均值AVE的n倍时,即可分割成两个等均值的数组
-
每个元素只有取或者不取两种可能性,因此可以转化为01背包问题
-
- 01背包问题实现
- 背包的体积为sum
- 背包要放入的商品(集合里的元素)重量为元素的个数(每个元素为1),价值为 元素的数值
- 背包中每一个元素是不可重复放入。
- 要求:找到一个背包的容量为nA,存满时其存在价值大小为AVE*nA,sumA = sum/n * nA
- 因为存在浮点数,所以将等式改为sumA * n = sum * nA
二维动态规划
-
确定dp数组(dp table)以及下标的含义
dp[i][j]表示 表示是否能从 nums 中选 i个数使它们的和为 j
背包总容量为j时,能否装满背包所需的元素个数为i。
-
确定递推公式
-
放元素nums[k]
当当前遍历元素为nums[k]时,如果dp[-1][j] = true,那么dp[i] [j+nums[k]]= true
-
不放元素nums[k]:dp[i][j] = dp[i][j]
-
-
dp数组如何初始化
dp[0][0] = true; -
确定遍历顺序
按顺序遍历每个物品,先逆序遍历背包容量i【避免重复放入同一个物品】,再正序遍历背包价值j
-
举例推导dp数组
-
代码
class Solution { public boolean splitArraySameAverage(int[] nums) { int len = nums.length; if (len <= 1){ return false; } int sum = 0; for (int i = 0; i < len; i++){ sum += nums[i]; } boolean[][] dp = new boolean[len + 1][sum + 1]; dp[0][0] = true; for (int k = 0; k < len ; k++){ for (int i = k + 1; i >= 1; i--){ for (int j = 0; j <= sum; j++){ if (dp[i-1][j] && j + nums[k] <= sum){ dp[i][j+nums[k]] = true; if ( i != 0 && i != len && (j + nums[k]) * len == sum * i){ return true; } } } } } return false; } }-
复杂度
- 时间复杂度:O(n2∗sum)O(n^2*sum)O(n2∗sum),n为数组长度,sum为数组和
- 空间复杂度:O(n∗sum)O(n*sum)O(n∗sum),dp数组大小
-
-
将二维数组转换为HashSet数组,set[n]代表当选取n个元素时,和可能的值
class Solution { public boolean splitArraySameAverage(int[] nums) { int len = nums.length; if (len <= 1){ return false; } int sum = 0; for (int i = 0; i < len; i++){ sum += nums[i]; } Set<Integer>[] dp = new Set[len + 1]; for (int i = 0; i <= len; i++) { dp[i] = new HashSet<Integer>(); } dp[0].add(0); for (int k = 0; k < len ; k++){ for (int i = k + 1; i >= 1; i--){ for (int x : dp[i-1]){ int curSum = x + nums[k]; if (i != 0 && i != len && curSum * len == sum * i){ return true; } dp[i].add(curSum); } } } return false; } }

该博客介绍了一种将整数数组分成两个均值相等子数组的方法,通过转化成01背包问题来解决。作者首先计算数组的平均值,并建立二维动态规划数组,通过遍历元素和背包容量来确定是否能形成两个均值相同的子数组。此外,还提供了一种使用HashSet优化的空间效率更高的解决方案。博客探讨了时间复杂度和空间复杂度,并展示了完整的Java代码实现。

被折叠的 条评论
为什么被折叠?



