Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 找到一个子阵,其和可以被K整除。子阵应该是所有可能子阵的最大和_Algorithm - Fatal编程技术网

Algorithm 找到一个子阵,其和可以被K整除。子阵应该是所有可能子阵的最大和

Algorithm 找到一个子阵,其和可以被K整除。子阵应该是所有可能子阵的最大和,algorithm,Algorithm,我一直在练习算法问题,我遇到了这个问题。 给定一个数组(包括+ve和-ve)数,我必须找到一个连续的子数组,这样,和可以被任意数K整除,子数组应该是最大和。例如, a={1,2,2,1,1,4,5,3}和k=5,可被k整除的最大和子数组将是 {2,2,1,1,4,5},和=15 目前我所能想到的是,每个元素都有两种可能,要么包含在目标子阵列中,要么不包含在目标子阵列中。但这将是一个指数算法。 编辑:是否可以在线性时间内解决此问题。请帮助如果不是负数,每个和可被K整除的连续子数组应该由最多K个元素

我一直在练习算法问题,我遇到了这个问题。
给定一个数组(包括+ve和-ve)数,我必须找到一个连续的子数组,这样,和可以被任意数K整除,子数组应该是最大和。例如,
a={1,2,2,1,1,4,5,3}
k=5
,可被k整除的最大和子数组将是
{2,2,1,1,4,5},和=15

目前我所能想到的是,每个元素都有两种可能,要么包含在目标子阵列中,要么不包含在目标子阵列中。但这将是一个指数算法。

编辑:是否可以在线性时间内解决此问题。请帮助

如果不是负数,每个和可被K整除的连续子数组应该由最多K个元素的较小和可整除子数组组成。但对于负数,这是不正确的

所以,基本上唯一的选择是检查每个子数组的和是否可整除。像这样:

a = [1,2,2,1,1,4,5,3]
K = 5

max_a = []
max_len = 0

for i in range(len(a)):
    for j in range(i+1, len(a)+1):
        s = sum(a[i:j])
        if s % K == 0 and j-i > max_len:    
            max_len = j-i
            max_a = a[i:j]

print max_a

好吧,这是多项式,但仍然不是很有效

