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

📅  最后修改于: 2021-10-26 02:31:54             🧑  作者: Mango

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

例子:

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

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

  • 我们必须制作数组值的前缀和数组,以在恒定时间内获得两个索引之间的总和。
  • 我们必须维护另一个带有所有当前片段的起始索引的 TreeSet,以便我们可以找到要切割的确切片段。例如,对于单件:
    1. {1, 8} -> start = 1, end = 2, value = 9 and {6, 3, 9} -> start = 3, end = 5, value = 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)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程。