数组子序列的最大平均值 - 需要有效的解决方案

时间:2018-05-03 03:35:39

标签: java algorithm

输入

1: array size (1 to 10^5)
2: Number to take average (1 to 10^3)
3: elements in array (1 to 10^5) Non sorted, any order is possible

输出:任何子阵列的最大平均值。

Eg:
5 3
1 2 3 4 5
o/p = 5

5 4
1 2 3 4 5
o/p = 3

for first example seq will be sum[0,4]=15 and its average with 3 will be 5.
for second example seq will be sum[2,4]=12 and its average with 4 will be 3.

我已经给出了o(n ^ 2)的解决方案,但它不适用于大输入。

            long max = 0;
            for( int m = 0; m < people; m++ )
            {
                long sum = 0;
                for( int n = m; n < people; n++ )
                {
                    sum = sum + chocolateArray[n];
                    if( sum % boxes == 0 )
                    {
                        if( ( sum / boxes ) > max )
                        {
                            max = sum / boxes;
                        }
                    }
                }
            }
            System.out.println( max );

其中people是数组大小,boxes是平均数,chocolateArray是原始数组。

请提供有效的解决方案。我想通过dynamic programming接受它,但是创建10 ^ 5大小的二维数组导致了内存问题。

2 个答案:

答案 0 :(得分:2)

由于所有数字都是正数,唯一有效的约束是可分性。所以问题是要求最大的子阵列总和可以被m整除,即盒子的数量。

这可以通过创建一个累积和的数组,模m,然后找到两个具有相同数字的地方,尽可能远。由于最多有m个值,我们可以简单地存储每个可能残差的最小和最大索引,然后选择具有最大子阵列总和的那个。下面的代码就是这样。

cumsum = int[people+1];
minPos = int[boxes];
maxPos = int[boxes];
Arrays.fill(minPos, -1);
Arrays.fill(maxPos, -1);
int residue = 0;
for(int i=0; i<people; i++){
    cumsum[i+1] = cumsum[i] + chocolateArray[i]; // For simplicity the array length is 1 longer
    residue = cumsum[i+1] % boxes;
    if(minPos[residue] == -1) minPos[residue] = i;
    maxPos[residue] = i;
}
int max = 0;
for(int i=0; i<boxes; i++){
    int sum = cumsum[maxPos[i]+1] - cumsum[minPos[i]+1];
    if(sum > max){
        max = sum;
    }
}
System.out.println(max/boxes);

例如:

People = 5
Boxes = 4
Array = [1, 2, 3,  4,  5]
Cumulative = [1, 3, 6, 10, 15]
Residue = [1, 3, 2, 2, 3]
MinMaxPos[0] = (-1, -1) -> sum = 0 -> avg = 0
MinMaxPos[1] = (0, 0) -> sum = 0 -> avg = 0
MinMaxPos[2] = (2, 3) -> sum = 4 -> avg = 1
MinMaxPos[3] = (1, 4) -> sum = 12 -> avg = 3

答案 1 :(得分:2)

立足于@ justhalf的精彩解决方案。我们将能够使用单次传递和仅一个数组

来完成此操作

dp[boxes]成为长度为boxes的数组,其中dp[i]将保留到目前为止的最小总和i = current_sum % boxes

由于所有数字都是正数,我们只能存储特定residue的第一次出现,因为下一次出现这个残差时,它将大于先前的总和。< / p>

在每次迭代时,我们都会检查是否已找到特定的residue。如果是,那么我们用前一个残差的总和减去current_sum

否则我们更新残留物的总和并移动。

int maxSubArrayAverage(vector<int> people, int boxes)
{
    vector<int> dp(boxes, -1);
    int max_sum = 0, current_sum = 0;
    dp[0] = 0; // if residue is 0 entire current_sum is the choice
    for(int i=0; i < people.size(); ++i)
    {
        current_sum += people[i];
        int residue = current_sum % boxes;

        if(dp[residue] == -1) // update for the first time
        {
            dp[residue] = current_sum;
        }
        else
        {
            max_sum= max(max_sum, current_sum - dp[residue]);
            // cout << i << ' ' << current_sum << ' ' << residue << ' ' << max_average << endl;
        }
    }
    // copy(dp.begin(), dp.end(), ostream_iterator<int>(cout, " "));
    // cout << endl;
    return max_sum/boxes;
}