给定一个数组arr []和一个整数k ,我们可以在k个不同的位置剪切该数组,其中k []存储所有所需剪切的位置。任务是在每次切割后打印所有切割中的最大和。
每个剪切都是整数x的形式,其中x表示arr [x]和arr [x + 1]之间的剪切。
例子:
Input: arr[] = {4, 5, 6, 7, 8}, k[] = {0, 2, 3, 1}
Output:
26
15
11
8
First cut -> {4} and {5, 6, 7, 8}. Maximum possible sum is 5 + 6 + 7 + 8 = 26
Second cut -> {4}, {5, 6} and {7, 8}. Maximum sum = 15
Third cut -> {4}, {5, 6}, {7} and {8}. Maximum sum = 11
Fourth cut -> {4}, {5}, {6}, {7} and {8}. Maximum sum = 8
Input: arr[] = {1, 2, 3}, k[] = {1}
Output:
3
天真的方法:将数组的结果片段存储在ArrayList中,并在每次剪切后线性计算最大可能和。但是此方法将需要O(n * k)时间来回答所有查询。
高效的方法:我们可以将数组的每个结果片段表示为一个Piece对象,并带有数据成员的开始(该片段的开始索引),结束(该片段的结束索引)和值(该片段的总和)。我们可以将这些片段存储在TreeSet中,并按照它们的总和值对其进行排序。因此,每次切割之后,我们都可以得到O(log(n))中总和最大的作品。
- 我们必须制作一个数组值的前缀和数组,以在恒定时间内获得两个索引之间的和。
- 我们必须使用当前所有片段的起始索引来维护另一个TreeSet,以便我们可以找到要剪切的确切片段。例如,对于一件:
- {1,8}->开始= 1,结束= 2,值= 9和{6,3,9}->开始= 3,结束= 5,值= 18
- 为了削减索引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)