给定一个数组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 对象,其数据成员为start (该部分的开始索引)、 end (该部分的结束索引)和value (该部分的总和值)。我们可以将这些片段存储在一个 TreeSet 中,并按它们的总和值对它们进行排序。因此,在每次切割后,我们都可以得到 O(log(n)) 中总和值最大的 Piece。
- 我们必须制作数组值的前缀和数组,以在恒定时间内获得两个索引之间的总和。
- 我们必须维护另一个带有所有当前片段的起始索引的 TreeSet,以便我们可以找到要切割的确切片段。例如,对于单件:
- {1, 8} -> start = 1, end = 2, value = 9 and {6, 3, 9} -> start = 3, end = 5, value = 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)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。