📜  根据给定查询将数组划分为子数组后的最大子数组总和

📅  最后修改于: 2021-04-23 19:24:21             🧑  作者: Mango

给定一个数组arr []和一个整数k ,我们可以在k个不同的位置剪切该数组,其中k []存储所有所需剪切的位置。任务是在每次切割后打印所有切割中的最大和。
每个剪切都是整数x的形式,其中x表示arr [x]arr [x + 1]之间的剪切。

例子:

天真的方法:将数组的结果片段存储在ArrayList中,并在每次剪切后线性计算最大可能和。但是此方法将需要O(n * k)时间来回答所有查询。

高效的方法:我们可以将数组的每个结果片段表示为一个Piece对象,并带有数据成员的开始(该片段的开始索引),结束(该片段的结束索引)和(该片段的总和)。我们可以将这些片段存储在TreeSet中,并按照它们的总和值对其进行排序。因此,每次切割之后,我们都可以得到O(log(n))中总和最大的作品。

  • 我们必须制作一个数组值的前缀和数组,以在恒定时间内获得两个索引之间的和。
  • 我们必须使用当前所有片段的起始索引来维护另一个TreeSet,以便我们可以找到要剪切的确切片段。例如,对于一件:
    1. {1,8}->开始= 1,结束= 2,值= 9和{6,3,9}->开始= 3,结束= 5,值= 18
    2. 为了削减索引4,我们需要将第二部分削减为两部分,分别为{6,3}和{9}。因此,我们从该TreeSet中获取要切割的片段的起始索引。

下面是上述方法的实现:

// Java implementation of the approach
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
  
// Comparator to sort the Pieces
// based on their sum values
class MyComp implements Comparator {
    public int compare(Piece p1, Piece p2)
    {
        if (p2.val != p1.val)
            return p2.val - p1.val;
        if (p1.start != p2.start)
            return p2.start - p1.start;
        return 0;
    }
}
class Piece {
    int start;
    int end;
    int val;
  
    // Constructor to initialize each Piece
    Piece(int s, int e, int v)
    {
        start = s;
        end = e;
        val = v;
    }
}
  
class GFG {
  
    // Function to perform the given queries on the array
    static void solve(int n, int k, int cuts[], int A[])
    {
  
        // Prefix sum array
        int sum[] = new int[n];
        sum[0] = A[0];
        for (int i = 1; i < n; i++)
            sum[i] = sum[i - 1] + A[i];
  
        // TreeSet storing all the starts
        TreeSet t = new TreeSet<>();
  
        // TreeSet storing the actual pieces
        TreeSet pq = new TreeSet<>(new MyComp());
        Piece temp[] = new Piece[n];
        temp[0] = new Piece(0, n - 1, sum[n - 1]);
  
        // Added the whole array or Piece of array
        // as there is no cuts yet
        pq.add(temp[0]);
        t.add(0);
  
        for (int i = 0; i < k; i++) {
  
            // curr is the piece to be cut
            int curr = t.floor(cuts[i]);
            pq.remove(temp[curr]);
            int end = temp[curr].end;
  
            // When a piece with start = s and end = e
            // is cut at index i, two pieces are created with
            // start = s, end = i and start = i + 1 and end = e
            // We remove the previous piece and add
            // this one to the TreeSet
            temp[curr]
                = new Piece(curr, cuts[i],
                            sum[cuts[i]]
                                - (curr == 0 ? 0 : sum[curr - 1]));
            pq.add(temp[curr]);
  
            temp[cuts[i] + 1]
                = new Piece(cuts[i] + 1,
                            end, sum[end] - sum[cuts[i]]);
            pq.add(temp[cuts[i] + 1]);
  
            t.add(curr);
            t.add(cuts[i] + 1);
  
            System.out.println(pq.first().val);
        }
    }
  
    // Driver code
    public static void main(String[] args)
    {
  
        int A[] = { 4, 5, 6, 7, 8 };
        int n = A.length;
        int cuts[] = { 0, 2, 3, 1 };
        int k = cuts.length;
  
        solve(n, k, cuts, A);
    }
}
输出:
26
15
11
8

时间复杂度O(n + k Log n)