In a given integer array A, we must move every element of A to either list B or list C. (B and C initially start empty.)

Return true if and only if after such a move, it is possible that the average value of B is equal to the average value of C, and B and C are both non-empty.

Example :
Input:
[1,2,3,4,5,6,7,8]
Output: true
Explanation: We can split the array into [1,4,5,8] and [2,3,6,7], and both of them have the average of 4.5.

Note:

  • The length of A will be in the range [1, 30].
  • A[i] will be in the range of [0, 10000].

给一个数组A,把A中的每一个元素都移到数组B或C中(B, C初始为空)。如果移动后可以使B和C的均值相等,则返回ture。其实就是将一个数组分成两部分,每部分的平均值相同。

题目的关键点是:当能拆分成两个平均值相等的数组时,拆分的数组和原来数组的平均值是相同的。因此问题转换为,先算出A的平均值A_aver,如果A中的数组成的子数组B的平均值等于A_aver,再去判断剩余的数组成的数组C的平均值是否和A_aver相等。

The key thing of this problem is, when we are able to make a same average split, the average of each splitted array is the same as the average of the whole array.
So the problem can be transformed into a simpler one: given a target number (tosum), can we construct it using a specific number (lenB) of integers in a list(A).
Then we can try every possible numbers of lenB, to see whether any one is feasible.

If the array of size n can be splitted into group A and B with same mean, assuming A is the smaller group, then

totalSum/n = Asum/k = Bsum/(n-k), where k = A.size() and 1 <= k <= n/2;
Asum = totalSum*k/n, which is an integer. So we have totalSum*k%n == 0;

如果一个长度为n的数组可以被划分为A和B两个数组,假设A的长度小于B并且A的大小是k,那么:total_sum / n == A_sum / k == B_sum / (n - k),其中1 <= k <= n / 2。可得出:A_sum = total_sum * k / n。由于A_sum一定是个整数,所以可以推导出total_sum * k % n == 0,那就是说,对于特定的total_sum和n而言,符合条件的k不会太多。首先验证是否存在符合条件的k,如果不存在就可以提前返回false。

解法1: early pruning + knapsack DP, O(n^3 * M)

如果经过第一步的验证,发现确实有符合条件的k,那么我们在第二步中,就试图产生k个子元素的所有组合,并且计算他们的和。这里的思路就有点类似于背包问题了,我们的做法是:定义vector<vector<unordered_set<int>>> sums,其中sums[i][j]表示A[0, i]这个子数组中的任意j个元素的所有可能和。可以得到递推公式是:sums[i][j] = sums[i - 1][j] "join" (sums[i][j - 1] + A[i]),其中等式右边的第一项表示这j个元素中不包含A[i],而第二项表示这j个元素包含A[i]。这样就可以采用动态规划的思路得到sums[n - 1][k]了(1 <= k <= n / 2)。

有了sums[n - 1][k],我们就检查sums[n - 1][k]中是否包含(total_sum * k / n)。一旦发现符合条件的k,就返回true,否则就返回false。

If there are still some k valid after early pruning by checking totalSum*k%n == 0,
we can generate all possible combination sum of k numbers from the array using DP, like knapsack problem. (Note: 1 <= k <= n/2)
Next, for each valid k, simply check whether the group sum, i.e. totalSum * k / n, exists in the kth combination sum hashset.

vector<vector<unordered_set<int>>> sums(n, vector<unordered_set<int>>(n/2+1));
sums[i][j] is all possible combination sum of j numbers from the subarray A[0, i];
Goal: sums[n-1][k], for all k in range [1, n/2]
Initial condition: sums[i][0] = {0}, 0 <= i <= n-1; sums[0][1] = {all numbers in the array};
Deduction: sums[i+1][j] = sums[i][j] "join" (sums[i][j-1] + A[i+1])
The following code uses less space but the same DP formula.
Runtime analysis:
All numbers in the array are in range [0, 10000]. Let M = 10000.
So the size of kth combination sum hashset, i.e. sums[...][k], is <= k * M;
For each number in the array, the code need loop through all combination sum hashsets, so
the total runtime is n * (1 * M + 2 * M + ... + (n/2) * M) = O(n^3 * M)