我为此编写了一个分治算法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
    class Program
    {
        static int k;

        static void Main(string[] args)
        {
            k = 5;
            int maxStart;
            int maxEnd;
            int sum;

            int[] a = new int[] { };
            f(a, 0, a.Length, out maxStart, out maxEnd, out sum);
            Console.WriteLine("{0},{1},{2}", maxStart, maxEnd, sum);

            a = new int[] { 1 };
            f(a, 0, a.Length, out maxStart, out maxEnd, out sum);
            Console.WriteLine("{0},{1},{2}", maxStart, maxEnd, sum);

            a = new int[] { 2,1 };
            f(a, 0, a.Length, out maxStart, out maxEnd, out sum);
            Console.WriteLine("{0},{1},{2}", maxStart, maxEnd, sum);

            a = new int[] { 2,3 };
            f(a, 0, a.Length, out maxStart, out maxEnd, out sum);
            Console.WriteLine("{0},{1},{2}", maxStart, maxEnd, sum);

            a = new int[] { 3,2,3,2 };
            f(a, 0, a.Length, out maxStart, out maxEnd, out sum);
            Console.WriteLine("{0},{1},{2}", maxStart, maxEnd, sum);

            a = new int[] { -5,10,15,-5 };
            f(a, 0, a.Length, out maxStart, out maxEnd, out sum);
            Console.WriteLine("{0},{1},{2}", maxStart, maxEnd, sum);

            a = new int[] { 1, 2, 2, 1, 1, 4, 5, 3 };
            f(a, 0, a.Length, out maxStart, out maxEnd, out sum);
            Console.WriteLine("{0},{1},{2}", maxStart, maxEnd, sum);

            a = new int[] { -1,-2,-3,-4,-5 };
            f(a, 0, a.Length, out maxStart, out maxEnd, out sum);
            Console.WriteLine("{0},{1},{2}", maxStart, maxEnd, sum);
        }

        static void f(int[] a, int start, int end, out int maxStart, out int maxEnd, out int sum)
        {
            if (end - start < 0)
            {
                throw new ArgumentException();
            }
            else if (end - start == 0)
            {
                maxStart = start;
                maxEnd = end;
                sum = 0;
            }
            else if (end - start == 1)
            {
                if (a[start] % k == 0)
                {
                    maxStart = start;
                    maxEnd = end;
                    sum = a[start];
                }
                else
                {
                    maxStart = -1;
                    maxEnd = -1;
                    sum = 0;
                }
            }
            else
            {
                int leftMaxStart;
                int leftMaxEnd;
                int leftMaxSum;
                int rightMaxStart;
                int rightMaxEnd;
                int rightMaxSum;
                int mid = (start + end) / 2;
                f(a, start, mid, out leftMaxStart, out leftMaxEnd, out leftMaxSum);
                f(a, mid, end, out rightMaxStart, out rightMaxEnd, out rightMaxSum);

                int[] r = new int[k];
                int[] rightEnds = new int[k];   //right end index array
                for (int i = 0; i < k; ++i)
                {
                    rightEnds[i] = -1;
                }
                int midSum = a[mid - 1] + a[mid];
                int midRightSum = midSum;
                int mod = Math.Abs(midRightSum % k);
                if (midRightSum > r[mod] || rightEnds[mod] == -1)
                {
                    r[mod] = midRightSum;
                    rightEnds[mod] = mid + 1;
                }
                for (int i = mid + 1; i < end; ++i)
                {
                    midRightSum += a[i];
                    mod = Math.Abs(midRightSum % k);
                    if (midRightSum > r[mod] || rightEnds[mod] == -1)
                    {
                        r[mod] = midRightSum;
                        rightEnds[mod] = i + 1;
                    }
                }

                int[] l = new int[k];
                int[] leftStarts = new int[k];  //left end index array
                for (int i = 0; i < k; ++i)
                {
                    leftStarts[i] = -1;
                }
                int leftSum = 0;
                for (int i = mid - 2; i >= start; --i)
                {
                    leftSum += a[i];
                    mod = Math.Abs(leftSum % k);
                    if (leftSum > l[mod] || leftStarts[mod] == -1)
                    {
                        l[mod] = leftSum;
                        leftStarts[mod] = i;
                    }
                }

                int crossMaxSum = int.MinValue;
                int crossMaxStart = -1;
                int crossMaxEnd = -1;
                if (rightEnds[0] != -1)
                {
                    crossMaxSum = r[0];
                    crossMaxStart = mid - 1;
                    crossMaxEnd = rightEnds[0];
                    if (leftStarts[0] != -1)
                    {
                        int crossSum = l[0] + r[0];
                        if (crossSum > crossMaxSum)
                        {
                            crossMaxSum = crossSum;
                            crossMaxStart = leftStarts[0];
                            crossMaxEnd = rightEnds[0];
                        }
                    }
                }
                for (int i = 1; i < k; ++i)
                {
                    int crossSum = l[i] + r[k-i];
                    if (crossSum > crossMaxSum)
                    {
                        crossMaxSum = crossSum;
                        crossMaxStart = leftStarts[i];
                        crossMaxEnd = rightEnds[k-i];
                    }
                }

                if (crossMaxStart != -1)
                {
                    if (leftMaxStart != -1)
                    {
                        if (rightMaxStart != -1)
                        {
                            if (leftMaxSum >= rightMaxSum && leftMaxSum >= crossMaxSum)
                            {
                                maxStart = leftMaxStart;
                                maxEnd = leftMaxEnd;
                                sum = leftMaxSum;
                            }
                            else if (crossMaxSum >= leftMaxSum && crossMaxSum >= rightMaxSum)
                            {
                                maxStart = crossMaxStart;
                                maxEnd = crossMaxEnd;
                                sum = crossMaxSum;
                            }
                            else
                            {
                                maxStart = rightMaxStart;
                                maxEnd = rightMaxEnd;
                                sum = rightMaxSum;
                            }
                        }
                        else
                        {
                            if (leftMaxSum >= crossMaxSum)
                            {
                                maxStart = leftMaxStart;
                                maxEnd = leftMaxEnd;
                                sum = leftMaxSum;
                            }
                            else
                            {
                                maxStart = crossMaxStart;
                                maxEnd = crossMaxEnd;
                                sum = crossMaxSum;
                            }
                        }
                    }
                    else
                    {
                        if (rightMaxStart != -1)
                        {
                            if (rightMaxSum >= crossMaxSum)
                            {
                                maxStart = rightMaxStart;
                                maxEnd = rightMaxEnd;
                                sum = rightMaxSum;
                            }
                            else
                            {
                                maxStart = crossMaxStart;
                                maxEnd = crossMaxEnd;
                                sum = crossMaxSum;
                            }
                        }
                        else
                        {
                            maxStart = crossMaxStart;
                            maxEnd = crossMaxEnd;
                            sum = crossMaxSum;
                        }
                    }
                }
                else
                {
                    if (leftMaxStart != -1)
                    {
                        if (rightMaxStart != -1)
                        {
                            if (leftMaxSum >= rightMaxSum)
                            {
                                maxStart = leftMaxStart;
                                maxEnd = leftMaxEnd;
                                sum = leftMaxSum;
                            }
                            else
                            {
                                maxStart = rightMaxStart;
                                maxEnd = rightMaxEnd;
                                sum = rightMaxSum;
                            }
                        }
                        else
                        {
                            maxStart = leftMaxStart;
                            maxEnd = leftMaxEnd;
                            sum = leftMaxSum;
                        }
                    }
                    else
                    {
                        if (rightMaxStart != -1)
                        {
                            maxStart = rightMaxStart;
                            maxEnd = rightMaxEnd;
                            sum = rightMaxSum;
                        }
                        else
                        {
                            maxStart = -1;
                            maxEnd = -1;
                            sum = 0;
                        }
                    }
                }
            }
        }
    }
}
如果FindMaxSubrayDivisible(array、start、end、maxStart、maxEnd、sum、k)是计算可被k整除的最大连续子数组的函数,则:

