给定一组正数和负数。任务是找到一个分区点,使得左数组的元素都不在右数组中。如果有多个分区,则找到左数组的总和与右数组的总和(|sum left – sum right |)相对于分区点的绝对差最小的分区。在多个点的情况下,打印从左边开始的第一个分区点,即(左数组的最后一个索引和右数组的第一个索引)/2。考虑基于 1 的索引。分区上的左右数组必须至少有 1 个元素,最多有 n-1 个元素。如果没有可能的分区,则打印 -1。
例子:
Input: a[] = {1, 2, -1, 2, 3}
Output: 1
Left array = {1, 2, -1, 2}
Right array = {3}
Sumleft = 4, Sumright = 3
Difference = 1 which is the minimum possible
Input: a[] = {1, 2, 3, 1}
Output: -1
一种天真的方法是从每个索引向左和向右遍历,并检查该索引处是否可能存在分区。如果分区是可能的,则检查左数组元素和右数组元素的总和之间的绝对差是否小于先前在分区处获得的值的差值。找到分割点后,贪婪地找到|sum left – sum right | .
时间复杂度: O(N 2 )
一个有效的解决方案是将每个出现元素的最后一个索引存储在哈希映射中。由于元素值很大,不能使用直接索引。创建一个prefix[]和suffix[]数组,分别存储前缀和和后缀和。将变量计数初始化为 0。迭代数组中的所有元素。一个常见的观察点是,如果当前元素的(A i )最后一次不出现不是 i 本身,那么在遍历时我们不能在 i 和元素的最后一次出现之间有分区。在遍历时存储元素最后一次出现的最大值,因为在此之前无法完成分区。
一旦计数是 i 本身,我们就可以有一个分区,现在如果有多个分区,则选择 min |sum left – sum right |。
注意:使用 map 而不是 unordered_map 可能会导致 TLE。
下面是上述方法的实现。
C++
// C++ program for SP- partition
#include
using namespace std;
// Function to find the partition
void partition(int a[], int n)
{
unordered_map mpp;
// mark the last occurrence of every element
for (int i = 0; i < n; i++)
mpp[a[i]] = i;
// calculate the prefix sum
long long presum[n];
presum[0] = a[0];
for (int i = 1; i < n; i++)
presum[i] = presum[i - 1] + a[i];
// calculate the suffix sum
long long sufsum[n];
sufsum[n - 1] = a[n - 1];
for (int i = n - 2; i >= 0; i--) {
sufsum[i] = sufsum[i + 1] + a[i];
}
// Check if partition is possible
bool possible = false;
// Stores the absolute difference
long long ans = 1e18;
// stores the last index till
// which there can not be any partition
long long count = 0;
// Stores the partition
long long index = -1;
// Check if partition is possible or not
// donot check for the last element
// as partition is not possible
for (int i = 0; i < n - 1; i++) {
// takes an element and checks it last occurrence
// stores the maximum of the last occurrence
// where partition can be done
count = max(count, mpp[a[i]]);
// if partition is possible
if (count == i) {
// partition is possible
possible = true;
// stores the left array sum
long long sumleft = presum[i];
// stores the right array sum
long long sumright = sufsum[i + 1];
// check if the difference is minimum
if ((abs(sumleft - sumright)) < ans) {
ans = abs(sumleft - sumright);
index = i + 1;
}
}
}
// is partition is possible or not
if (possible)
cout << index << ".5" << endl;
else
cout << -1 << endl;
}
// Driver Code-
int main()
{
int a[] = { 1, 2, -1, 2, 3 };
int n = sizeof(a) / sizeof(a[0]);
partition(a, n);
return 0;
}
Java
// Java program for SP- partition
import java.util.*;
class GFG
{
// Function to find the partition
static void partition(int a[], int n)
{
Map mpp = new HashMap<>();
// mark the last occurrence of
// every element
for (int i = 0; i < n; i++)
mpp.put(a[i], i);
// calculate the prefix sum
long[] presum = new long[n];
presum[0] = a[0];
for (int i = 1; i < n; i++)
presum[i] = presum[i - 1] + a[i];
// calculate the suffix sum
long[] sufsum = new long[n];
sufsum[n - 1] = a[n - 1];
for (int i = n - 2; i >= 0; i--)
{
sufsum[i] = sufsum[i + 1] + a[i];
}
// Check if partition is possible
boolean possible = false;
// Stores the absolute difference
long ans = (long) 1e18;
// stores the last index till
// which there can not be any partition
long count = 0;
// Stores the partition
long index = -1;
// Check if partition is possible or not
// donot check for the last element
// as partition is not possible
for (int i = 0; i < n - 1; i++)
{
// takes an element and checks its
// last occurrence, stores the maximum
// of the last occurrence where
// partition can be done
count = Math.max(count, mpp.get(a[i]));
// if partition is possible
if (count == i)
{
// partition is possible
possible = true;
// stores the left array sum
long sumleft = presum[i];
// stores the right array sum
long sumright = sufsum[i + 1];
// check if the difference is minimum
if ((Math.abs(sumleft - sumright)) < ans)
{
ans = Math.abs(sumleft - sumright);
index = i + 1;
}
}
}
// is partition is possible or not
if (possible)
System.out.print(index + ".5" + "\n");
else
System.out.print(-1 + "\n");
}
// Driver Code
public static void main(String[] args)
{
int a[] = { 1, 2, -1, 2, 3 };
int n = a.length;
partition(a, n);
}
}
// This code is contributed by 29AjayKumar
Python3
# Python program for SP- partition
# Function to find the partition
def partition(a: list, n: int):
mpp = dict()
# mark the last occurrence of every element
for i in range(n):
mpp[a[i]] = i
# calculate the prefix sum
preSum = [0] * n
preSum[0] = a[0]
for i in range(1, n):
preSum[i] = preSum[i - 1] + a[i]
# calculate the suffix sum
sufSum = [0] * n
sufSum[n - 1] = a[n - 1]
for i in range(n - 2, -1, -1):
sufSum[i] = sufSum[i + 1] + a[i]
# Check if partition is possible
possible = False
# Stores the absolute difference
ans = int(1e18)
# stores the last index till
# which there can not be any partition
count = 0
# Stores the partition
index = -1
# Check if partition is possible or not
# donot check for the last element
# as partition is not possible
for i in range(n - 1):
# takes an element and checks it last occurrence
# stores the maximum of the last occurrence
# where partition can be done
count = max(count, mpp[a[i]])
# if partition is possible
if count == i:
# partition is possible
possible = True
# stores the left array sum
sumleft = preSum[i]
# stores the right array sum
sumright = sufSum[i + 1]
# check if the difference is minimum
if abs(sumleft - sumright) < ans:
ans = abs(sumleft - sumright)
index = i + 1
# is partition is possible or not
if possible:
print("%d.5" % index)
else:
print("-1")
# Driver Code
if __name__ == "__main__":
a = [1, 2, -1, 2, 3]
n = len(a)
partition(a, n)
# This code is contributed by
# sanjeev2552
C#
// C# program for SP- partition
using System;
using System.Collections.Generic;
class GFG
{
// Function to find the partition
static void partition(int []a, int n)
{
Dictionary mpp = new Dictionary();
// mark the last occurrence of
// every element
for (int i = 0; i < n; i++)
if(mpp.ContainsKey(a[i]))
mpp[a[i]] = i;
else
mpp.Add(a[i], i);
// calculate the prefix sum
long[] presum = new long[n];
presum[0] = a[0];
for (int i = 1; i < n; i++)
presum[i] = presum[i - 1] + a[i];
// calculate the suffix sum
long[] sufsum = new long[n];
sufsum[n - 1] = a[n - 1];
for (int i = n - 2; i >= 0; i--)
{
sufsum[i] = sufsum[i + 1] + a[i];
}
// Check if partition is possible
bool possible = false;
// Stores the absolute difference
long ans = (long) 1e18;
// stores the last index till which
// there can not be any partition
long count = 0;
// Stores the partition
long index = -1;
// Check if partition is possible or not
// donot check for the last element
// as partition is not possible
for (int i = 0; i < n - 1; i++)
{
// takes an element and checks its
// last occurrence, stores the maximum
// of the last occurrence where
// partition can be done
count = Math.Max(count, mpp[a[i]]);
// if partition is possible
if (count == i)
{
// partition is possible
possible = true;
// stores the left array sum
long sumleft = presum[i];
// stores the right array sum
long sumright = sufsum[i + 1];
// check if the difference is minimum
if ((Math.Abs(sumleft -
sumright)) < ans)
{
ans = Math.Abs(sumleft - sumright);
index = i + 1;
}
}
}
// is partition is possible or not
if (possible)
Console.Write(index + ".5" + "\n");
else
Console.Write(-1 + "\n");
}
// Driver Code
public static void Main(String[] args)
{
int []a = { 1, 2, -1, 2, 3 };
int n = a.Length;
partition(a, n);
}
}
// This code is contributed by Rajput-Ji
Javascript
4.5
时间复杂度: O(n) 假设 unordered_map 搜索在 O(1) 时间内工作。
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。