找到相等总和的contiguos子阵列

时间:2017-11-03 07:54:24

标签: algorithm

Given array : 8 3 5 2 10 6 7 9 5 2
So the o/p will be Yes.   

as:{8,3,5} {10,6} {9,5,2}他们都有相同的总和值,即16。

But for this array : 1 4 9 6 2 12
      o/p will be No.

as:没有连续的幻灯片具有相同的总和值

我正在考虑使用 SubSetSum算法/ Kadane最大子阵列算法,但后来我最终因为所有算法都需要预定义的目标总和。 但是这里我们不知道目标总和

3 个答案:

答案 0 :(得分:1)

如果给出了所需的总和,并且所有子阵列都应该是连续的,那么可以在O(n)中轻松完成。

在数组上运行循环并维护切片(leftright索引)和currentSum的边界。

从第一个元素开始为0.边界将是[0,0](为简单起见,我们包括右边)。然后在一个循环中你有三个条件。

  1. 如果sum小于期望值,则将右元素添加到总和并向右前进索引
  2. 如果sum大于期望值,则从总和中删除左元素并向左前进索引
  3. 如果sum等于给定,则打印切片。要在下一次迭代中避免此切片,请前进左侧索引并调整总和。
  4. 转换为代码

        public static void main(String[] args) {
            int givenSum = 16;
            int[] a = new int[] {8, 3, 5, 2, 10, 6, 7, 9, 5, 2};
    
            // boundaries of slice
            int left = 0; // defines position of slice
            int right = 0; // exclusive
            int currentSum = 0;
    
            while (right < a.length) {
    
                if (currentSum < givenSum) { // sum is not enough, add from the right
                    currentSum += a[right];
                    right++;
                }
    
                if (currentSum > givenSum) { // sum exceeds given, remove from the left
                    currentSum -= a[left];
                    left++;
                }
    
                if (currentSum == givenSum) { // boundaries of given sum found, print it
                    System.out.println(Arrays.toString(Arrays.copyOfRange(a, left, right)));
                    // remove the left element, so we can process next sums
                    currentSum -= a[left];
                    left++;
                }
            }
    
        }
    

    对于你的情况,它打印4个切片,产生总和16

    [8, 3, 5]
    [10, 6]
    [7, 9]
    [9, 5, 2]
    

    编辑:

    由于OP澄清,没有给定的总和,目标是检查是否存在至少两个不同的连续子阵列,产生相等的总和。

    最直接的算法是生成所有可能的总和并检查是否存在重复

    int[] a = new int[] {1, 4, 9, 6, 2, 12};
    
    HashSet<Integer> sums = new HashSet<>();
    int numOfSums = 0;
    
    for (int left = 0; left < a.length - 1; left++) {
        for (int right = left; right < a.length; right++) {
            // sum from left to right
            int sum = 0;
            for (int k = left; k <= right; k++) {
                sum += a[k];
            }
            numOfSums++;
            sums.add(sum);
        }
    }
    System.out.println(sums.size() == numOfSums);
    

    这是O(n^3)的复杂性,不是一个好的,但有效。

    提示:可以探索一个技巧来将其提升到O(n^2),你不需要计算每对切片的总和!

答案 1 :(得分:0)

您可以通过以下方式执行此操作

  1. 总和= 48
  2. 现在每个子集的总和将等于48的因子。因子越小,您可以将其分成的子集数越多
  3. 对于总和的所有因素,检查该因素是否可能。这可以通过简单地遍历数组在O(n)中完成。
  4. 时间复杂度为O(n *因子(总和))

答案 2 :(得分:0)

使用动态编程查找数组的所有子和,然后找到具有相同和的子数组。复杂性应该是O(n2)。

    void subsum(int n, int* arr, int** sum) {
         for (int i = 0; i < n; ++i) {
              sum[i][i] = arr[i];
         }
         for (int l = 2; l <= n; ++l) {
              for (int i = 0; i < n - l + 1; ++i) {
                   sum[i][i + l - 1] = sum[i][i + l - 2] + arr[i + l -1];
              }
         }
     }