FindMaxSubarrayDivisible(array, start, end, out maxStart, out maxEnd, out sum, k)
    mid=(start+end)/2;
    FindMaxSubarrayDivisible(array, start, mid, out leftMaxStart, out leftMaxEnd, out leftSum, k)
    FindMaxSubarrayDivisible(array, mid, end, out rightMaxStart, out rightMaxEnd, out rightSum, k)
    FindMaxCrossingSubarrayDivisible(array, start, end, out crossMaxStart, out crossMaxEnd, out crossSum, k)
    Determine the max of the three above, if exists

findMaxCrossingSubArraydivible
可以使用O(k)存储在O(max(n,k))时间内完成。我的想法是有一个由k个整数组成的数组,其中每个元素存储余数i数组右侧的最大交叉和,其中0这个问题的关键字是前缀和

计算它们的伪代码如下所示:

int prefix_sum[N];
prefix_sum[0] = array[0];
for (i = 1; i < n; i++)
    prefix_sum[i] = prefix_sum[i-1] + array[i];
int前缀_和[N];
前缀_sum[0]=数组[0];
对于(i=1;i
现在我们有了前缀和,唯一剩下的就是找到子数组。 我们可以通过从最后一个子数组中减去子数组的第一个前缀和值来查看子数组的和

我们关心的属性是求和和和K的可整除性。现在要找到最大和子数组,我们看一次每个元素。当我们只看一次每个元素时,我们会做4件事:

  • 将前缀和除以K:
    rem[i]=前缀和[i]%K。通过这种方式,我们知道子数组是有效的当且仅当
    rem[start\u subarray]+rem[end\u subarray]==K
    。 但是我们不仅用它来检查子数组是否可整除,我们还可以用它来查找子数组(见下文)

  • 我们使用大小为
    K
    的数组
    max\u start
    。当我们计算
    前缀和[i]
    的剩余部分时,当前缀和[i]大于
    最大开始[rem[i]]中当前索引的前缀和时,我们将索引存储在
    最大开始[rem[i]
    中。 现在我们可以在O(1)中查找前缀和最大的索引,该索引具有给定的余数

  • 对于我们的元素
    array[i]
    我们查看
    rem[i]
    并查找前缀和最大的元素,该元素的余数为
    K-rem[i]
    。当我们这样做时,我们得到a)可被K整除的子数组,b)的和最大(对于以该元素结尾的所有数组,
    array[i]

  • 我们检查此数组的总和是否大于当前发现的最大数组,并在何时将此数组设置为新的最佳得分手


  • 细节是非常复杂的,因为你必须寻找正确的索引,你必须关心所有的异常情况(比如什么都找不到…),但我想你会了解算法的。这个函数的运行时间是O(n),由于前缀和,它应该适用于负数和正数。

    一开始我也考虑使用前缀(已经提到过)

    但是…我认为有一个更简单的方法:

    在描述给定问题之前,我先解决一个更简单的问题(我希望输入中有负数):

    在具有最大和的向量中查找子数组:

    结果为
    mx

    复杂性
    O(n+k)

    的修改可能会有所帮助。我也考虑过这一点,但未能实现。考虑<代码> {3,2,2,3} < /代码>和<代码> k=4 < /代码>。你会如何检查整除性?你提到了+ve和-ve-这是否意味着数组有界元素?@ZiyaoWei不,在采访中,这也会被视为蛮力。邦德,是的,这是蛮力方法。没有看到编辑。你能用一些例子解释一下吗。我认为在求解
    K-rem[I]
    时会出现一些问题,结果是索引
    I
    本身。取
    a={2,1,3,2}
    k=6
    ,然后
    prefix_sum={2,3,6,8}
    rem={2,3,0,2}
    max_start={2,3,1,1,1,2}
    。现在当
    i=1
    时,
    rem[i]=3
    和K-rem[i]也是如此,即
    6-3=3
    现在我们转到
    max\u start[3]
    并查看那里的值是
    i.e 1
    本身。我有点困惑。如前所述,细节可能会变得非常复杂。(我上面的顺序不太好,当我使用other时会更清楚)在对元素执行所有其他操作后,将rem值添加到max_start,这意味着,在当时rem[1]仍然为空,结果是没有以元素1结尾的有效子数组。(我没有那么多时间,但我将添加一个示例,以便您查看)。如果您在第一个元素之前插入一个
    0
    ,这将简化事情,之后您应该查找两个
    K
    ;你必须对每一个数字类都这样做
    [0:K)
    …我认为这个算法的复杂性是:
    O(n*K)
    你能解释一下这句话吗?我们知道一个子数组是有效的当且仅当rem[start\u subarray]+rem[end\u subarray]=K。对于这个数组{4,2,2,2,1}和K=7-rem[]=4,6,1,3,4}。re
    min_sum=0
    max_sum=0
    sum=0
    for x in elements{
      sum+=x
      if sum < min_sum { min_sum=sum }
      if sum > max_sum { max_sum=sum }
    }
    result=max_sum-min_sum
    
    min_sum= [ array, k zeros]
    max_sum= [ array, k zeros]
    sum=0
    for x in elements{
      sum+=x
      s = sum % k  // current numberclass
      if sum < min_sum[s] { min_sum[s]=sum }
      if sum > max_sum[s] { max_sum[s]=sum }
    }
    mx=0
    for x in [0:k){
      s=max_sum[x]-min_sum[x]
      if(mx<s) mx=s
    }