分割数组的方法数量

时间:2015-01-14 07:43:07

标签: java algorithm

我想找到将数组划分为3个连续部分的方法的数量,使得这三个部分的总和相等

-10^9 <= A[i] <= 10^9

我的方法: 输入和检查基础案例:

for(int i=0;i<n;i++){
     a[i]= in.nextLong();
     sum+=a[i];
}
if(sum%3!=0)System.out.println("0");

如果答案不在上面那么形成前缀和后缀总和。

for(int i=1;i<=n-2;i++){
        xx+=a[i-1];
        if(xx==sum/3){

            dp[i]=1;
        }        
    }

后缀求和更新二进制索引树

for(int i=n ;i>=3;i--){
         xx+=a[i-1];
         if(xx==sum/3){
             update(i, 1, suffix);
         }
    }

现在简单地循环数组以找到Total Ways: int ans = 0;

for(int i=1;i<=n-2;i++){

        if(dp[i]==1)
        {

            ans+=  (query(n, suffix) - query(i+1, suffix)); 
         // Checking For the Sum/3 in array where index>i+1
        }
}

我对上述方法的答案错误

我不知道我在哪里犯了错误请帮助纠正我的错误。

更新和查询功能:

public static void update(int i , int value , int[] arr){

       while(i<arr.length){
           arr[i]+=value;

           i+=i&-i;

       }
}
public static int query(int i ,int[] arr){

     int ans=0;

       while(i>0){

           ans+=arr[i];
           i-=i&-i;
       }

       return ans;

}

3 个答案:

答案 0 :(得分:3)

就你的方法而言,它是正确的。但是有一些观点因为它可能会给WA

  1. 很可能这个和会溢出int,因为每个元素的大小可以是10 ^ 9,所以请使用long long。
  2. 确保后缀和dp数组初始化为0。
  3. 说过在这里使用BIT树是一种矫枉过正,因为与 O(nlogn)解决方案相比,它可以在 O(n)中完成(但是如果你是在提交在线法官,那就无所谓了。 对于 O(n)方法,只需使用后缀[] 数组。并且如果已经标记后缀[i] = 1 i n sum / 3 ,向后遍历数组可以在 O(n)中完成。 然后再从后面再次遍历后缀[i] + =后缀[i-1] (除了基本情况i = n)。现在后缀[i] 存储索引数 i&lt; = j&lt; = n ,使得从索引 j n 的总和为 sum / 3 ,这是你想用BIT实现的目标。
    那么我建议你写一个暴力破解者或者这个简单的 O(n)并检查你的代码, 因为就你的方法而言,它是正确的,调试是不适合的 计算器。

答案 1 :(得分:1)

首先,我们计算一个数组dp,其中dp [i] =从0到i的和,这可以在O(n)中完成

long[]dp = new long[n];
for(int i = 0; i < n; i++)
   dp[i] = a[i];
   if(i > 0)
     dp[i] += dp[i - 1];

其次,假设数组的总和是x,所以我们需要找到哪个位置,我们有dp [i] == x / 3;

对于具有dp [i] == 2 * x / 3的每个i位置,我们需要添加到最终结果,索引j的数量&lt;我,dp[j] == x/3

int count = 0;
int result = 0;
for(int i = 0; i < n - 1; i++){
    if(dp[i] == x/3)
       count++;
    else if(dp[i] == x*2/3)
       result += count;
}

答案在result

您的方法有什么问题,

    if(dp[i]==1)
    {

        ans+=  (query(n, suffix) - query(i+1, suffix)); 
     // Checking For the Sum/3 in array where index>i+1
    }

这是错的,应该是

(query(n, suffix) - query(i, suffix));

因为,我们只需要删除1到i,而不是1到i + 1。

不仅如此,这一部分:

for(int i=1;i<=n-2;i++){
  //....      
}

应为i <= n - 1;

同样,此部分for(int i=n ;i>=3;i--)应为i >= 1

第一部分:

for(int i=0;i<n;i++){
     a[i]= in.nextLong();
     sum+=a[i];
}

应该是

for(int i=1;i<=n;i++){
     a[i]= in.nextLong();
     sum+=a[i];
}

您的代码中存在许多小错误,您需要花费大量精力进行首先调试,跳到这里询问并不是一个好主意。

答案 2 :(得分:0)

在提出的问题中,我们需要在数组中找到三个连续的部分,它们的总和是相同的。 我将提及步骤以及将为您解决问题的代码片段。

  1. 通过执行线性扫描O(n)和计算sum / 3来获取数组的总和。
  2. 从头开始扫描给定的数组。在每个索引处我们需要存储我们可以得到等于(sum / 3)的和的方式的数量,即如果end [i]是3,那么从索引i到n(数组范围)开始的数组中有3个子集其中sum是sum / 3。
  3. 第三步也是最后一步是从头开始扫描并找到sum为sum / 3的索引。在找到索引添加到解决方案变量(启动为零)时,结束[i + 2]。
  4. 我们正在做的事情是,从start开始遍历数组,直到len(array)-3。在找到总和,sum / 3,比如说索引i,我们有上半部分。

    现在,不关心下半部分并将解决方案变量(启动为零)添加到等于end [i + 2]的值。 end [i + 2]告诉我们从i + 2开始到结束的总方式,得到的数量等于第三部分的sum / 3.

    在这里,我们所做的是处理第一和第三部分,我们也处理了第二部分,它将默认等于sum / 3。我们的解决方案变量将是问题的最终答案。

    以下是代码片段,以便更好地理解上述算法:: -

    在这里,我们正在进行向后扫描,以存储从每个索引的末尾获得sum / 3的方式的数量。

    long long int *end = (long long int *)calloc(numbers, sizeof(long long int);
    long long int temp = array[numbers-1];
    if(temp==sum/3){
        end[numbers-1] = 1;
    }
    for(i=numbers-2;i>=0;i--){
        end[i] = end[i+1];
        temp += array[i];
        if(temp==sum/3){
            end[i]++;
        }
    }
    

    一旦我们有了结束数组,我们就会进行前向循环并得到我们的最终解决方案

    long long int solution = 0;
    temp = 0;
    for(i=0;i<numbers-2;i++){
        temp+= array[i];
        if(temp==sum/3){
            solution+=end[i+2];
        }
    }
    

    solution 存储最终答案,即将数组拆分为具有相等和的三个连续部分的方式的数量。