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. django项目中使用手机号登录

    本文使用聚合数据的短信接口,需要先获取到申请接口的appkey和模板id 项目目录下创建ubtils文件夹,定义返回随机验证码和调取短信接口的函数 function.py文件 import rando ...

  2. moviepy这个版本,除了字幕,基本可用

    只是注意,开头要坚拍,中间要横拍,结尾图左上右下. 哈哈,如果不是这样,那就要调调角度了. from moviepy.editor import * from moviepy.video.tools. ...

  3. 《Maven在Java项目开发中的应用》论文笔记(十七)

    标题:Maven在Java项目开发中的应用 一.基本信息 时间:2019 来源:山西农业大学 关键词:Maven:Java Web:仓库:开发人员:极限编程; 二.研究内容 1.Maven 基本原理概 ...

  4. Unity点击播放卡死问题的解决

    Unity项目使用了github for unity 插件,用来管理项目,结果安装完后Unity卡死在播放的界面,任务管理器中显示无响应. 经过排查后发现是 git for windows这个程序引起 ...

  5. LG1036

    当我们看到这道题的时候,我们不仅大吼一声,这不就是搜索嘛. 于是搜索两大刀!搜索目标和搜索状态! 搜索目标:求选数的方案,以及他们的和是否为质数. 搜索状态: 1.从后往前分析目标(或从前往后):和是 ...

  6. 使用docker搭建etcd

    下载etcd代码然后拷贝到服务器 来自为知笔记(Wiz)

  7. file 的类型 input

    上传你选择的文件和相关信息.在 HTML 文档中 <input type="file"> 标签每出现一次,一个 FileUpload 对象就会被创建.该元素包含一个文本 ...

  8. solidworks 学习 (三)

    汽车轮毂三维建模

  9. BZOJ 5469: [FJOI2018]领导集团问题 dp+线段树合并

    在 dp 问题中,如果发现可以用后缀最大值来进行转移的话可以考虑去查分这个后缀最大值. 这样的话可以用差分的方式来方便地进行维护 ~ #include <bits/stdc++.h> #d ...

  10. Omnibus 安装

    使用gem gem install omnibus 说明 可能需要配置gem source ,通过 gem source list 可以进行检查 参考如下:   gem source -r https ...