解法2: TLE, For such k, the problem transforms to "Find k sum = Asum, i.e. totalSum * k/n, from an array of size n". This subproblem is similar to LC39combination sum, which can be solved by backtracking.

Python:

class Solution(object):
def splitArraySameAverage(self, A):
if len(A)==1: return False
global_avg = sum(A)/float(len(A))
for lenB in range(1, len(A)/2+1):
if int(lenB*global_avg) == lenB*global_avg:
if self.exist(lenB*global_avg, lenB, A):
return True
return False def exist(self, tosum, item_count, arr):
if item_count==0:
return False if tosum else True
if item_count > len(arr) or not arr:
return False
if any([self.exist(tosum-arr[0], item_count-1, arr[1:]),
self.exist(tosum, item_count, arr[1:])]):
return True
return False 

Python:

# Time:  O(n^4)
# Space: O(n^3)
class Solution(object):
def splitArraySameAverage(self, A):
"""
:type A: List[int]
:rtype: bool
"""
def possible(total, n):
for i in xrange(1, n//2+1):
if total*i%n == 0:
return True
return False
n, s = len(A), sum(A)
if not possible(n, s):
return False sums = [set() for _ in xrange(n//2+1)];
sums[0].add(0)
for num in A: # O(n) times
for i in reversed(xrange(1, n//2+1)): # O(n) times
for prev in sums[i-1]: # O(1) + O(2) + ... O(n/2) = O(n^2) times
sums[i].add(prev+num)
for i in xrange(1, n//2+1):
if s*i%n == 0 and s*i//n in sums[i]:
return True
return False  

C++: 1

class Solution {
public:
bool splitArraySameAverage(vector<int>& A) {
int n = A.size(), m = n/2, totalSum = accumulate(A.begin(), A.end(), 0);
// early pruning
bool isPossible = false;
for (int i = 1; i <= m && !isPossible; ++i)
if (totalSum*i%n == 0) isPossible = true;
if (!isPossible) return false;
// DP like knapsack
vector<unordered_set<int>> sums(m+1);
sums[0].insert(0);
for (int num: A) {
for (int i = m; i >= 1; --i)
for (const int t: sums[i-1])
sums[i].insert(t + num);
}
for (int i = 1; i <= m; ++i)
if (totalSum*i%n == 0 && sums[i].find(totalSum*i/n) != sums[i].end()) return true;
return false;
}
};  

C++: 1

class Solution {
public:
bool splitArraySameAverage(vector<int>& A) {
int n = A.size(), m = n / 2;
int totalSum = accumulate(A.begin(), A.end(), 0);
// early pruning
bool isPossible = false;
for (int i = 1; i <= m; ++i) {
if (totalSum * i % n == 0) {
isPossible = true;
break;
}
}
if (!isPossible) {
return false;
}
// DP like knapsack
vector<unordered_set<int>> sums(m + 1);
sums[0].insert(0);
for (int num: A) { // for each element in A, we try to add it to sums[i] by joining sums[i - 1]
for (int i = m; i >= 1; --i) {
for (const int t: sums[i - 1]) {
sums[i].insert(t + num);
}
}
}
for (int i = 1; i <= m; ++i) {
if (totalSum * i % n == 0 && sums[i].find(totalSum * i / n) != sums[i].end()) {
return true;
}
}
return false;
}
};  

C++: 2 TLE

class Solution {
public:
bool splitArraySameAverage(vector<int>& A) {
int n = A.size(), m = n/2, totalSum = accumulate(A.begin(), A.end(), 0);
sort(A.rbegin(), A.rend()); // Optimization
for (int i = 1; i <= m; ++i)
if (totalSum*i%n == 0 && combinationSum(A, 0, i, totalSum*i/n)) return true;
return false;
}
bool combinationSum(vector<int>& nums, int idx, int k, int tar) {
if (tar > k * nums[idx]) return false; // Optimization, A is sorted from large to small
if (k == 0) return tar == 0;
for (int i = idx; i <= nums.size()-k; ++i)
if (nums[i] <= tar && combinationSum(nums, i+1, k-1, tar-nums[i])) return true;
return false;
}
};

  

All LeetCode Questions List 题目汇总

[LeetCode] 805. Split Array With Same Average 用相同均值拆分数组的更多相关文章

  1. 805. Split Array With Same Average

    In a given integer array A, we must move every element of A to either list B or list C. (B and C ini ...

  2. [LeetCode] Split Array With Same Average 分割数组成相同平均值的小数组

    In a given integer array A, we must move every element of A to either list B or list C. (B and C ini ...

  3. [Swift]LeetCode805. 数组的均值分割 | Split Array With Same Average

    In a given integer array A, we must move every element of A to either list B or list C. (B and C ini ...

  4. [LeetCode] 659. Split Array into Consecutive Subsequences 将数组分割成连续子序列

    You are given an integer array sorted in ascending order (may contain duplicates), you need to split ...

  5. [LeetCode] 410. Split Array Largest Sum 分割数组的最大值

    Given an array which consists of non-negative integers and an integer m, you can split the array int ...

  6. [LeetCode] 548. Split Array with Equal Sum 分割数组成和相同的子数组

    Given an array with n integers, you need to find if there are triplets (i, j, k) which satisfies fol ...

  7. LeetCode 548. Split Array with Equal Sum (分割数组使得子数组的和都相同)$

    Given an array with n integers, you need to find if there are triplets (i, j, k) which satisfies fol ...

  8. leetcode 659. Split Array into Consecutive Subsequences

    You are given an integer array sorted in ascending order (may contain duplicates), you need to split ...

  9. LeetCode 842. Split Array into Fibonacci Sequence

    原题链接在这里:https://leetcode.com/problems/split-array-into-fibonacci-sequence/ 题目: Given a string S of d ...

随机推荐

  1. POI不同浏览器导出名称处理

    /** * * @Title: encodeFileName * @Description: 导出文件转换文件名称编码 * @param @param fileNames * @param @para ...

  2. Linux端口转发工具rinetd

    介绍:Rinetd是为在一个Unix和Linux操作系统中为重定向传输控制协议(TCP)连接的一个工具.Rinetd是单一过程的服务器,它处理任何数量的连接到在配置文件etc/rinetd中指定的地址 ...

  3. js遍历localStorage的键值对

    //遍历本地存储localStorage for (var i = 0; i < localStorage.length; i++) { var key = localStorage.key(i ...

  4. WinDbg常用命令系列---!address

    !address 这个!address扩展命令显示有关目标进程或目标计算机使用的内存的信息. 用户模式: !address Address !address -summary !address [-f ...

  5. 纯js制作九宫格

    Demo实现了对任意方格进行拖拽,可以交换位置,其中Demo-1利用了勾股定理判断距离! Demo-1整体思路: 1.首先div实现自由移动,一定需要脱离标准文档流,所以我们给它使用绝对定位. 2.利 ...

  6. 4、spark streaming+kafka

    一.Receiver模式 1. receiver模式原理图 在SparkStreaming程序运行起来后,Executor中会有receiver tasks接收kafka推送过来的数据.数据会被持久化 ...

  7. CSS Variables:css自定义属性的使用

    CSS Variables,一个并不是那么新的东西,但对css来说绝对是一场革命.之前使用变量的时候,需要借助sass.less等预处理工具来实现,现在我们可以直接使用css来声明变量. 一.兼容性 ...

  8. 洛谷P1076 寻宝

    寻宝 模拟加优化,细节比较重要. 我们用ti[i]表示i这一层有楼梯的个数,然后我们把当前1号点的数据mod上ti[i],然后使该数不能等于0,就行了. #include <bits/stdc+ ...

  9. Ubuntu 安装MySQL报共享库找不到

    错误信息1: ./mysqld: error : cannot open shared object file: No such file or directory 解决办法:安装改库 # apt-g ...

  10. rabbitmq添加user及vhost

    rabbitmqctl add_vhost /myhost # 添加 vhost rabbitmqctl add_user me me123 # 设置用户和密码 rabbitmqctl set_per ...