📜  须藤放置[1.5] |划分

📅  最后修改于: 2021-10-27 08:24:52             🧑  作者: Mango

给定一组正数和负数。任务是找到一个分区点,使得左数组的元素都不在右数组中。如果有多个分区,则找到左数组的总和与右数组的总和(|sum left – sum right |)相对于分区点的绝对差最小的分区。在多个点的情况下,打印从左边开始的第一个分区点,即(左数组的最后一个索引和右数组的第一个索引)/2。考虑基于 1 的索引。分区上的左右数组必须至少有 1 个元素,最多有 n-1 个元素。如果没有可能的分区,则打印 -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 现场工作专业课程学生竞争性编程现场课程